Skip to content

Prove the updater on a booted box in CI: real update and real revert in the cloud-image lane #382

Description

@onel

Size

M

Area

tooling

Depends on

#386

Summary

Prove the control-plane updater on a booted box, in CI rather than on a maintainer's machine. Everything below it — the ledger, the transaction, the trigger — is proven against a fake Docker, which is precisely the gap docs/progress/control-plane-update-transaction.md and control-plane-update-trigger.md both name. The update path has never met a real Docker daemon, a real registry, a real brain restart, or a real revert.

This issue was rewritten. It originally proposed extending the local QEMU medium lane (sudo -E ./dev/test-qemu/run-medium-tests.sh). That was written believing QEMU needed a privileged local runner. It does not: .github/workflows/ci-cloud-image.yml already runs QEMU boot proofs on stock ubuntu-24.04 GitHub-hosted runners — it installs qemu-system-x86 + ovmf, uses /dev/kvm when the runner exposes it and falls back to TCG when it does not, and runs four boots (unseeded seeded bios access) via make test-cloud-qemu. The update proof belongs there, beside the others.

Spec / source of truth

docs/specs/UPDATES.md # 3 (apply + rollback) and # 8.4; docs/specs/TESTING.md; docs/dev/hosted-boot-proof.md

Do

Add an update boot scenario to the existing cloud lane, alongside unseeded / seeded / bios / access:

  • dev/cloud/cloud-assertions.sh — the in-guest assertions (it already switches on the boot name).
  • dev/cloud/run-cloud-tests.sh — the driver (BOOTS, default list on line ~91).
  • .github/workflows/ci-cloud-image.yml — add it to MALMO_CLOUD_BOOTS on the boot-test step.

Assert the happy path. Drive a real update through the real trigger — POST /api/v1/system/update on the running brain, the endpoint #386 shipped — and assert: both containers recreated on the new refs, images.json and the staged compose both naming the new pair, the brain answering /healthz on the new image, and GET /api/v1/system/version reporting it. The brain recreating itself through host-agent is the single riskiest step in the whole design and has never once run.

Assert the revert. Point an update at a brain image that fails its health check, then assert both images and the SQLite snapshot are restored and the box is serving again on the old pair. The revert is the half that only matters once something has already gone wrong, so it is the half most worth exercising for real.

Give the guest something to pull from. The lane is air-gapped by design, so a real pull-by-digest needs a registry inside the guest. Test-only scaffolding must not land in the production image — that image is what gets published, and make build-cloud-image runs a lean check over it. If a real in-guest registry proves too expensive, a docker load + retag still proves recreate/revert/snapshot-restore but does not prove pull-by-digest; that is an acceptable fallback only if the limitation is stated plainly in the progress entry rather than glossed over.

Touch

dev/cloud/, .github/workflows/ci-cloud-image.yml, docs/dev/hosted-boot-proof.md, docs/progress/

Done when

gh workflow run "CI / Cloud image" --ref <branch> -f publish=false performs a real update and a real failed-update-then-revert inside the VM, both asserted, and a red result is diagnosable from the serial log without attaching a debugger. The run publishes nothing.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions