fix(os-update): version floor + data-migration rollback guard - #863
Merged
Conversation
This was referenced Aug 3, 2026
A correctly-signed OS bundle is not automatically a safe one. Two gaps: - os-update had no version floor: a signed OLDER bundle installed, health-passed, and committed — a signed downgrade that re-opens the holes the newer image fixed, under our own valid signature. - The migration-deadlock rule was unimplemented: no manifest compatibility fields, so a forward-only /data migration left no record and a later rollback could strand the migrated chain data. Stamp version + data_migration + minimum_os_version into the bundle manifest's [meta.pithead] section (validated up front in mkbundle.sh, before the multi-minute image build). os-update reads them back and: - installs without --allow-downgrade ONLY a clean X.Y.Z release at or newer than the running OS. Both guards fail CLOSED: an older bundle, a pre-release/-prep version, garbage, or an absent stamp is not proof of safety, so it refuses rather than silently skipping the check. - records a /data migration floor when a data_migration bundle installs, and refuses any later rollback below it outright (no override). A corrupt floor file, or a bundle whose version can't be parsed, also refuses — a floor that exists is authoritative. semver_newer only understands clean X.Y.Z, so os_semver_ok gates every comparison; a version it can't parse never reaches the buggy path. Executing the forward-only migration itself, and withholding chain services until the slot commits (the automatic-fallback half of the deadlock rule), remain scoped follow-up — documented in appliance-release.md and appliance-wizard.md. The manual-rollback guard is real, tested, and armed now. Closes #856 Refs #851 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
VijitSingh97
force-pushed
the
fix/851-856-update-safety
branch
from
August 3, 2026 01:46
94533ac to
59a163a
Compare
Collaborator
Author
|
Adversarial-review round (force-pushed, amended into the single commit):
Tests added: a |
This was referenced Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Two related update-safety gaps, one shared manifest mechanism.
#856 — signed downgrade.
pithead os-updatehad no version floor: anycorrectly-signed older bundle installed, health-passed, and committed — a
signed downgrade that re-opens the holes the newer image fixed, under our own
valid signature, so no signature check catches it.
#851 — migration-deadlock rule. The
data_migration/minimum_os_versionmanifest compatibility fields were unimplemented (
dual-distribution-plan.mdrisk #6). A forward-only
/data(lmdb) migration left no record, so a laterrollback could strand the migrated chain data on an OS that can no longer read it.
Change
The bundle manifest's
[meta.pithead]section grows the channel contract,validated up front in
mkbundle.sh(before the multi-minute image build):versionVERSION)data_migrationtrueif this release runs a forward-only/datamigrationminimum_os_version/dataonce it has migratedos-updatereads them back and:--allow-downgrade(os-update has no version floor: a signed older bundle installs and commits (downgrade attack), minimum_os_version unimplemented #856);/datamigration floor when adata_migrationbundle installs, andrefuses any later rollback below it outright —
--allow-downgradedoes notoverride it, because the migrated chain data is unreadable there (Appliance: migration-deadlock rule (data_migration flag) and manifest compatibility fields not implemented #851).
Deliberate A/B rollback (
rauc status mark-bad booted) is unaffected — it bootsthe spare slot already present, it does not re-install an old bundle.
Scoped follow-up (explicit)
Recording and enforcing the floor is done and tested. Executing the
forward-only migration, and withholding chain services (monerod/tari) until the
slot commits — the automatic-fallback half of the deadlock rule — remain scoped
follow-up, documented in
appliance-release.mdandappliance-wizard.md. Untilthat boot-path change lands, the guard here prevents the manual rollback path
from stranding data; the automatic-fallback ordering is bench/tier-4 work
(
tests/os/run.sh --phase update). The plan'sdb_schemafield lands with thatrunner — nothing reads it yet.
Tests
tests/stack/run.sh:os_bundle_metaparsing of all three fields; the downgraderefusal +
--allow-downgradeoverride; the below-floor hard refusal (nooverride); the floor being recorded on a
data_migrationinstall and not on aplain one;
mkbundle.sh's fail-fast metadata validation. Full suite: 1996passed, 0 failed.
make lintgreen (shellcheck, shfmt, docs-voice, operator-strings).Closes #856
Refs #851 — the safety guard + manifest fields are done and tested here; the
migration runner and the automatic-fallback boot ordering are scoped follow-up,
so this deliberately does not auto-close #851.
🤖 Generated with Claude Code