Skip to content

feat(receiptspec): extract public stdlib-only receipt protocol package - #34

Merged
shreyanshjain7174 merged 3 commits into
mainfrom
feat/receiptspec
Oct 2, 2026
Merged

shreyanshjain7174 merged 3 commits into
mainfrom
feat/receiptspec

Conversation

@shreyanshjain7174

Copy link
Copy Markdown
Contributor

What

Extract the receipt protocol into pkg/receiptspec (stdlib only). internal/receipt forwards to it via type aliases. One implementation. Wire format unchanged.

Why

The Clawdlinux operator needs the same receipt format and verifier. A second producer must not reimplement chaining or verification.

Changes

  • pkg/receiptspec: Receipt, Validate, canonical hashing, Chain builder, JSONL, trust root, chain and manifest verification.
  • HashRecord and VerifyRecordBinding bind an arbitrary decision record to a receipt through params_sha256. No enum change. See pkg/receiptspec/DECISION.md.
  • cmd/agentgate-verify reads and verifies through receiptspec.
  • Gateway ledger builds receipts with receiptspec.Chain.

Verification

  • go build, go vet, gofmt clean.
  • go test ./...: 19 ok packages, 0 FAIL. Golden vectors and external tests unchanged and passing.
  • go list -deps ./pkg/receiptspec: standard library only.
  • Fuzz run on canonical JSON: no failures.

Follow-up

Tag v0.1.4 after merge so the operator can drop its local replace.

Move the receipt type, canonical hashing, chain and manifest verification,
and JSONL encoding into pkg/receiptspec. internal/receipt now forwards to it
with type aliases, so there is one implementation and the wire format is
unchanged. Add a Chain builder for other producers, plus HashRecord and
VerifyRecordBinding for decision records bound through params_sha256.
agentgate-verify uses receiptspec for JSONL parsing and verification.

Signed-off-by: Shreyansh Sancheti <43677304+shreyanshjain7174@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Protocol safety and compatibility need human review, and blocking correctness issues remain.

Review effort: Balanced
Findings: 1 High severity · 3 Medium severity

Open (4)
What changed in this PR

Extracts AgentGate’s receipt protocol into a public, standard-library-only package so other producers can share the gateway’s implementation.

Changes:

  • Adds public receipt production, verification, and decision-record binding without changing the v1 wire format.
  • Moves gateway and CLI protocol operations to the shared package, with compatibility tests and documentation.
File Description
README.md Documents other receipt producers.
pkg/​receiptspec/​verifier.go Adds public chain and bundle verification.
pkg/​receiptspec/​sign.go Adds signing and individual receipt verification.
pkg/​receiptspec/​record.go Adds canonical decision-record hashing and binding.
pkg/​receiptspec/​record_test.go Tests record canonicalization and binding.
pkg/​receiptspec/​receipt.go Defines public receipt types and validation.
pkg/​receiptspec/​manifest.go Provides signed export-manifest operations.
pkg/​receiptspec/​jsonl.go Provides JSONL parsing and writing.
pkg/​receiptspec/​encoding.go Implements canonical receipt hashing.
pkg/​receiptspec/​DECISION.md Documents decision-record conventions.
pkg/​receiptspec/​chain.go Adds the reusable chain builder.
pkg/​receiptspec/​chain_test.go Tests chain construction and compatibility.
internal/​signer/​signer.go Delegates key-ID computation.
internal/​receipt/​verifier.go Forwards verification APIs.
internal/​receipt/​record_jcs_test.go Checks hashing against gateway canonicalization.
internal/​receipt/​receipt.go Aliases public receipt types and validation.
internal/​receipt/​ledger.go Builds ledger receipts through the shared chain.
internal/​receipt/​jsonl.go Forwards JSONL encoding APIs.
internal/​receipt/​export.go Forwards manifest and key-line APIs.
internal/​receipt/​encoding.go Forwards canonical hashing APIs.
cmd/​agentgate-verify/​receiptspec_test.go Tests verification of another producer’s receipts.
cmd/​agentgate-verify/​main.go Uses shared JSONL and bundle verification.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread pkg/receiptspec/sign.go
Comment thread pkg/receiptspec/manifest.go
Comment thread pkg/receiptspec/record.go
Comment thread pkg/receiptspec/verifier.go Outdated
…und input)

Seal and Chain.Next clone DelegationChain so returned receipts never alias
caller slices. VerifyManifest and VerifyChain reject wrong-length trusted
public keys instead of panicking in ed25519.Verify. CanonicalRecord bounds raw
input at 1 MiB before decoding.

Signed-off-by: Shreyansh Sancheti <43677304+shreyanshjain7174@users.noreply.github.com>
Signed-off-by: Shreyansh Sancheti <43677304+shreyanshjain7174@users.noreply.github.com>
@shreyanshjain7174
shreyanshjain7174 requested a balanced review from Copilot October 2, 2026 04:27
@shreyanshjain7174
shreyanshjain7174 merged commit d1b7219 into main Oct 2, 2026
2 checks passed
@shreyanshjain7174
shreyanshjain7174 deleted the feat/receiptspec branch October 2, 2026 04:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Public protocol APIs need human review, with unresolved trust handling and signing-key ownership issues.

Review effort: Balanced
Findings: 1 High severity

Open (1)
Resolved since last review (4)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Mutable private key slice invalidates cached signer identity

pkg/​receiptspec/​sign.go:47

The constructor retains the caller's mutable key slice but caches its KID. Reusing or clearing that buffer changes later signatures while the signer still reports the original KID. Receipts then fail verification against the original public key. Clone priv before computing the KID and storing the key.

Comment on lines +241 to +242
if len(trusted) == 0 {
trusted = b.Keys
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.

2 participants