operations
Update and rollback
Update and rollback
What this guide does
Walk through the update and rollback flow on deputyOS: what deputyctl update --check and deputyctl update --apply do today, what deputyctl rollback does today, what is not yet shipped (the actual A/B
slot swap and watchdog auto-rollback), and how make verify lets you
rebuild a published release locally and SHA-compare against the
signed manifest.
The update trust chain is detailed in Security → Update trust chain; this page is the operator-facing flow.
The update flow
deputyctl update --check
sudo deputyctl update --check
sudo deputyctl update --check --json
Performs:
- Read the update URL from
/etc/deputyos/update-url(orDEPUTYOS_UPDATE_URLenv override; or dev fallback tofile://<repo>/dist/manifest.json). - Fetch
manifest.jsonandmanifest.json.minisigto a tmp dir. - Verify the minisign signature against
/etc/deputyos/pubkey.minisign. Hard fail on mismatch. - Parse the manifest. Refuse if
schema_version != 1. - Compare
release_versionto the contents of/etc/deputyos/version(the running image’s version). - If newer, find the artefact entry matching this device’s
(target, profile)pair. - Print:
info: update available: <version>plus the artefact’s sha256 and signed URL.
--json emits the same content as a structured object suitable for
piping to jq.
deputyctl update --apply
sudo deputyctl update --apply --yes
Performs everything --check does, plus:
-
Download the artefact to
/var/lib/deputyos/staging/<filename>. -
SHA-256 verify against the manifest entry. Hard fail on mismatch (delete the partial download).
-
Verify the artefact’s detached
.minisigagainst the manifest’s declared signature URL. (Belt-and-braces: the manifest itself is signed, but per-artefact sigs let independent verifiers confirm any one image without parsing the manifest.) -
Fire the
update-appliedhook with payload:{"kind":"update-applied", "staged_at":"/var/lib/deputyos/staging/<filename>", "filename":"<filename>","sha256":"<hex>","release_version":"Y.M.D"} -
Print:
info: staged at <path>; A/B swap on next boot is not yet enabled.
Not yet shipped Today,
--applyends at “staged.” The actual slot swap requires bootloader plumbing (tryboot on Pi 5, U-Boot bootcount on Pi 4, GRUB swap on x86) that is still in development. The hook does fire on the staging step so admin tooling can refresh dashboards eagerly — the staged artefact is the proof an update is ready, even if the swap hasn’t happened.
deputyctl rollback
sudo deputyctl rollback
The contract today (per deputyctl/src/rollback.rs):
- Identify the inactive A/B slot.
- Validate its integrity — sha256 against the manifest that produced it, plus an “is the unit file there” probe.
- Refuse to swap with a clear “not yet enabled” message and a non-zero exit.
The validation step proves the rollback path is wired and the inactive
slot is intact. The actual reboot --bootloader-set inactive-slot
is still in development.
make verify — local reproducibility
make verify VERSION=2026.4.27 TARGET=qemu-aarch64 PROFILE=openclaw
Performs:
- Read
dist/manifest.json(orDEPUTYOS_UPDATE_URL). - Find the artefact for
(VERSION, TARGET, PROFILE). - Run
make build TARGET=$TARGET PROFILE=$PROFILEto rebuild the image locally with the same hermetic-build invariants. - SHA-256 the rebuilt artefact.
- Compare to the manifest’s published sha256.
Set DEPUTYOS_VERIFY_STRICT=1 to make a mismatch fatal (default:
warning, exit 0). The non-strict default exists so contributors with
slightly different host toolchains can see “yes, this rebuilds, but
the bytes diverge here” rather than a hard fail — which is the right
shape until fully reproducible builds land.
The bigger story (SLSA L3 attestation) is in Security → Update trust chain.
Watchdog auto-rollback
Not yet shipped. The plan: a systemd watchdog on the active
profile’s gateway that, on N consecutive crashes within a window,
flips the boot-slot pointer to the inactive slot and reboots. The
inactive-slot validity check from deputyctl rollback is the
foundation; the watchdog plumbing is the remaining piece.
For now, manual rollback (once it ships) plus deputyctl doctor in a
systemd timer is the substitute. A timer-driven deputyctl doctor
exit-non-zero plus an alert hook gives you the same “something is
broken, page someone” signal without auto-recovery.
Failure modes
| Failure | Where | Recovery |
|---|---|---|
| Manifest signature invalid | update --check | Refuses, exit 2. Don’t override; investigate the signing key path. |
| Artefact sha256 mismatch | update --apply | Refuses, deletes partial. Rerun — likely transient CDN. |
Artefact .minisig invalid | update --apply | Refuses. Same as above. |
| Network down | update --check | Reports DNS / connect timeout. Retry when network returns. |
Missing artefact for (target, profile) | update --check | Reports “no artefact in manifest for this device.” Indicates a broken release. |
| Disk full at staging | update --apply | Reports ENOSPC. Free space, retry. |
update-applied hook script fails | post-staging | Logs; staging is already complete. Hook failures don’t roll back staging. |
Verification
# Doc-driven local loop
make publish-local # mirror dist/ for file:// CDN
sudo deputyctl update --check # should detect the local mirror
sudo deputyctl update --apply --yes # stages
ls /var/lib/deputyos/staging/ # verify
sudo deputyctl rollback # validates inactive, refuses the swap
Troubleshooting
update --checksays ‘no update’ but the manifest has a newer version Comparecat /etc/deputyos/versionto the manifest’srelease_version. The on-disk version is what the bake wrote; if they’re equal, you’re already on the latest. If they differ, look for cached manifest data andrm -rf /var/lib/deputyos/staging/*before retrying.
update --applysucceeds but next reboot doesn’t pick up the new image Expected today. The staged artefact is in/var/lib/deputyos/staging/; the bootloader still points at the old slot. The automatic swap is still in development.
Bypassing signature verification Don’t. The trust chain is the only thing that prevents a compromised CDN from delivering a malicious image. There is no
--forceflag, by design. If you have a release-key incident, rotate the pubkey baked at/etc/deputyos/pubkey.minisignand re-bake the appliance image. See Security → Update trust chain.
Use
make verifybefore pulling an update onto production On a separate test rig, runmake verify VERSION=<v> TARGET=<hw>before any production roll. Even withDEPUTYOS_VERIFY_STRICT=1, you get a fast “yes, this rebuilds bit-identically” signal.
Related
- Reference → CLI → deputyctl (
update,rollbacksubcommands) - Reference → Schemas → release manifest
- Reference → Schemas → hook payloads (the
update-appliedschema) - Security → Update trust chain
- Build → Make targets (the
manifest/publish-local/verifytargets)