Summary
Two checksums.yaml pins are stale against live upstream, so ACFS refuses to
install lang.rust and tools.atuin with Security Error: Checksum mismatch.
Contrary to the error text, main does not carry refreshed values — the
entries are byte-identical on the release commit and on main, so neither
--checksums-ref main nor waiting helps.
This is a recurrence of #398, which reported tools.atuin stale on v0.9.0 with
different hashes. So the pin was refreshed after #398 and has gone stale again
— the underlying cause is that these URLs are moving targets, not a one-off
missed refresh.
Environment
ACFS version: 0.10.0
Release commit: ba924f17f4b00a6c4b57966570633e27c9422c69
main at test time: 405de32b3e8c22aadc90c8783d1694fdf48ddf92
OS: Omarchy 4.0.6 (ID=omarchy, ID_LIKE=arch)
Date observed: 2026-10-21Observed mismatches
ERROR: Security Error: Checksum mismatch for rust
Expected: 7d0ea0f8eba7fa1ebfe998091cd7ec4501e33ec5ca6b884eb4d894d7da5170af
Actual: 9502b514362a21096210d498f143b8cdacda365d3dfcf45e8f5541e089ccafc0
URL: https://sh.rustup.rs
ERROR: Security Error: Checksum mismatch for atuin
Expected: e632c6d1dc71e75c9710caf5f645c11131f0d94c859ed6b4266444e11240abdb
Actual: 69c7c0e057084ede4536de25f856c037f4649dcf8f29cc98a64ac52340320a99
URL: https://github.com/atuinsh/atuin/releases/latest/download/atuin-installer.shmain has the same stale values
Fetched checksums.yaml from both refs and compared — identical entries:
# identical at ba924f17… and at main (405de32b…)
atuin:
url: "https://github.com/atuinsh/atuin/releases/latest/download/atuin-installer.sh"
sha256: "e632c6d1dc71e75c9710caf5f645c11131f0d94c859ed6b4266444e11240abdb"
rust:
url: "https://sh.rustup.rs"
sha256: "7d0ea0f8eba7fa1ebfe998091cd7ec4501e33ec5ca6b884eb4d894d7da5170af"The error text states:
End users: checksums.yaml is refreshed from upstream automatically, so a mismatch on a current ACFS means the PUBLISHED pin is stale
For these two entries that automatic refresh has not happened on main, so the
only recourse the message offers (acfs hold) leaves the tools permanently
uninstalled.
Likely reason the drift went unnoticed: #457
The checksum monitor has been flapping for the past week — all comments on #457 are automated alerts:
| Timestamp (UTC) | Event |
|---|---|
| 2026-10-15 20:31 | recovered after 6 consecutive fail-closed runs |
| 2026-10-15 23:16 | failed closed ×3 — "remote main and legacy mirror differ before observation" |
| 2026-10-15 23:31 | recovered after 3 fail-closed runs |
| 2026-10-16 10:01 | failed closed ×3 — "pinned base already contains generated drift" |
| 2026-10-17 23:31 | failed closed ×3 — "remote main and legacy mirror differ" |
Drift monitoring was therefore intermittently down across the window in which these two pins went stale, and the last recorded state is fail-closed. Fixing #457 is probably a prerequisite for these pins staying fresh.
Cascade
tools.ast_grep installs via ~/.cargo/bin/cargo install ast-grep --locked, so
the lang.rust failure cascades into it:
ERROR: tools.ast_grep: install command failed: ~/.cargo/bin/cargo install ast-grep --lockedRoot cause: unpinnable URLs
Both entries point at moving targets:
https://sh.rustup.rs— a live script that changes whenever rustup ships.…/releases/latest/download/atuin-installer.sh—latestby definition.
Neither can be pinned durably, so both will drift again immediately after any refresh. #435 reports the same class of problem for AADC ("still builds unpinned main despite published installer and binaries").
Suggested fix
- Re-pin
rustandatuinvia./scripts/lib/security.sh --update-checksums. - Prefer immutable, versioned URLs over
latest/download/andsh.rustup.rs— e.g. pin a specific atuin release tag, and for rustup pin a versionedrustup-initartifact rather than the live bootstrap script. Where a distro package is a viable source (Arch shipsatuinandrustupinextra), consider allowing that path to satisfy the module instead. - Soften the end-user text: it currently promises an automatic refresh that did
not occur here, and offers
acfs holdas the only recourse. Whenmainand the release commit carry the same stale hash, saying so explicitly would save users from trying--checksums-ref main. - Surface stale pins in
acfs doctoras a distinct state from "install failed", so users can tell an upstream pin problem from a local one.
Workaround used
Skipped the module and installed from Arch extra instead:
sudo pacman -S --needed atuin rustup
rustup default stable # rust 1.99.1Note this does not satisfy either module's installed_check — lang.rust
tests test -x ~/.cargo/bin/cargo while Arch's rustup places proxies in
/usr/bin, and tools.atuin requires ~/.atuin/bin/atuin plus an
ACFS-generated wrapper marker. Reported separately in the Arch/Omarchy
generated-modules issue.
Related
#398 (same class, v0.9.0, closed), #457 (monitor failing closed — likely why
this drifted), #435 (unpinned main builds), #468 (checksums.yaml re-pin
breaking bootstrap integrity).
Activity
2Review of the v18.24.2 atuin-installer.sh bytes behind the pending authorization in #480 (digest d7643f38…), for the atuin half only.
Hash. releases/latest/download/atuin-installer.sh still hashes to 682117ada10ef0886fa4974f1afcf5fb396ce466c45acaffbf075eeb06f6dc25 today (2026-10-27). That matches releases/download/v18.24.2/atuin-installer.sh, and v18.24.1's installer hashes to the current pin 69c7c0e0…. main (5e344051) still carries 69c7c0e0….
Diff v18.24.1 → v18.24.2. Only the usual per-release cargo-dist changes. No logic differs:
APP_VERSION18.24.1→18.24.2releases/download/v18.24.1→v18.24.2in the threeARTIFACT_DOWNLOAD_URLSbranches and the help text- the
versionfield of the embedded install receipt (cargo-dist0.31.0in both) - the seven per-platform
_checksum_valuesha256 entries
Both files are 55965 bytes.
Embedded artifact hashes vs. the release. I compared these with the release's published .sha256 assets:
| target | installer | release .sha256 |
|---|---|---|
x86_64-unknown-linux-gnu | 005a4953f2fe96d4… | 005a4953f2fe96d4… ✓ |
aarch64-unknown-linux-gnu | 5ec6cc8bd3889b61… | 5ec6cc8bd3889b61… ✓ |
The release was published by github-actions[bot] on 2026-10-22T10:07:24Z with 36 assets.
Not covered. I did not find a .sha256 asset under the atuin-x86_64-unknown-linux-musl-static.tar.gz.sha256 name, so that target's embedded value (311cd1ba…) is unverified here. I also did not review the uv half of #480 (live https://astral.sh/uv/install.sh currently hashes to 1c6e7f02…, the same value #480 observed). The authorization should still get its own look at uv.
Context: we hit this on a 0.10.0 VPS, where acfs update reported Atuin (reinstall) as its only failure. We're holding atuin there (acfs hold atuin --expiry 2026-11-10) until the pin is published.
I checked both pins on main against the live upstream files today.
rust(https://sh.rustup.rs): the checksum monitor refreshed this pin in 99fe9f79 on 2026-10-21, about half an hour after this report, to9502b514…, the value you observed. Upstream still hashes to that value.atuin: 99fe9f79 also refreshed this pin, to69c7c0e0…, the value you observed. Atuin then released v18.24.2 on 2026-10-22, andreleases/latest/download/atuin-installer.shnow hashes to682117ad…. So main is stale for atuin again.The monitor is not broken here; this deferral is deliberate. It publishes new hashes on its own only for installers hosted by this repository's owner. A change to a third-party installer waits until a maintainer has reviewed the new bytes and authorized that exact change. The monitor opened that request within minutes of the release: #480 (#481 is a duplicate with the same digest). The request also covers
uv, whose installer changed upstream the same day.I re-ran
scripts/lib/security.sh --verify --jsonagainst main today. atuin and uv are the only mismatches, and their evidence still hashes to the digest in #480, so that authorization request is current.Remaining operator step: review the v18.24.2
atuin-installer.shand the currenthttps://astral.sh/uv/install.sh. Then, on the monitor host, writeauthorize:d7643f38a766a806f15fb0fb97a17621adf8fcb25b0e911b66eb5f1501a9b4b9intoauthorized-checksum-changein the monitor's state directory ($ACFS_MONITOR_STATE, default~/.local/state/acfs-monitor). The file must be owner-only and must not be a symlink. The next monitor run, within 15 minutes, publishes both pins. Until then,--skip tools.atuin(oracfs hold) is the workaround.You are right that
latest/download/URLs will keep drifting: every atuin release repeats this until someone authorizes it. Pinning a versioned release URL would replace that with manual version bumps, which is a maintainer decision and is not changed here.I'm leaving this open until the atuin pin is published.