Skip to content

adapters: make AGT transparency optional and validate session fields (#534) - #539

Open
drk-ram wants to merge 1 commit into
agentrust-io:mainfrom
drk-ram:drk-ram-fix-adapters-agt-and-sandbox-validation
Open

drk-ram wants to merge 1 commit into
agentrust-io:mainfrom
drk-ram:drk-ram-fix-adapters-agt-and-sandbox-validation

Conversation

@drk-ram

@drk-ram drk-ram commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

What this changes

Closes #534

Contributor: Raghuvar Durga (@drk-ram)

tests/test_public_functions_raise_what_they_document.py declares "adapters": ("ValueError", "ValidationError") in DOCUMENTED, but _public_functions() skips classes, leaving TraceAGTAdapter, AGTSessionResult, TraceSandboxAdapter, and SandboxSessionResult unswept. This change fixes four boundary defects across the two reference adapters:

  1. Optional transparency in TraceAGTAdapter: TraceAGTAdapter.__init__ now accepts transparency: str | None = None (matching TraceSandboxAdapter.__init__), omits "transparency" from the emitted record when self._transparency is None, and validates that any non-None transparency in both TraceAGTAdapter and TraceSandboxAdapter is a non-empty str. Removes the transparency="https://example.test/unused" and record.pop("transparency") workaround from docs/tutorials/agt-adapter.md.
  2. AGTSessionResult field validation: Validates agent_did (against _SUBJECT_RE), policy_bundle_bytes (isinstance(..., bytes)), audit_entries (list of dict objects), merkle_chain_tip (non-empty UTF-8 str without lone surrogates), and call_count (non-negative int, not bool, within [0, JCS_SAFE_INTEGER], or None) both in AGTSessionResult.__post_init__ and in TraceAGTAdapter.build_trust_record / hash helpers, raising ValueError.
  3. SandboxSessionResult and TraceSandboxAdapter field validation: Validates policy_bundle_bytes (isinstance(..., bytes)), decisions (list of dict objects), attestation (SandboxAttestation or None), and call_count (non-negative int, not bool, within [0, JCS_SAFE_INTEGER], or None) in SandboxSessionResult.__post_init__ and TraceSandboxAdapter.build_trust_record / bundle_hash / transcript_hash, and validates image_digest and bundle_hash in TraceSandboxAdapter.software_measurement, raising ValueError.

Cold-reader review findings and changes made:

  • SandboxSessionResult.attestation was not checked in SandboxSessionResult.__post_init__ or re-validated in TraceSandboxAdapter.build_trust_record, allowing non-SandboxAttestation objects to leak AttributeError in _runtime() and post-construction object.__setattr__(att, "platform", "software-only") mutations to bypass SandboxAttestation.__post_init__. Added _check_attestation to both SandboxSessionResult.__post_init__ and TraceSandboxAdapter.build_trust_record.
  • build_trust_record(session) in both adapters accessed attributes on session before checking isinstance(session, ...), raising AttributeError on None or non-session inputs. Added isinstance checks raising ValueError at the start of build_trust_record in both adapters.
  • _check_merkle_chain_tip accepted lone UTF-16 surrogates ("\ud800") at AGTSessionResult construction and deferred a UnicodeEncodeError to _measurement. Added a UTF-8 encode check in _check_merkle_chain_tip.
  • TraceSandboxAdapter.software_measurement(image_digest, bundle_hash) did not validate its arguments. Added _check_image_digest and _check_bundle_hash checks in software_measurement.
  • Added unit tests for TraceAGTAdapter._measurement, SandboxSessionResult.attestation, TraceSandboxAdapter.software_measurement, and in-place / post-construction mutation guards on build_trust_record.

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

Reference library adapters (src/agentrust_trace/adapters/agt.py, src/agentrust_trace/adapters/sandbox.py) and tutorial (docs/tutorials/agt-adapter.md), aligning with spec/trace-v0.2.md section 3.1 (optional transparency below Level 2, subject URI pattern, tool_transcript, and policy.bundle_hash).

Tests for a fix

Added in tests/test_agt_adapter.py and tests/test_sandbox_required_string_fields.py:

  • test_transparency_defaults_to_none_and_is_omitted_when_unanchored
  • test_transparency_rejects_empty_or_non_string
  • test_agent_did_rejects_invalid_or_non_string_values
  • test_policy_bundle_bytes_rejects_non_bytes
  • test_audit_entries_rejects_non_list_or_non_dict_items
  • test_merkle_chain_tip_rejects_empty_or_non_string
  • test_call_count_rejects_invalid_values
  • test_build_trust_record_revalidates_session_and_in_place_mutations
  • test_session_policy_bundle_bytes_refuses_non_bytes
  • test_session_decisions_refuses_non_list_or_non_dict_entries
  • test_session_call_count_refuses_invalid_values
  • test_adapter_transparency_refuses_empty_or_non_string
  • test_session_attestation_refuses_non_attestation_values
  • test_software_measurement_refuses_invalid_digests
  • test_sandbox_build_trust_record_revalidates_session_and_in_place_mutations

Validation commands run and results:

  • python -m pytest tests/test_agt_adapter.py tests/test_sandbox_required_string_fields.py tests/test_sandbox_adapter.py tests/test_docs_quickstart.py tests/test_integer_by_value.py tests/test_public_functions_raise_what_they_document.py -q: passed (607 passed)
  • python tools/review_bar.py --base origin/main --head HEAD: passed (79 fail on behaviour, 0 fail on a missing name or file, 64 pass or skip)
  • python -m ruff check src/agentrust_trace/adapters/agt.py src/agentrust_trace/adapters/sandbox.py tests/test_agt_adapter.py tests/test_sandbox_required_string_fields.py: passed (All checks passed!)
  • python -m mypy src/agentrust_trace/adapters/agt.py src/agentrust_trace/adapters/sandbox.py: passed (Success: no issues found in 2 source files)
  • python tools/check_dashes.py: passed (no dashes outside examples/, spec/trace-v0.1.md)

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)

- Make `transparency: str | None = None` optional in `TraceAGTAdapter`
  and omit `"transparency"` from the emitted record when `None`,
  matching `TraceSandboxAdapter`.
- Reject empty or non-string non-`None` `transparency` values with
  `ValueError` in both `TraceAGTAdapter` and `TraceSandboxAdapter`.
- Validate `agent_did`, `policy_bundle_bytes`, `audit_entries`,
  `merkle_chain_tip` (including UTF-8 surrogate rejection), and
  `call_count` in `AGTSessionResult` and `TraceAGTAdapter`, raising
  `ValueError`.
- Validate `policy_bundle_bytes`, `decisions`, `attestation`,
  `call_count`, and `software_measurement` digest inputs in
  `SandboxSessionResult` and `TraceSandboxAdapter`, raising `ValueError`.
- Remove the `transparency="https://example.test/unused"` and
  `record.pop("transparency")` workaround from `docs/tutorials/agt-adapter.md`.

Fixes agentrust-io#534

Signed-off-by: Raghuvar Durga <177662415+drk-ram@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@drk-ram
drk-ram requested review from a team, lywinged and rajnisht7 as code owners October 15, 2026 22:13

@imran-siddique imran-siddique left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approving 2bbecec. The three touched test files run 337 of 337 here; full suite 3864 passed, and the only local failures are Windows path cases that fail identically on main. Three mutations, each killed: emitting transparency when it is None, dropping the JCS_SAFE_INTEGER bound on call_count, and accepting non-dict entries in decisions. The tutorial no longer needs the record.pop("transparency") workaround, which was the point of #534.

One cleanup for later: _check_policy_bundle_bytes, _check_call_count and _check_transparency are now identical in agt.py and sandbox.py. A shared adapters module would keep the two from drifting.

)


def _check_call_count(value: object) -> None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same body as agt.py:73. Not blocking.

This branch has not been deployed

No deployments
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.

adapters: TraceAGTAdapter requires dummy transparency for Level 0 records, and both adapters accept str/dict transcripts and invalid session fields

2 participants