-
released this
2026-09-23 03:48:48 +00:00 | 324 commits to main since this releaseLand R-I25: version the artifact digest, and the frozen-source digest too
Self's finding: R-I20 changed digest_artifact's bare-file shape, but three
stored values are compared against a fresh recompute forever after they are
sealed -- expected.artifact_sha256 (IdunnExpectedIncarnationRecord),
ArtifactReceipt::sha256 (SealedRelease, in host.rs's verify_artifacts), and
HostWorkloadObservation::executable_sha256. The first Idunn upgrade past
R-I20 would have refused every already-installed and already-running
workload sealed before it.The ruling asked for an explicit version tag recorded with the stored
value. That channel does not exist here: expected.artifact_sha256 and
ArtifactReceipt::sha256 are both validated to a baresha256-<64 lower hex>
shape with no room for one -- IdunnExpectedIncarnationRecord's validator
lives in the pinned cultnet-rs git dependency, a separate repo this
worktree has no authority to widen, and ArtifactReceipt::sha256's own local
validator enforces the identical shape. There has only ever been one prior
shape (raw_sha256 of the file's bytes alone, nothing else), so
verify_artifact_digest recomputes under the current algorithm first and
falls back to that exact legacy shape -- the same effect as reading an
implicit version, without a tag this worktree cannot add. New seals always
call digest_artifact directly, so they always use the current shape;
nothing here ever rewrites a stored value to match.host.rs's start(), observe() and verify_artifacts() now go through
verify_artifact_digest instead of comparing digest_artifact's output to the
stored string directly. start() carries expected.artifact_sha256 forward
into the returned observation rather than a fresh recompute, so a
legacy-shaped receipt is echoed, not silently upgraded to a value it was
never sealed against.Checked whether frozen_source_sha256 (the frozen-source digest,
observe_frozen's stored-value comparison against FrozenSourceReceipt) has
the same exposure: yes. Its algorithm changed twice before this batch
touched anything -- R-I9 added mode and gid, R-I18 added xattrs -- and a
FrozenSourceReceipt is persisted in DeploymentTransaction.frozen_source
between the freeze() step and the step that calls observe_frozen, each a
separate advance_sealing call that can cross a restart. The window is
narrower than the artifact side (one in-flight Sealing-phase transaction,
not every installed workload), but this cut's own batches 6 through 8
already crossed it twice. verify_frozen_source_digest applies the same
answer against both prior shapes, which are reproduced verbatim in
frozen_source_sha256_legacy from git history (f873b54^ andf873b54).Tests: verify_artifact_digest_accepts_a_receipt_sealed_under_the_pre_r_i20_shape
and verify_frozen_source_digest_accepts_both_shapes_that_predate_this_cuts_sixth_batch
construct a stored value the old code would have produced and confirm the
new code still accepts it, confirm the current-algorithm-only comparison
they replace would have refused it, and confirm a real content tamper is
still caught. verify_artifacts_accepts_a_receipt_sealed_under_the_pre_r_i20_shape
exercises the same thing through host.rs's own verify_artifacts. Manually
mutated (fallback removed, then restored) on Yggdrasil; see the verification
report.Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Downloads
-
Source code (ZIP)
1 download
-
Source code (TAR.GZ)
1 download
-
Source code (ZIP)