Skip to content

docs(sandbox): correct "can't fake hardware" claim in TraceSandboxAdapter - #315

Merged
imran-siddique merged 2 commits into
agentrust-io:mainfrom
rajnisht7:fix-claim-TraceSandboxAdapter
Sep 11, 2026
Merged

docs(sandbox): correct "can't fake hardware" claim in TraceSandboxAdapter#315
imran-siddique merged 2 commits into
agentrust-io:mainfrom
rajnisht7:fix-claim-TraceSandboxAdapter

Conversation

@rajnisht7

Copy link
Copy Markdown
Contributor

What this changes

The module docstring in sandbox.py and docs/integration/sandbox-runtime.md both said: "It will not let a caller claim hardware it does not have" and that a record saying tpm2 "carries a measurement that something other than
this process produced."

That's doesnt seem true. As SandboxAttestation only checks shape platform is in the allowed enum, measurement looks like a sha256:/sha384: digest. There's no quote, signature, or nonce check anywhere. So this is accepted as-is, signed,
and passes schema validation:

SandboxAttestation(
    platform="amd-sev-snp",
    measurement="sha256:" + "0" * 64,
)

Type of change

  • Editorial (typo, link fix, clarification: no normative effect)
  • Non-breaking spec change (new optional field, new platform profile, informative addition)
  • Breaking spec change (requires 14-day comment period and Project Lead sign-off)
  • Schema change
  • Example addition

Spec section

None

Checklist

  • DCO sign-off on all commits (git commit -s)
  • CHANGELOG.md updated (for any normative change)
  • Breaking changes marked with <!-- CHANGED: #NNN: description --> in spec text
  • Backward compatibility statement included (for breaking changes)

@rajnisht7
rajnisht7 requested review from a team and lywinged as code owners September 10, 2026 14:23
@rajnisht7
rajnisht7 force-pushed the fix-claim-TraceSandboxAdapter branch from 748a21b to 08ce15a Compare September 10, 2026 14:30
@rajnisht7
rajnisht7 force-pushed the fix-claim-TraceSandboxAdapter branch from fcd55b8 to 6e08d43 Compare September 10, 2026 15:28

@lywinged lywinged left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things to change, both small, and then this is an approval. Reviewed at 6e08d43 on a247244.

The correction is right. The original sentence claimed an appraisal the adapter never performed, and the two new docstrings say what is enforced and what is not. The second test is the more valuable half: it pins a property the docs already state and the adapter cannot enforce, that a genuinely verified quote signed with an unrelated key is indistinguishable here from a fabricated one.

What I checked rather than read:

  • sandbox.py with every docstring stripped parses to the same tree on this head and on main, so "No runtime behavior changes" is measured.
  • _runtime() copies platform, measurement and nonce from the attestation verbatim, and build_trust_record returns a placeholder cnf, which is what the new text says.
  • The three sentences attributed to docs/trust-levels.md and the one attributed to docs/verification.md, "The producing profile defines that binding", exist as quoted. Both new anchors resolve in an mkdocs build assembled the way docs.yml assembles it.
  • examples/sandbox-runtime.json's nonce decodes to sandbox-runtime-nonce.
  • The four CI steps with the pinned install, on 3.11 and on 3.12: green, 1404 passed and 1 skipped, the sandbox file 45 passed.

The first. examples/README.md line 24 still reads "sandbox-runtime.json: a sandboxed agent runtime, TPM 2.0 rooted." The guide now says of the same file "It is not a TPM-rooted record", so as merged the repository would say both about one file. Something like:

- `sandbox-runtime.json`: a sandboxed agent runtime in the shape a `tpm2` attestation
  produces. Its measurement, nonce and key are placeholders; see
  `docs/integration/sandbox-runtime.md`. Produced by `TraceSandboxAdapter`; the decision
  log is a kernel-sandbox policy trace rather than MCP tool calls.

The second. Two places say the nonce is checked against nothing: the field docstring, "nothing here or downstream checks that binding, so an unrelated string is accepted just as readily", and the new test's docstring, "or against anything else". The module docstring's "nothing in this codebase does" reads the same way to anyone who does not already know the parameter. sign.verify_record takes expected_nonce and compares it with runtime.nonce in constant time, and that parameter is the hook the paragraph's own advice needs, since a verifier that knows the challenge can already check the nonce. What nothing checks is the nonce's binding to the key, which is the true claim underneath all three. Naming the parameter is worth a clause, because no page under docs/ mentions it and a reader who takes the advice will otherwise not find it. For the field docstring, something like:

where that challenge goes; nothing here binds it to the key, and downstream
``verify_record(expected_nonce=...)`` compares it only with a value the verifier
already knows.

Three things I would not hold the merge for:

  • The CHANGELOG entry says the correction is "consistent with how every other Level 1 producer in this codebase is documented". The only other adapter, agt.py, emits Level 0, so that sentence describes a set with no other member. docs/trust-levels.md, which the entry already cites, is the claim that can be checked.
  • Twenty-two -- in the added text. They pass check_dashes.py, whose own hint for an em dash is "use a colon, a comma, or two sentences". main already carries fifteen, in one crosswalk page and three modules, so this is a preference rather than a rule.
  • sandbox.py line 307 has one extra leading space at the start of a docstring line.

Signed-off-by: rajnisht7 <rajnishtiwari9787@gmail.com>
@rajnisht7
rajnisht7 requested a review from lywinged September 10, 2026 17:48

@lywinged lywinged left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved on 4382e66.

Both changes landed as asked: examples/README.md no longer calls the example TPM-rooted, and the nonce field docstring now names verify_record(expected_nonce=...). The stray space is gone too. Re-run on this head with the pinned install: the four CI steps green, 1404 passed and 1 skipped, and a sweep of the whole tree for "TPM 2.0 rooted" finds nothing.

One clause from the same request is still standing, in the new test's docstring at lines 247 and 248: "or against anything else". verify_record(expected_nonce=...) is the thing it says does not exist. Not holding the merge for a test docstring, but since the field docstring beside it now says the true thing, this is the one line left saying the other:

``nonce`` is carried through verbatim and is never checked against ``cnf.jwk`` or
against the signing key passed to ``sign_record``; ``verify_record(expected_nonce=...)``
compares it only with a value the verifier already knows.

The other two notes stand as preferences and need nothing from you.

@imran-siddique
imran-siddique merged commit df0120b into agentrust-io:main Sep 11, 2026
5 of 6 checks passed
lywinged added a commit to lywinged/trace-spec that referenced this pull request Sep 11, 2026
`main` moved from a247244 to 760cc3f while this branch was open, taking
df0120b (agentrust-io#315) and 760cc3f (agentrust-io#327). The only conflict is CHANGELOG.md, where
agentrust-io#315 added an entry under `### Fixed` at the same anchor this branch does.
Both entries are kept, this branch's first, which is the order the file
already uses.

Nothing else overlaps: of the eight files this branch touches, CHANGELOG.md
is the only one main also touched.

The check worth stating is not the conflict. This branch's sweep accounts
for every parameter of every public function by name and fails on one it has
not swept or declared, and agentrust-io#315 changed src/agentrust_trace/adapters/sandbox.py.
It reports nothing new: on the merged tree the suite gives 1494 passed,
1 skipped and 2 xfailed, against 1491 passed and 2 xfailed on this branch
alone and 1402 passed on main alone, so the three tests main adds are the
whole difference and none is lost. The two xfailed are still xfailed rather
than xpassed, so agentrust-io#320 is still open and the strict marker still holds.

ruff, mypy on src/agentrust_trace, tools/check_dashes.py and the suite all
pass on the merged tree.

Signed-off-by: Louie Lu <48041247+lywinged@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants