Permissions
The adversary.yaml permissions block declares portable access intent. It is not a free-form capability list, and it does not replace official signature trust.
Canonical manifests use a single structured field: permissions. There is no requires: list of tokens such as repo.read or llm.call in the v1 schema. Official catalog packages declare the same shape as local projects.
Permissions describe what isolation or broker access the package requests. They do not decide whether host execution is allowed — that is official signature trust (or an explicit local path). See the execution trust model.
Typical catalog package
Most official packages look like this (advisory isolation, repo read only, no network, model broker enabled):
permissions:
enforcement: advisory
filesystem:
read:
- .
write: []
network: false
model: true
environment:
allow: []Field reference
| Field | Meaning |
|---|---|
| enforcement | advisory (default): records preferred isolation; does not block HostExecutor. required: every non-empty isolation request becomes mandatory and fails closed if the executor cannot enforce it. |
| filesystem.read | Relative paths the package expects to read (often "." for the target repository). Non-empty lists request filesystem-read isolation when enforcement is required. |
| filesystem.write | Relative paths the package expects to write (for example .adversary/results). Empty means no write boundary request. |
| network | Boolean. false requests network isolation. On HostExecutor (which reports no network isolation), enforcement: required or CLI --no-network fails before launch. |
| model | When true, the package may use the CLI-owned model review broker (SDK ctx.model.review). Provider API keys stay in the CLI process; the child receives only a short-lived loopback broker token. |
| environment.allow | Environment variable names the package expects. Non-empty lists request environment isolation when enforcement is required. Empty allow means no environment boundary request. |
Enforcement and HostExecutor
Today the default backend is HostExecutor: a normal process with the user's privileges. It reports no isolation capabilities.
- With
enforcement: advisory(the catalog default), isolation fields are documentation of intent. The process still runs on the host. - With
enforcement: required, non-empty filesystem/environment lists andnetwork: falsebecome mandatory. HostExecutor cannot satisfy them, so the run fails before launch. - CLI
--no-networkalways requests mandatory network isolation, regardless of enforcement mode — and therefore fails on HostExecutor.
permissions:
enforcement: required
filesystem:
read:
- .
write: []
network: false
environment:
allow:
- PATH
- HOMEModel access (permissions.model)
When model: true, the package may call the SDK model helper. The CLI starts a short-lived authenticated loopback broker and injects only the broker endpoint and execution token into the child. Provider API keys (OPENAI_API_KEY, ANTHROPIC_API_KEY, FIREWORKS_API_KEY) stay with the CLI.
export OPENAI_API_KEY="..."
adversary run go/security --path . \
--model-provider openai \
--model "your-model-id"
# Or let the CLI infer the provider when exactly one key is set:
export ANTHROPIC_API_KEY="..."
adversary run go/security --path .Flags override ADVERSARY_MODEL_PROVIDER and ADVERSARY_MODEL. Tokens are not accepted as flags (process listings leak).
New project template
adversary init scaffolds approximately:
permissions:
enforcement: advisory
filesystem:
read:
- .
write:
- .adversary/results
network: false
environment:
allow: []What permissions are not
- Not a capability marketplace or paid feature gate.
- Not publisher trust — unsigned packages stay untrusted for host execution even if permissions look minimal.
- Not OS sandboxing by themselves under HostExecutor with advisory enforcement.
- Not a substitute for reviewing the package code before you run it with elevated trust overrides.
Related: CLI, SDK, execution trust model.