feat(adapters): TraceSandboxAdapter for sandboxed agent runtimes - #130
Merged
Conversation
A kernel sandbox confines one agent on one machine. It does not answer, on its own, which agent on which of two hundred machines took an action, what actually ran rather than what the policy said, or how to say either on a host with no secure hardware. TraceSandboxAdapter builds a Trust Record from what such a runtime already has at session close: sandbox identity, image digest, the effective policy bundle bytes, and the decision log. It requires no change to the runtime. One code path spans Level 0 and Level 1. Passing a SandboxAttestation moves the record from software-only to the attested platform and nothing else about the call changes, because a sandbox runs wherever the customer runs it and the deployments that most need evidence often have the least hardware. A caller cannot claim hardware it does not have: platform is only ever set from a supplied attestation, an attestation may not name software-only, the platform is validated against the enum on RuntimeInfo rather than a copy of it, and the measurement must be a digest. Sandbox identity and image ride the existing subject and build_provenance.digest, so no schema change was needed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Imran Siddique <imran.siddique@opaque.co>
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
Adds
TraceSandboxAdapter, a first-party adapter that builds Trust Records from a sandboxed agent runtime: the class of runtime that confines one agent on one machine with kernel isolation (Landlock, seccomp), an egress policy, and injected credentials.That confinement answers what a single agent may touch. It does not answer, on its own:
The adapter answers all three from what the runtime already has at session close. No change to the runtime is required, and no schema change was needed.
Design notes
One code path spans Level 0 and Level 1.
TraceAGTAdapterhardcodessoftware-only. This adapter takes an optionalSandboxAttestation; supplying it moves the record to the attested platform and nothing else about the call changes. A sandbox runs wherever the customer runs it, and the deployments that most need evidence often have the least hardware. An adapter that could only emit Level 0 would force a second code path for exactly those.A caller cannot claim hardware it does not have.
platformis only ever set from a supplied attestation; an attestation may not namesoftware-only; the platform is checked againstget_args(RuntimeInfo.model_fields["platform"].annotation)rather than a hand-maintained copy, with a test guarding the drift; and the measurement must be asha256:/sha384:digest. A record readingtpm2therefore carries a measurement something other than this process produced.Two defaults differ from the AGT adapter, deliberately.
appraisal.statusdefaults to"none", not"affirming". Building a record does not appraise it, andaffirmingwould put a verdict in the field a consumer reads to find out whether anybody checked.transparencydefaults toNoneand is omitted. That is what an unanchored record should say below Level 2.tool_transcript.hashuses RFC 8785, notjson.dumps(sort_keys=True). The two agree on ASCII and diverge on non-ASCII strings and number formatting. A decision log carries paths and hostnames, andsign.pyalready canonicalises the signature pre-image with JCS for the reason its docstring gives. A test asserts the divergence on non-ASCII input so the choice is not silently reverted.Sandbox identity and image ride the existing
subjectandbuild_provenance.digest. A dedicatedsandboxobject belongs in a later profile.Type of change
Additive only. No normative text, no schema field, no existing behaviour altered.
Spec section
None modified.
docs/integration/sandbox-runtime.mdis a new informative integration guide alongsideagt.mdandcmcp.md.Testing
43 new tests, 148 passing overall. Coverage includes: structural validity and sign/verify round trip; a tampered record failing verification; the Level 0 measurement being reproducible from its two named inputs and moving when either changes; attestation fields reaching the record verbatim; every rejection path for a dishonest platform or measurement claim; the platform-enum drift guard; JCS vs naive-sorted-JSON divergence on non-ASCII; key-order stability; determinism.
Two pre-existing issues surfaced, not introduced
transparencymodel/schema divergence. 0.5.1 madetransparencyoptional on the model because an unanchored record has no receipt to name, butschema/trace-claim.jsonstill lists it inrequired. An unanchored record therefore validates against the model and not against the published schema.test_unanchored_record_is_model_valid_but_the_json_schema_still_requires_transparencydocuments this and will fail loudly the day it is reconciled, rather than being rediscovered downstream. Happy to split the schema fix into its own PR.ruff check srcreportsUP038insign.py:356onmain, unrelated to this change. Left alone to keep this PR additive.Checklist
git commit -s)CHANGELOG.mdupdatedexamples/sandbox-runtime.jsongenerated by the adapter and validated againstschema/trace-claim.jsonruffandmypyclean on all changed files🤖 Generated with Claude Code