ReviewOS

stacks/drone

Runtime updates: persist trust state and coordinate known-good slots

#42
Open chris opened this 9 days ago ·
9 days ago

Goal

Complete the persistent software update coordinator required by #9, building on the offline TUF image-verification module in #41. A verified candidate is an input to this work, not installed firmware or a selected boot slot.

Required behavior

  • Enroll an independently authenticated root/platform policy and trusted release floor into protected local state. Record versions and integrity without taking trust from candidate receipts. Define key replacement/revocation and trusted-clock requirements explicitly.
  • Persist TUF root/timestamp/snapshot/targets high-water state and the release security floor across process restarts. Preserve verified metadata advancement even if a later refresh, compatibility, target-download or staging phase fails. The pinned SDK currently writes its private cache in place; copying a successful candidate or resetting a failed cache is insufficient. Design and test this persistence seam before treating it as anti-rollback.
  • Coordinate exclusive installed/candidate/known-good slots with authenticated image bytes and explicit state transitions. Keep the previous known-good slot until a new boot has passed health confirmation bound to the exact candidate and boot/session identity. Receipt existence and a caller-supplied healthy boolean alone cannot authorize selection.
  • Recover interrupted staging, selection and confirmation without inventing success, discarding security floors or overwriting the only known-good image. Rollback must obey current trust/security policy; corrupt/expired/unavailable rollback images fail closed with an actionable state.
  • Use native Stacks CLI/persistence where appropriate and keep the domain functions under resources/functions/drone/. Preserve independent control/RC authority and disabled physical deployment. Do not add flashing/arming/actuator endpoints as a shortcut.

Failure and evidence acceptance

  • Real signed repositories cover valid update, sequential root rotation, role/version replay, frozen/expired metadata, wrong platform/protocol, release downgrade, rejected images after valid metadata advancement, revocation and revoked known-good rollback.
  • Actual host process interruption/restart campaigns cover each state transition and verified-prefix recovery. Faults cover short/zero writes, ENOSPC/EDQUOT/EIO, sync failure, corrupt/missing state, missing slots and concurrent writers. Preserve original failures and distinguish process-crash behavior from unmeasured physical power loss.
  • Native Buddy and compiled standalone commands use the same coordinator and preserve rejection/status semantics outside the checkout. Types, Pickier, full native tests and exact-commit CI pass.
  • The signed-stage module is integrated rather than bypassed. No protected metadata or release floor can silently decrease. No incomplete candidate is reported as installed/confirmed.
  • Document the state schema, threat model, trust/key lifecycle, recovery procedures and remaining board gates. Show which assertions concern host files versus actual boot behavior. Commissioning remains blocked until #9 and its hardware dependencies supply measured evidence.

Parent scope and dependencies

Refs #9 and #41. This is a host-software dependency of the full update/rollback requirement, not a redefinition of #9 as a staging-only task. Actual board image format/build attestation, bootloader/install protocol, electrical removal/power-loss/full-medium recovery and hardware anti-rollback/commissioning still need explicit implementation and measured evidence under #2/#9. Avoid irreversible provisioning or changes to independent authority while developing the host coordinator.

Current implementation status

The five acceptance groups above remain unchecked. The host coordinator has substantial implemented behavior, but #42 is not complete and physical deployment remains disabled.

SurfaceCurrent evidence and limits
Independent enrollment and persistent trustImmutable independently pinned enrollment; journaled verified TUF metadata, metadata epochs and release/clock floors; historical prefix recovery. The original anchor is separate from writable SDK caches.
Signed image ownershipProtected preparation authenticates actual bytes and records exclusive candidate identities, integrity and retained retirement history. A marker alone grants no boot authority.
Owned host slots#54, published at 7e6a7565ff760ed4db46d04596ddcb9839876249, adds format-3 host roles, exact signed-image/build equality, 214-input health bound to owned boot/session challenges, clean actual process exit, fresh-policy rollback and exact interrupted-trial abandonment after metadata recovery. Older known-good images and security floors are retained.
Native and standalone toolingBuddy and compiled standalone commands share the same coordinator. The Stacks bounded-process helper was contributed to framework main at 3c52a79013df2e8026e4b364dfb9589eaf11375c. Drone's explicit byte-identical source bridge is pinned because installed CLI 0.75.221 lacks that export.
Actual partial file writes#57, head b809edd4b0d53f670bb8b8e5d956496db221242c, uses a real read-back process-local file limit. An authenticated image copy retains its actual 1 MiB prefix and fails with EFBIG, preserving accepted root 2, targets 3, release floor 9 and previous known-good bytes. Recovery and fresh health run in new processes. Published to origin/main by normal fast-forward as Chris without coauthor trailers after CI 39729241490 passed all five jobs, including both actual Linux executions and the full native suite. Terminal log retained once: 3,019,951 bytes, SHA-256 e2c0ea9501910a68bac101bd160c27d16edd757869fc881c65a58bca3af0ad2d. This is not ENOSPC evidence.
Actual full filesystem#58, current head 7b120baf4a40e904710aa804bbc54f4cc64f64ea, adds an opt-in private Linux tmpfs campaign for real ENOSPC, failed SQLite persistence and explicit recovery/abandonment/fresh trial. The first Linux run at parent 6386c6e passed, and independent archive readback verified 62 file hashes, public states, actual ENOSPC plus two SQLITE_FULL errors, the 1 MiB authenticated prefix and fresh health. A stats/manifest filename collision was then corrected. The corrected-head Linux case passed; separate archive readback verified distinct zero-free-space statistics, all 62 file hashes and retained/fresh public states. The exact-head CI 39731192997 passed all five jobs. Published to origin/main at 7b120baf4a40e904710aa804bbc54f4cc64f64ea by normal fast-forward as Chris without coauthor trailers. Retained terminal log: 3,027,959 bytes, SHA-256 e19fc1f0f23e8ebbfcfd6e62557fcfe016d11ece410c8d3aa59d60428cce34a5. A local skip is unqualified.
Explicit maintenance continuation#59, published at 1e4622898c863d8ee57b5010c467bfc0c5606f0e, adds format-4 atomic predecessor/successor handoffs. Exact active attempt, independent pins, explicit unresolved-input acknowledgement and trusted current clock are required. Original phases and inputs remain unresolved and retained; every accepted root/epoch/release/clock floor is preserved. Fresh verification still requires existing signed root continuity. All five exact-head CI jobs passed, including the full Linux Buddy suite (1,498 pass, 0 fail), both actual three-cut campaigns and copied CLI. Downloaded archives independently verify retained input/metadata hashes and distinct boot IDs. Both independent reviews found no actionable defects. Corrupt handoff/budget boundaries and in-commit storage failures still need targeted qualification; lost-root reanchoring and clock-floor reduction are unsupported.
Zero-byte copy recovery, published Linux qualification#61, corrected head 02dcbc082dd70183362983d4cbebc97eee9f8535, adds separate zero-free-byte and 1 MiB-free tmpfs campaigns. Both actual Linux cases pass. Independent archive readback verifies 124 file hashes, exact empty/partial files, actual ENOSPC and two SQLITE_FULL errors per case, retained old known-good bytes and root 2/targets 3/release floor 9, explicit fresh-process recovery/abandonment and distinct fresh boot/session health. The initial fixture incorrectly expected mismatch for an empty file; both reviews and the original failed Linux archive established the existing public unavailable semantics. Original failure is retained, and the fixture is corrected. Both final reviews find no actionable defects. All five exact-head jobs pass in CI 39802940081. Published to origin/main at 02dcbc082dd70183362983d4cbebc97eee9f8535 by normal fast-forward as Chris without coauthors. The retained terminal log is 3,039,589 bytes, SHA-256 9f6f4ff88b0c7cb01abff7774a3a1de8ec665d4a4aa2526a80b05b18e26d97ff. This does not qualify a write syscall returning zero without an error or physical-media durability.

Published host-slot CI 39720949558 passed all five jobs, including the full native suite, actual Linux full-input-pipe regression, copied CLI campaign, both browser jobs, firmware cross-build and purge namespace qualification. The full terminal log was collected once: 3,033,252 bytes, SHA-256 1d4e6250f356fe1de1a647e04c967aa5bf0f7c3b77767fc513f1fe3bace5f3b3.

The original local full-suite run remains a failure: 1,502 passed, 25 skipped and three failed. Its raw log is retained (427,362 bytes, SHA-256 6d884c7966f217c823a20cc439b8636035c99b160b648ea6e92ced5e5e29ab7c). The reproduced retention-setup throughput assumption in #36 was corrected by tests-only #55, published after all five exact-head jobs passed. #52 and #53 retain their unresolved causes. Published #56 adds lifecycle observations for future purge-fixture failures; it is not a causal fix for #53. Later passing CI does not rewrite that original local result.

Remaining implementation and qualification

  • Authenticated key maintenance, revocation/repair procedures and trusted clock acquisition/repair, with retained security history and explicit authorization. Existing clock-source labels are audit labels, not time attestations.
  • Finish the complete storage-fault matrix, including zero-progress writes, ENOSPC, EDQUOT, EIO, sync failures, corrupt/missing state and every interruption boundary. Process-local EFBIG and memory-backed filesystem exhaustion do not establish persistent-media or electrical power-loss durability.
  • Finish rejection/recovery and fresh-policy rollback coverage for every revocation/expiry/corruption case. Preserve the only known-good image and all committed security floors.
  • Qualify exact Buddy and copied standalone semantics with full native tests, types, Pickier and all applicable CI jobs on the final source. Keep remaining or failed observations visible.
  • Implement and measure actual board image/build attestation, bootloader/install protocol, persistent boot selection, hardware anti-rollback, storage timing and power-loss/recovery behavior under #2/#9. Host virtual-clock health and a Pico cross-build do not satisfy these gates. Independent FC/RC authority remains intact.

The later Mac full Buddy run on 1e4622898c863d8ee57b5010c467bfc0c5606f0e stopped without a terminal receipt after execution-lifetime failures and explicit disk exhaustion. It is not a full pass. Original raw log SHA-256: 6f6c45a60fcfa501835919dbf0f47490ff68f25490ba4425e3bf8d05d0f5caf6. Both unchanged focused lifetime cases subsequently pass at their original limits; the cause remains unresolved in #60. No acceptance group above is marked complete by the Linux result alone.

Sign in to comment on this issue.