Repository navigation
A2 reader: snapshot take requires the custody export receipt - #13858
Conversation
|
Addressed review 79272 (dashboard-only REQUEST_CHANGES):
Do not merge: landing still waits on srv1/srv2 receipt read-back. |
|
review 79272 (on eccf863) is addressed on the current head cf33201.
— sent from clever-hawk-741 |
|
review 79277 asked for the SecretRef join to go through
The foreign-project wet RED is — sent from clever-hawk-741 |
|
review 79347: both findings are on head
Hermetic metadata claims: https://app.buildbuddy.io/invocation/62c8a69e-3ef8-4ea2-ab24-f2a0572ac060 (4 PASS). Do not merge: landing still waits on srv1/srv2 receipt read-back. — sent from clever-hawk-741 |
The take joins the same buffer it copied to a root-published receipt (no receipt-free fallback) and records the generation on the sealed snapshot, so a launch can name which Secret Manager version it ran. Co-authored-by: Cursor <cursoragent@cursor.com>
…t directory be publisher-owned. declared.host was unused; a receipt for another host with matching path and principals would have sealed. Directory mode bits alone also let a reader-owned 0755 directory pass. The attempt's NonEmptyStr host_identity stays a named residual. Co-authored-by: Cursor <cursoragent@cursor.com>
…a publisher-owned directory. Take uses resolve_returned_version (exact pin only), metadata is a pure decision over observed owners and modes, Claude custody is the declaration not a path fork, and the converge data leaf no longer imports SnapshotExecutor. Co-authored-by: Cursor <cursoragent@cursor.com>
admit_enrollment_secret_version already refuses latest; the 2026-10-10 srv1 custody run resolved versions/1. The pin follows the srv1 export receipt if that receipt names another version. Co-authored-by: Cursor <cursoragent@cursor.com>
…t carry fabricated owners. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
596b45c to
93da68d
Compare
…ject before version join. A path-based restat after the read let a replacement authenticate different bytes; directory authority, a regular-file lstat, and posix_sh_receipt_object_command keep owner, mode and content on one descriptor. Co-authored-by: Cursor <cursoragent@cursor.com>
…rammar. snapshot_path_dirname was a third, quadratic copy of dirname; the take now calls std.filesystem.path_parent_directory. exec < "$0" is a bash_build_with_redir_from_file row rather than a concatenated string. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Addressed review 79442 (dashboard artifact
— sent from clever-hawk-741 |
…ion arm has a discriminating RED. The replacement RED now runs the body with \$0 as the receipt path, directory authority is one pure function the observer calls before any content read, and the join returns the decoded receipt so the take does not parse twice. Co-authored-by: Cursor <cursoragent@cursor.com>
Native parse_g0 left tokens on `wrote && { let run ... }`, which refused the live-root population and failed witnesses.
Co-authored-by: Cursor <cursoragent@cursor.com>
…and the RED body. review 79454 was right that the stat-and-cat statement was written twice; the body program stays because the replacement and character-device REDs run it without the wrapper. Co-authored-by: Cursor <cursoragent@cursor.com>
review 79454The unused-helper claim was stale on this head: The duplication of the |
…ks keep a named cutover. emit call sites now use std.filesystem path_parent_directory. Belt and frontend walks still return empty for a relative basename, which is a different remainder, so they stay until those consumers admit the root. Co-authored-by: Cursor <cursoragent@cursor.com>
review 79460Body program. On this head path_parent_dir. Deleted. The three emit sites and the live_deploy emit witness call
|
…f this PR. The character-device RED already uses if/else so native parse_g0 does not leave tokens. SnapshotReceiptReadTimedOut is the timeout cause; live_deploy emit is restored to main. Co-authored-by: Cursor <cursoragent@cursor.com>
…t receipt at lstat. Directory-first take never reaches SnapshotCustodyUnreadable without a planted receipt, and a missing receipt is unobservable at lstat rather than unreadable at open. Co-authored-by: Cursor <cursoragent@cursor.com>
…m comment. A basename with no slash is not the filesystem root, and the helper comment must not roster cutovers that are a different question. Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
dispatch_credential_snapshot_takerequires the root-published export receipt (no fallback). Directory authority is established first (publisher-owned, no group/other write). The receipt is lstat'd as a regular file, then opened once; owner, mode and bytes come from that descriptor (extdeps.posix.sh_invocationposix_sh_receipt_object_command/posix_sh_receipt_object_body_program: wrapperexec < "$0", bodystat -Lof/dev/stdinthencat). Residual: after the directory is admitted, only the publisher can swap the path between lstat and open.declared.secret.project == fleet_secrets_project_idfirst (SnapshotReceiptSecretProjectMismatch), thenresolve_returned_versionagainstfleet_secrets_project_numberunchanged: onlySecretRefVersionResolvedExactadmits.SnapshotReceiptObservedNotRegular | SnapshotReceiptObservedRegular { … }). Claude guard yields the declaration. Custody leaf is data only.placement_settled: true. It is not a full remote-converge test.1, same shape as Cursor. Last srv1 custody run (2026-10-10, run 38086667921 / job 114315569214) resolvedprojects/582015116396/secrets/claude-code-oauth-harness/versions/1.admit_enrollment_secret_versionalready refuseslatest. IAM grant is per secret (fleet_secret_accessor_roster), not per version. The operator confirms the intended exact version. Custody's receipt must agree with it. If the observed version differs, landing remains blocked until the intended version is explicitly selected and the declaration and custody are brought into agreement.Landing gates
Claude/srv1 receipt and exact-head CI are satisfied. Cursor/srv2 receipt remains a mandatory C1 activation precondition; until it exists, Cursor snapshot acquisition refuses typed with no fallback.
Cursor activation chain: operator IAM bootstrap → approved
gcp-iam-converge→ srv2 Cursor custody converge → export receipt readback → C1 live entitlement trip. A missing or mismatched receipt must keep C1 from starting the provider.c6b72a3ead:export=PUBLISHED path=/etc/gunbc-claude-code/oauth-token-harness.gunbc-export-receipt sm_version=projects/582015116396/secrets/claude-code-oauth-harness/versions/1 digest=01062ea8d5e193fa4b0ddf78c74b9a922dbe5cb113a9b2a5676c4dd1f7946028, withcustody=HELD,content=identical-to-sm-version,dir=owner=root:briansrls mode=0750. The version agrees with the pinned1.c38fd21aa8dby squash onto current main).Test plan
test.claim.dispatch_credential_snapshot_wet_witness(33, the replacement / FIFO //dev/null/ timeout / directory-order / project REDs among them), pairingthe_real_take_accepts_the_production_export_publication,snapshot_receipt_metadata_witness(8),src/v2/test/claim/bash_command_fold.dag(63).c38fd21aa8d: passed.witnessesonc38fd21aa8d: SUCCESS, https://github.com/gunb-ai/gunbc/actions/runs/38466782474/job/115573267445 (attempt 2, srv4; earlier attempts were cancelled at the 90-minute job cap on srv3).Prior receipts on earlier heads remain in the conversation (coproduct, version join, rebase onto
std.live_tree).Mutation table (this head, same remote dispatch)
"$0"instead of/dev/stdina_replaced_receipt_does_not_authenticate_held_writable_bytesSnapshotReceiptJoinedover the held bytes, so the RED fails because the take accepteda_group_writable_directory_refuses_before_the_custody_readSnapshotCustodyUnreadable; RED failsa_character_device_on_held_stdin_is_not_a_regular_receipt/dev/nullis not refused; RED failsa_fifo_at_the_receipt_path_refuses_without_waitingSnapshotReceiptReadTimedOutafter about 5s; RED fails, no hanga_foreign_declared_project_refuses_a_fleet_number_receipt/a_declared_foreign_project_refuses_a_fleet_number_receiptSide chat: source APPROVE at
c38fd21aa8d; then LAND by squash onto current main, with no branch update or CI rerun.Composition at merge (main
dfa83f4baf): independent. Since the merge base, three PR files also changed on main (extdeps.exec.command,v2.extdeps.languages.bash,gunbc.roadmap.roadmap_dispatch_actuator), in disjoint regions; no added line uses the symbols #13882 moved. #13803 (v2 parser) changes no PR file. Its next-line[rule applies only after an operand, and the PR's two line-leading list literals followjoin(. Its lambda-body sealing only widens what parses.git merge-treeis clean.Head:
c38fd21aa8d4b00ec81d35c8f13b8274800a47d5