feat(sdk): contrat permissions.workspaceExec pour l'exécution contrôlée via l'hôte — #346

Cadrage capacités plugin SCM (#346): le manifeste plugin gagne
permissions.workspaceExec.allow — règles d'exécution contrôlée par l'hôte
(commande bare ASCII résolue sans shell, argv exact avec jeton `*` en
suffixe, cwd project-relative sûr, effect read/write/network/destructive,
64 règles max) — au lieu de lectures ad hoc du store interne .git.
Validation manifeste + exports runtime/index + docs README/manifest/
services + auto-check script étendu (règles valides acceptées, règles
unsafe rejetées).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-09-13 12:07:56 +02:00
parent 720cd53924
commit 8ff0f475de
7 changed files with 196 additions and 1 deletions

View File

@ -29,6 +29,38 @@ Key APIs:
- `stat(path, projectId?)`
- `watch(path, handler, projectId?)`
- `queryStructure(query?)`
- `execTool(request)`
### Short external tools
`services.workspace.execTool()` runs a short external executable already available
to the host. It is generic: IdeA does not expose Git, SVN, formatter, or linter
semantics. The plugin owns the arguments and parses the returned output.
```ts
const result = await ctx.services!.workspace.execTool({
projectId,
command: "tool",
args: ["status", "--short"],
cwd: ".",
timeoutMs: 5_000,
maxStdoutBytes: 256_000,
maxStderrBytes: 64_000
});
```
The host passes `command` and `args` directly without a shell. The plugin must
declare a matching `permissions.workspaceExec.allow` rule, be active for the
project, and use a project-relative `cwd`. IdeA canonicalizes the cwd, bounds
time/stdin/output/concurrency, exposes only an allowlisted environment, applies
the project filesystem sandbox where supported, and audits metadata without
captured stdout/stderr contents. This API returns output directly and never
creates a visible Work/background-task entry.
Current host maxima are 30 seconds, 1,000,000 stdout bytes, 256,000 stderr bytes,
and 64,000 stdin bytes. Requested output/time values above a maximum are clamped;
zero is rejected. Output is returned as lossy UTF-8 with explicit truncation
flags.
## Tasks