Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: sonnet Assistant-Process: 328925@bnt-lap001 Assistant-Session: 14b795fd-c632-4c01-8d28-e7e490c7b0ed
11 KiB
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):
- Add an optional
identitysection toExecutionRequest/ profile: requiredon_behalf_of(the person, becomesact.sub),mode(agent), requestedttl_seconds(profile ceiling 3600),audiencelist. - Before
rein.start_session, the gateway asks a pluggableAgentIdentityIssuer(interface in Glas, KeyCape-backed adapter) for a token whose subject is the run (agent:<request_id>),principal_type=agent,act.subthe person, expirymin(profile ttl, remaining timeout, 3600). Fail closed: no token, no identity-requiring profile run (newfailure_stagesuch asidentity). - 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. - 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.
- 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, tokenjti, issuer, expiry; no token),session_idandauthority_ref(assignment/role/duty already exist as refs) toExecutionEvidence. - 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 saysevents_completeness: unavailablerather 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
detailand 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
boundaryblock 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_profileagainst a rein-published manifest (rein-aharnessprofiles.pyregistry) 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 echoestool_profilein 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
- 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.
- Identity over a still-blocked runtime: all profiles are non-ready, so this should be built behind unverified profiles and proven in isolation first.
- 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).
- Hub authorship stays unauthenticated until the Hub changes (owner: state-hub).
actorvaluesadm/agt/atmpredate this standard; mappingagtto IAMprincipal_type agentneeds an agreed table with net-kingdom.- 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
- Contract fields and evidence (b, identity_ref placeholders) and the boundary declaration with tool-profile echo check (c): no external dependency, immediately useful.
- Issuer interface with a test double; fail-closed gateway path.
- Real KeyCape adapter and delivery once key-cape and sand-boxer agree.
- Interactive-session contract and a Codex/Grok feasibility note.