fix: two reachable panics + two OCI image digest nondeterminisms - #1105
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 29 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
Comment |
Four small independent fixes: two reachable panics and two sources of OCI image digest instability. None of them change
BuildSpec, the spec-hash encoding, or any cache key — behavior only changes on inputs that previously crashed, and for OCI images whose digests were previously unstable between identical runs.1.
mfile: empty exec string panicked the task parserTask::exec_and_argstokenized a task'sexecstring withshlexand called.next().unwrap()on the token stream. Anexecthat is empty, whitespace-only, or otherwise yields no tokens has no first token, sominimalpanicked on a malformed-but-easy-to-writeminimal.toml:The list form already handles this case:
exec = []resolves to("", [])and fails downstream with a real error. The fix makes the string form take the same path. Regression test included (exec_str_empty_does_not_panic).2.
lcache: special files in a cache directory panicked the walkerlcache'sDirEntry::file_typeclassified entries asFileorDirand hitunreachable!()for anything else. But the local cache directory is ordinary host filesystem — a stray symlink, socket, or fifo (leftover tooling, a curious user, a crashed process) is entirely reachable, and one such entry made any cache walk panic. Added aFileType::Othervariant so walks classify these instead of crashing. The cache itself never creates such entries; this only makes foreign ones survivable. No callers matched exhaustively on the enum, so no behavior changes forFile/Dir.3.
op: OCI image layer order depended on thread schedulingImage layers are built in parallel under a
rayon::scope, and each worker pushed its finished layer into a sharedVec— i.e. layers landed in completion order, which varies run to run with thread scheduling. Layer order is part of the OCI manifest, and the manifest digest is the image digest, so two builds of the identical graph could produce different image digests. Workers now tag results with their dependency index and the results are sorted back into dependency order before manifest assembly — same layers, same content, stable order.4.
op: OCI config env order depended on HashMap iterationThe image config's
envlist was built by iterating aHashMapdirectly. Rust'sHashMapiteration order is randomized per process, so the config blob — and with it the image digest — differed between identical builds. The vars are now sorted by key before serialization.Why 3 and 4 matter beyond tidiness
These made
op's OCI output non-reproducible even for perfectly reproducible inputs: the same graph, same artifacts, same everything produced a different image digest each run. Anything that wants to compare, cache, sign, or attest image digests needs digest stability first. (Because the previous digests were unstable, nothing could have validly pinned one — so stabilizing them breaks no existing expectation.)Provenance
All four were findings of the formal-verification readiness audit of minimal's pure cores (write-up circulating separately); they are its "phase 0" — fixes that stand on their own regardless of any decision about that effort.
🤖 Generated with Claude Code
Note
Fix two reachable panics and two OCI image digest nondeterminisms
lcache::fs::FileTypegains anOthervariant;file_type()in fs.rs returns it for symlinks, sockets, and other non-file/non-directory entries instead of callingunreachable!().Task::exec_and_args()in tasks.rs returnsSome(("", vec![]))for empty or whitespace-only exec strings instead of panicking on an unwrap.lcache::fs::FileTypemust now handle the newOthervariant.Macroscope summarized d8ae2d9.