feat(grid-agent): enforce central action policy (#120)
This commit is contained in:
80
docs/grid-agent-policy.md
Normal file
80
docs/grid-agent-policy.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Grid-agent authorization and safety policy
|
||||
|
||||
Every production tool action crosses `PolicyGateway` and then
|
||||
`PolicyToolExecutor`. The gateway is deny-by-default: a tool must be registered
|
||||
with its typed argument schema, capability, read/write risk, allowed origins,
|
||||
maximum resource cost, deterministic cost estimator, idempotency,
|
||||
approval rule, and scheduler eligibility. A tool description is model context,
|
||||
not authority, and is never consulted by policy.
|
||||
|
||||
## Identity and origin matrix
|
||||
|
||||
Grid authority comes only from the sender UUID carried by the grid event.
|
||||
Names, message bodies, UUID text embedded in messages, and tool arguments cannot
|
||||
select an origin. Local-operator principals can only be constructed by the
|
||||
crate's authenticated control-plane boundary. Scheduler contexts require an
|
||||
opaque grant previously issued from an authorized IM or operator action.
|
||||
|
||||
| Origin | Informational read | Public LSL delivery capability | Allow-listed mutation | Scheduled action |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Public chat, including an authorized avatar | yes | yes | no | no |
|
||||
| Unprivileged IM | yes | no | no | no |
|
||||
| Authorized IM | when registered | when registered | when registered | may create an exact grant |
|
||||
| Authenticated local operator | when registered | when registered | when registered | may create an exact grant |
|
||||
| Internal scheduler | exact grant only | no | exact grant only | bounded runs and expiry |
|
||||
|
||||
The public LSL capability is a narrow inventory-mutation marker for the later
|
||||
script-delivery workflow; it does not permit executing generated code or any
|
||||
other public command. Tool names are exact ASCII identifiers, so case changes,
|
||||
newlines, smuggled names, and Unicode confusables do not resolve to registered
|
||||
tools.
|
||||
|
||||
## Approvals and budgets
|
||||
|
||||
Arguments are parsed again at the gateway and must equal the arguments bound to
|
||||
the proposed call. Canonical JSON is SHA-256 hashed. An approval binds that
|
||||
hash, exact tool, requesting principal, expiry, and one execution. Changed
|
||||
arguments, another principal, an ungranted/expired approval, or a replay is a
|
||||
stable denial. Authorization is represented by non-cloneable
|
||||
`AuthorizedAction`, whose fields have no public constructor; action backends
|
||||
cannot accept a raw call plus a caller-created decision.
|
||||
|
||||
Each authorized attempt atomically charges a configured time-window budget for
|
||||
both the originating principal and the whole agent. The resource vector covers
|
||||
tool-call rate, L$, upload bytes, inventory operations, movement millimetres,
|
||||
and build prims. Hard ceilings validate configured budgets and per-tool maximum
|
||||
costs. This milestone fixes every L$ budget at zero and refuses registration or
|
||||
execution for currency spend, estate/parcel changes, permanent deletion,
|
||||
arbitrary inventory acceptance, and generated-code execution.
|
||||
|
||||
Scheduler grants preserve the originating principal and bind one tool and
|
||||
argument hash. Run count and lifetime are bounded; every run is charged again.
|
||||
The opaque `PolicySnapshot` preserves budgets, approvals (including consumed
|
||||
replay state), and scheduler grants when a trusted persistence integration
|
||||
reconstructs the gateway. No durable policy store is enabled by the current
|
||||
offline service; a future store must protect snapshot integrity rather than
|
||||
accept caller-authored approval data.
|
||||
|
||||
## Prompt and audit boundaries
|
||||
|
||||
Chat, IM, inventory metadata, object text, parcel data, web/LLM output, and
|
||||
generated scripts use `UntrustedData`. It emits a bounded labelled JSON data
|
||||
record and never contributes system instructions or tool availability. This is
|
||||
defence in depth: authorization is still enforced after inference at the exact
|
||||
gateway.
|
||||
|
||||
Every decision emits a bounded structured `PolicyAuditRecord` before an action
|
||||
is authorized. It contains origin class and UUID where applicable, principal,
|
||||
session/correlation IDs, exact tool, disposition, stable reason code, applied
|
||||
budget, an argument hash, and outcome. The executor emits the completed,
|
||||
rejected, failed, or ambiguous final outcome. Raw/secret arguments and hidden
|
||||
reasoning are never stored. Audit backpressure fails closed before issuing a
|
||||
new authorization.
|
||||
|
||||
Focused verification:
|
||||
|
||||
```sh
|
||||
cargo test --locked -p metacrate-grid-agent --lib policy_tests
|
||||
cargo test --locked -p metacrate-grid-agent --test policy_gateway
|
||||
cargo clippy --locked -p metacrate-grid-agent --all-targets -- -D warnings
|
||||
```
|
||||
Reference in New Issue
Block a user