Skip to content

id(artifact): finish the receipt contract — frontier policy is Forbidden, builders refuse what receipt refuses - #5576

Merged
dezren39 merged 2 commits into
mainfrom
queue/9606-5539-receipt-contract
Nov 4, 2026
Merged

dezren39 merged 2 commits into
mainfrom
queue/9606-5539-receipt-contract

Conversation

@dezren39

@dezren39 dezren39 commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

Implements the remaining gaps of the #3231 receipt contract for issue #5539 (queue task 9606).

What was already on main

#3187 receipt rules (duplicate endpoints by validated identity, world_id bounds, replay grandfathering), #3192 receipt NFC checks, #3146 count/shape pins, and the duplicate-after check inside verify's helper.

This PR

Tests

  • cargo test -p id --lib on the laptop: 2136 passed, 0 failed (artifact+directory filtered run: 167 passed).
  • New/updated tests: Forbidden classification for duplicate frontier, builder refusal in sign_after, duplicate request IDs refused at insert, legacy duplicate-request removal still replays, declare_home producer refusal.

Refs #5539, #3231, #3196, #3146, #3187. Does not close #3232 (closing audit still owed).


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.

…den, builders refuse what receipt refuses

Implements the remaining gaps of the #3231 receipt contract (task 9606, issue #5539):

- verify(): after-frontier policy failures (too many / malformed /
  duplicate hashes) are now Refusal::Forbidden naming the rule, split
  from check_authenticity so hash/signature failures stay
  Refusal::Unauthenticated (#3196).
- SignedArtifact::sign_after refuses the same frontier violations at
  construction; the two receipt tests that crafted invalid frontiers
  through it now sign raw via a test helper.
- parsed(): friend_remove request IDs must be unique on fresh receipt
  (#3146 remainder); replay stays lenient, mirroring the #3187
  grandfathering, since the removed-request effect is idempotent.
- home_declared checks extracted to check_home_declared, shared by
  parsed() and Directory::declare_home, which now refuses a duplicate
  endpoint or out-of-bound world_id before signing (#3187 producer seam).
- artifact.rs module docs state the receipt contract (#3231); the
  field-by-field closing audit remains with #3232.

Tests: cargo test -p id --lib — 2136 passed, 0 failed (artifact+directory
filtered run: 167 passed). New/updated tests cover Forbidden
classification, builder refusal, duplicate request refusal at insert,
legacy duplicate-request replay, and declare_home producer refusal.
@dezren39
dezren39 requested a review from a team as a code owner November 4, 2026 16:16
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-04T17:00:01.393332Z 101a19f Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 59 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 4ddef845-4a7c-4874-88e4-86554cffbd43
Commits

Reviewing files that changed from the base of the PR and between 6d7845e and 101a19f.

Files selected for processing: 2
  • pkgs/id/src/artifact.rs
  • pkgs/id/src/directory.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 078f33886c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread pkgs/id/src/artifact.rs
Comment on lines +464 to +467
if !replay {
let mut named = HashSet::with_capacity(body.requests.len());
if body.requests.iter().any(|request| !named.insert(request)) {
return Err(forbidden("a friend removal names the same request twice"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use replay-aware parsing for directory recovery too

If an older server stored a removal containing duplicate request IDs and crashed between appending the artifact and its directory journal entry, upgrading now silently loses that removal's effect. Although ArtifactLog::open accepts the legacy artifact through parsed_for_replay, the recovery scans in Directory::open and Directory::replay_read_only still call strict artifact.parsed() (directory.rs:465 and directory.rs:569), which now rejects it. The friendship consequently remains active and the request IDs are not tombstoned. Both directory recovery scans need to use the replay-aware interpretation as well.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 101a19f (task 9606, lane code-y): both directory recovery scans — Directory::open and Directory::replay_read_only — now interpret stored artifacts with parsed_for_replay (widened to pub(crate)), mirroring the artifact log replay path. The live receipt path (receive_artifact) stays on strict parsed, so new receipts still refuse duplicate request IDs.

Regression test: a_legacy_removal_with_duplicate_request_ids_still_ends_the_friendship_on_recovery signs a removal naming the formed-by request ID twice, asserts strict parsed() refuses it, appends it to the artifact log with no journal entry, and asserts both recovery paths end the friendship (and, for writer open, tombstone the request ID). Targeted tests on the laptop: cargo test --lib directory:: 53 passed, cargo test --lib artifact:: 37 passed.

)

Directory::open and Directory::replay_read_only used strict parsed() when scanning the artifact log for unjournaled friend removals, so a legacy removal with duplicate request IDs (stored before #3146 refused them at receipt) was silently dropped on recovery: the friendship stayed active and its request IDs were never tombstoned. Both scans now use parsed_for_replay (widened to pub(crate)), mirroring ArtifactLog replay; the live receipt path in receive_artifact stays strict. Regression test covers both recovery paths.
@dezren39

dezren39 commented Nov 4, 2026

Copy link
Copy Markdown
Member Author

@codex review — pushed 101a19f addressing the P2 above (replay-aware parsing in both directory recovery scans + regression test).

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: 101a19fa23

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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.

Phase 3 (audit) of #3231 — field-by-field receipt-validation audit for pkgs/id artifacts + contract statement

1 participant