Close the cross-stream gaps the parallel fix round left open

Three items each of which fell between two agents' file lists.

`scrub_secrets_from_snapshots` was the third unsynchronised writer of
`triple-c-snapshot-{id}:latest`, after a recreate's commit and a
compaction. It has the same read-modify-write shape — create a scratch
container from the snapshot, commit back over the same tag — and loses
the same race, which here means re-baking the very credential it exists
to remove. It now takes the project's claim, under a new
`ProjectOp::SecretScrub`, and reports a snapshot it had to skip rather
than rewriting it unsafely.

Its scratch container also now carries `triple-c.scrub=true`, so the
Disk panel's reclaim bucket discriminates by label and by the live claim
rather than by a clock. The 15-minute age gate stays as the backstop for
the cross-process case the claim cannot see.

The store plugin is unregistered and its dependency dropped. Its
capability grants were removed as a host-file-write primitive; the
registration without a grant was unreachable but dead.

Finally, container.rs's fold test was pinning a fold that no longer
exists — disk.rs now emits the JSON exec form. It asserts the stronger
property instead: the script a compaction runs is byte-for-byte the one
snapshot_scrub_script() produces, so the two files cannot drift silently.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GBq2rGum6GX7xXgsas1fDc
This commit is contained in:
2026-08-23 11:53:25 -07:00
co-authored by Claude Opus 5
parent 17f031a5d7
commit a76f2c0a17
11 changed files with 169 additions and 417 deletions
+9
View File
@@ -96,6 +96,13 @@ pub enum ProjectOp {
/// write `:latest`, but it must not run while the container is being
/// removed out from under it.
CacheClear,
/// `container::scrub_secrets_from_snapshots` — the third writer of
/// `triple-c-snapshot-{id}:latest`, reached from `clear_claude_token`. It
/// creates a scratch container from the snapshot and commits back over the
/// same tag, so it is the same read-modify-write shape as a compaction and
/// loses the same race: any `:latest` move landing between its create and
/// its commit is overwritten by an image derived from the pre-read state.
SecretScrub,
}
impl ProjectOp {
@@ -108,6 +115,7 @@ impl ProjectOp {
ProjectOp::Reset => "This project is being reset",
ProjectOp::Destroy => "Something of this project's is being deleted",
ProjectOp::CacheClear => "This project's caches are being cleared",
ProjectOp::SecretScrub => "A revoked credential is being removed from this project's snapshot",
}
}
@@ -120,6 +128,7 @@ impl ProjectOp {
ProjectOp::Reset => "resetting it",
ProjectOp::Destroy => "deleting anything of its",
ProjectOp::CacheClear => "clearing its caches",
ProjectOp::SecretScrub => "removing a credential from its snapshot",
}
}
}