feat(commerce): verify released UCP purchase accountability - #108
Conversation
|
🟡 Contributor Check: MEDIUM
Automated check by AgenTrust Contributor Check. |
carloshvp
left a comment
There was a problem hiding this comment.
Reviewed commit db6d6f7. No blocking findings.
Validated the host smoke: 229 tests passed with 94.92% combined statement/branch coverage, plus Ruff, formatting, mypy, and Bandit. Additional checks passed for restart persistence, cross-checkout grant replay, signed-header removal, and grant expiry. The four existing commerce tests passed, and regenerated fixtures were unchanged.
The implementation checks signature coverage and raw-body digests, enforces authorization before handler invocation, and commits the local SQL effect and cached evidence together. The documentation appropriately distinguishes authenticated observations from independent execution proof and limits the payment and consent claims.
Docker was unavailable locally; the container smoke passed in CI.
Approved within the documented scope of this offline, local verification harness.
imran-siddique
left a comment
There was a problem hiding this comment.
Approving. Taking the four acceptance criteria from #89 in turn, because that is what this PR answers and each one is separately checkable.
Schema validation. Offline bundles generated from UCP v2026-08-25 with provenance.json, the upstream licence, and a regeneration script, validated before SDK coercion and then against ucp-sdk==0.5.0. Checking the original JSON first is the right order: validating only the SDK-parsed object would test the SDK's tolerance rather than the wire artifact.
Signed protocol artifacts. Real ES256 HTTP message signatures rather than a shaped placeholder, twenty tests in test_wire.py.
The four negative cases. Each exists by name. test_correctly_signed_overspend_is_policy_denial is the one that matters most, because a correctly signed request being denied on policy is the whole point of the example. Substitution is covered from three directions: test_authenticated_target_substitution_is_denied, test_request_target_substitutions_are_denied, and test_auditor_rejects_cross_bound_signed_artifact_substitution. Stale digest is test_stale_signed_quote_is_rejected_against_current_checkout alongside test_digest_checks_raw_bytes_not_equivalent_json. Replay is the idempotency cluster, and test_equivalent_json_with_same_idempotency_key_still_conflicts is the one I would have asked for: it pins the comparison to raw bytes rather than to parsed equivalence, which is the failure mode that lets a re-serialized replay through.
Trust boundaries. Stated in the README rather than implied, and stated against the example's own interest: four disposable keys in one local process, roles cryptographically separate and not deployed as separate security domains, one fictional USD reservation and no real payment.
Two notes, neither blocking. The ci.yml addition is a per-example job, which is this repository's convention, and it runs the demo under --network none --read-only --cap-drop ALL --security-opt no-new-privileges with a pinned action SHA, so the harness proves itself without network. And this is the only uv.lock in the repository; that deviation is earned here because the --no-cache image build is what CI actually executes, so the lock is load-bearing rather than incidental.
On CI: this PR reported two checks until today because eight workflow runs sat in action_required and nobody could see them. Released, it is green on all nineteen, including released-ucp-accountability, five smoke jobs and every other example. 102 tests. The existing example and its fixtures are untouched, which is what makes this additive rather than a replacement.
Summary
Follow-up to #89 and the distinction from the illustrative example in #90: add a separate
agentic-commerce-accountability/released_ucpverification harness. The existing example and its fixtures keep their behavior; its README links to this upgrade.The example connects a merchant-authenticated checkout, a signed local spending grant, a platform-authenticated completion request, one local SQL effect, and an independently rerunnable evidence audit. It deliberately handles one fictional USD reservation and no real payment.
Acceptance evidence
ucp-sdk==0.5.0models. The release commit, resolver version, hashes, license, and regeneration procedure are included. Original JSON is checked before SDK coercion.http-message-signatures==2.0.1, required component coverage, signed UCP-Agent declaration, and RFC 9530 raw-body digest checks. Response transport annotations are not mistaken for authenticated request identity.joserfc; releasedagentrust-trace==0.10.0validates/signs/verifies the software policy record. The outer decision binds that record to the grant, checkout, request, response, policy, and configured key digests.GRANT_SPENTrefusals. Separate concurrent purchases retain their own invocation IDs. A post-handler failure is a transaction abort, never a denial claiming that no handler ran.The README contains a short allow trace, trust-boundary diagram, test-name matrix, and exact source links. The CI job runs the same Docker smoke as documented, with no runtime network, root user, writable image layers, capabilities, secrets, or publication.
Validation
On commit
db6d6f75daa3659a7e0fac5e49d01b41d8c10c62:linux/arm64: 229 passed, no skips; Ruff/formatting, mypy, Bandit andOFFLINE_SMOKE_PASSED. The image ran as UID/GID10001:10001with the documented network-none/read-only security flags. Image ID:sha256:378b760b77362091352cb952c8026472ca21ef3a4ea6e4e69b06a2d8bee4d34d.Deliberate limits
This is cap-based local authorization, not AP2 exact-price consent: the platform signs the checkout route/body, while the merchant authenticates terms and compares them against its current state. The grant permits one supported purchase under its cap.
No merchant network, payment instrument, settlement, discovery/enrollment service, hardware attestation, runtime-integrity proof, or full UCP/AP2 conformance is claimed. All roles run in one process with distinct keys. TRACE is software-only; a trusted controller's signed observation is not independent proof of physical execution. SQLite can roll back the effect here because the effect is entirely local SQL; this does not provide exactly-once external payment execution. The short-lived harness does not implement a production 24-hour retry SLA or historical archive verification. The pinned base, hash-verified bootstrap and Python lock do not imply bit-reproducible image output.
This PR supplies reviewable acceptance evidence for #89 without treating a local example as a protocol certification or automatically declaring the broader issue closed.