166 lines
11 KiB
Markdown
166 lines
11 KiB
Markdown
|
|
# Assessment: session-scoped agent identity and tool boundary
|
||
|
|
|
||
|
|
Date: 2026-10-24. Status: assessment only; no harness behavior changed.
|
||
|
|
Request: net-kingdom hub message 14ea093a (standard
|
||
|
|
`service-identity-privilege_v0.1.md` draft-3 SI-14, SI-15; companion section 7;
|
||
|
|
SEC-DSM DSM-AGENT-002, -007, -008). key-cape assesses the issuing side in parallel.
|
||
|
|
Plan: `workplans/GLAS-WP-0018-session-agent-identity-and-tool-boundary.md`.
|
||
|
|
|
||
|
|
## Verdict
|
||
|
|
|
||
|
|
Feasible for the sessions glas-harness actually launches, in three separable steps.
|
||
|
|
Glas is the right place for (a) carriage and (b) attribution, and for *declaring*
|
||
|
|
(c); enforcement of (c) belongs to the rein, the sandbox and the token's audience.
|
||
|
|
Glas cannot control a person's interactive Claude Code, Codex or Grok terminal
|
||
|
|
session; for those it can only offer a shared contract and helper. Be explicit in
|
||
|
|
the declaration that such sessions stay at SI-14's "holds the person's reach".
|
||
|
|
|
||
|
|
## What exists today
|
||
|
|
|
||
|
|
Evidence is from `src/glas_harness/{gateway,contract,hub}.py`, the reins and profiles.
|
||
|
|
|
||
|
|
| Need | Today | Gap |
|
||
|
|
|---|---|---|
|
||
|
|
| Actor type | `ExecutionRequest.actor` is `adm`/`agt`/`atm`, validated into sand-boxer `Consumer`; `run_id` is the request id. Docs state attribution is "not caller authentication". | A label, not an IAM principal. No `principal_type=agent`, no `act.sub`, no token. |
|
||
|
|
| Per-run identity | `request_id` (uuid) names the run and the sandbox consumer. Sandbox is per run and destroyed after. | Nothing binds `request_id` to an issuer-signed subject. |
|
||
|
|
| Credentials | `credential_route_refs` are labels passed to the sandbox owner (`SandboxExecRequest.credential_route_refs`), applied only to the workload command; secret-looking values are refused in profiles. | A KeyCape agent token is a new credential class with no route. The owner (sand-boxer / credential owner) must deliver it. |
|
||
|
|
| Tool boundary | Profile field `tool_profile` (for example `green-commit-only`) is passed as `--tool-profile` to rein-aharness / rein-openweights; the rein enforces it. Sandbox profile (bwrap, egress deny-by-default) bounds filesystem and network. | Glas does not know what a tool profile allows; it is an opaque string. No Glas-side check that the profile is narrower than the person's reach. Tool profiles do not name credentials or hub write scope. |
|
||
|
|
| Attribution record | `ExecutionEvidence` (actor, project, profile, rein, model, sandbox_id, commit_sha, timings, tool_events_count and completeness, refs to assignment/role/duty). Posted to the Hub as a `gateway_run` progress event with hard-coded `author: agt-glas-harness`. | Aggregate per run, not per state-changing action. Tool events are `complete` only when the rein streams them, parsed after the subprocess ends; `unavailable` for open-weight. No `on_behalf_of`, no session identity, no evidence location/hash. Hub author is unauthenticated free text (the declared net-kingdom gap). Hub post is best-effort, no outbox. |
|
||
|
|
| Commit trailers | Commits inside the sandbox are made by the rein. | Glas neither requires nor verifies `Assistant`, `Assistant-Session`, `Assistant-Process`. |
|
||
|
|
| Limits | Token, turn, USD budgets and per-command timeout passed to reins that support them. | No aggregate wall clock; nothing ties session lifetime to token lifetime (60 minute ceiling). |
|
||
|
|
| Readiness | No committed profile is `ready`. | Any identity feature starts on unverified/blocked profiles, so it cannot yet claim production assurance. |
|
||
|
|
|
||
|
|
## (a) Per-session agent identity
|
||
|
|
|
||
|
|
Design sketch (not implemented):
|
||
|
|
|
||
|
|
1. Add an optional `identity` section to `ExecutionRequest` / profile: required
|
||
|
|
`on_behalf_of` (the person, becomes `act.sub`), `mode` (`agent`), requested
|
||
|
|
`ttl_seconds` (profile ceiling 3600), `audience` list.
|
||
|
|
2. Before `rein.start_session`, the gateway asks a pluggable `AgentIdentityIssuer`
|
||
|
|
(interface in Glas, KeyCape-backed adapter) for a token whose subject is the run
|
||
|
|
(`agent:<request_id>`), `principal_type=agent`, `act.sub` the person, expiry
|
||
|
|
`min(profile ttl, remaining timeout, 3600)`. Fail closed: no token, no
|
||
|
|
identity-requiring profile run (new `failure_stage` such as `identity`).
|
||
|
|
3. Deliver the token to the workload as a sandbox credential (stdin or a
|
||
|
|
sandbox-owner delivery route), never in argv, task file, evidence, Hub detail
|
||
|
|
or logs; never in the person's password safe (SI-9). Redaction of the token
|
||
|
|
pattern in tool output before it enters `ToolResult`.
|
||
|
|
4. Carry through tool calls: Glas passes a token handle; the rein presents it to
|
||
|
|
downstream services. Reins must accept and use it (a rein change), and
|
||
|
|
downstream services must verify it (their change). Glas alone can only guarantee
|
||
|
|
issue, scoped delivery, expiry and revocation at teardown.
|
||
|
|
5. Teardown: discard the token, request revocation if the issuer supports it
|
||
|
|
(dependency on key-cape), record issuance and revocation in evidence by
|
||
|
|
token id (`jti`) only.
|
||
|
|
|
||
|
|
Dependencies: KeyCape agent-token issuance (principal_type claim, `act`,
|
||
|
|
60 minute cap, per-run subject, revocation) and the sandbox/credential owner for
|
||
|
|
delivery. Without them Glas can stub the issuer for tests but must not claim
|
||
|
|
identity.
|
||
|
|
|
||
|
|
Effort: contract + issuer interface + fail-closed gateway wiring + tests,
|
||
|
|
roughly 3 to 5 days in Glas; real issuer adapter and delivery 3 to 5 days after
|
||
|
|
key-cape and sand-boxer land their sides; rein acceptance of the token is a
|
||
|
|
separate rein-aharness task.
|
||
|
|
|
||
|
|
## (b) Attribution per state-changing action
|
||
|
|
|
||
|
|
Today's evidence answers "which run, profile, model, sandbox, outcome, commit".
|
||
|
|
SI-15 also wants "on whose authority" and "where the evidence is kept" per action.
|
||
|
|
|
||
|
|
Proposal:
|
||
|
|
|
||
|
|
- Add `identity_ref` (subject, `act.sub`, token `jti`, issuer, expiry; no token),
|
||
|
|
`session_id` and `authority_ref` (assignment/role/duty already exist as refs) to
|
||
|
|
`ExecutionEvidence`.
|
||
|
|
- Define an `ActionRecord` (actor, on_behalf_of, session, operation, target,
|
||
|
|
result, evidence_location, evidence_sha256, timestamp). Glas emits one per
|
||
|
|
commit it can see and one per tool event when the rein streams events; where
|
||
|
|
the rein cannot report, the record says `events_completeness: unavailable`
|
||
|
|
rather than implying coverage. This honestly keeps SI-15's "reconstructable"
|
||
|
|
as partial.
|
||
|
|
- Write a hashed evidence receipt file (sandbox-external, append-only
|
||
|
|
location chosen with the custodian), and put its hash in the Hub event. Use a
|
||
|
|
durable local outbox so the Hub post is not best-effort only.
|
||
|
|
- Require and verify commit trailers (`Assistant`, `Assistant-Session`,
|
||
|
|
`Assistant-Process`) on sandbox commits; refuse or flag a run whose commits
|
||
|
|
lack them.
|
||
|
|
- Replace the hard-coded Hub author with the run identity once the Hub can
|
||
|
|
authenticate it; until then record it in `detail` and keep the gap stated.
|
||
|
|
|
||
|
|
Effort: 4 to 6 days. Risk: tool-event coverage is rein-dependent; ActionRecords
|
||
|
|
from parsed streams are after-the-fact, not tamper-evident, unless the receipt is
|
||
|
|
stored outside the agent's reach.
|
||
|
|
|
||
|
|
## (c) Session-scoped tool boundary
|
||
|
|
|
||
|
|
Facts: the boundary today is sandbox profile (filesystem, egress) plus rein
|
||
|
|
`tool_profile`. For a harness-launched session the person's ambient reach is
|
||
|
|
already mostly absent: the run is in a bwrap sandbox with a deny-by-default
|
||
|
|
network and no person credentials; `credential_route_refs: []` in the local
|
||
|
|
profile. The risk SI-14 names is the *interactive* terminal session, which Glas
|
||
|
|
does not launch.
|
||
|
|
|
||
|
|
Proposal for launched sessions:
|
||
|
|
|
||
|
|
- Make the boundary declarative and checkable: a `boundary` block in the profile
|
||
|
|
(tool profile id and hash, sandbox profile, egress hosts, credential route refs,
|
||
|
|
hub write scope, max lifetime) that Glas records in evidence, and a catalog
|
||
|
|
validation that every profile with a non-empty credential route or
|
||
|
|
identity requirement names a non-default tool profile.
|
||
|
|
- Resolve `tool_profile` against a rein-published manifest (rein-aharness
|
||
|
|
`profiles.py` registry) so Glas can state, not just forward, what the tools
|
||
|
|
can reach, and fail when the rein reports a different profile than requested
|
||
|
|
(the rein already echoes `tool_profile` in its result; Glas currently does not
|
||
|
|
compare).
|
||
|
|
- Effective authority statement: tools reachable x token audience x sandbox
|
||
|
|
egress. Emit it per run as evidence (DSM-AGENT-008).
|
||
|
|
- Bind token audience and scopes to the boundary, so a tool that is callable but
|
||
|
|
outside the boundary is rejected by the downstream service, not by the model's
|
||
|
|
good manners (companion section 7 rule 2).
|
||
|
|
|
||
|
|
Effort: 3 to 4 days in Glas plus a rein-aharness manifest export. Risk: a tool
|
||
|
|
profile that allows shell lets the agent reach whatever the sandbox network and
|
||
|
|
credentials allow; the sandbox, not the profile name, is the real boundary.
|
||
|
|
|
||
|
|
## Claude Code, Codex and Grok
|
||
|
|
|
||
|
|
| Session type | Glas control | Identity | Tool boundary | Attribution |
|
||
|
|
|---|---|---|---|---|
|
||
|
|
| Harness-launched via rein-aharness (Claude CLI inside sandbox) | Full outer lifecycle | Feasible once KeyCape + delivery exist; rein must present the token | Sandbox + tool profile, enforced by sand-boxer and the rein | Run evidence now; per-action partial via streamed events |
|
||
|
|
| Harness-launched via rein-openweights | Full outer lifecycle | Same, if the rein accepts it | Same | Weaker: tool events unavailable |
|
||
|
|
| Interactive Claude Code in a person's terminal | None | Could use a helper script that requests a token at session start; person must run it | Claude Code permission and hook settings, set by the person; not Glas | Commit trailers and hub notes only |
|
||
|
|
| Codex | No rein exists. Needs a new rein (CLI adapter) to be harness-launched | As above once a rein exists | Codex sandbox/approval modes, outside Glas | Trailers already used by Codex commits (`Assistant: codex`) |
|
||
|
|
| Grok | No rein exists | Same | Not known; unverified | Not verified |
|
||
|
|
|
||
|
|
Honest scope: Glas can only deliver SI-14 conformance for sessions it launches.
|
||
|
|
For the rest it can publish a small, provider-neutral "session identity
|
||
|
|
contract" (what a session must obtain, carry, record) that the person or a
|
||
|
|
wrapper implements. Whether Codex and Grok expose hooks sufficient for per-call
|
||
|
|
attribution is not established here and needs checking before any claim.
|
||
|
|
|
||
|
|
## Risks and open questions
|
||
|
|
|
||
|
|
1. Token in the sandbox: the agent can read and exfiltrate its own token within
|
||
|
|
its lifetime. Mitigation is narrow audience, short TTL, egress deny-by-default,
|
||
|
|
revocation at teardown; it is not eliminated.
|
||
|
|
2. Identity over a still-blocked runtime: all profiles are non-ready, so this
|
||
|
|
should be built behind unverified profiles and proven in isolation first.
|
||
|
|
3. Evidence that the agent can write is not independent evidence; the receipt
|
||
|
|
location must be outside the sandbox and the verifier independent (SI-15 step 4).
|
||
|
|
4. Hub authorship stays unauthenticated until the Hub changes (owner: state-hub).
|
||
|
|
5. `actor` values `adm`/`agt`/`atm` predate this standard; mapping `agt` to
|
||
|
|
IAM `principal_type agent` needs an agreed table with net-kingdom.
|
||
|
|
6. Scope creep: Glas must not become an identity provider or policy engine; it
|
||
|
|
carries and records. Authorization stays with flex-auth and the issuer.
|
||
|
|
|
||
|
|
## Recommended order
|
||
|
|
|
||
|
|
1. Contract fields and evidence (b, identity_ref placeholders) and the
|
||
|
|
boundary declaration with tool-profile echo check (c): no external
|
||
|
|
dependency, immediately useful.
|
||
|
|
2. Issuer interface with a test double; fail-closed gateway path.
|
||
|
|
3. Real KeyCape adapter and delivery once key-cape and sand-boxer agree.
|
||
|
|
4. Interactive-session contract and a Codex/Grok feasibility note.
|