diff --git a/docs/src/design/orchestrator/orchestrator-machine.md b/docs/src/design/orchestrator/orchestrator-machine.md index 69c9dfad..d216a964 100644 --- a/docs/src/design/orchestrator/orchestrator-machine.md +++ b/docs/src/design/orchestrator/orchestrator-machine.md @@ -24,7 +24,7 @@ stateDiagram-v2 AwaitingReady --> Recovering : Timeout(id) [id == awaiting]
/ RestoreGoldenImage state SupervisingPlatform { - Ready --> Updating : UpdateRequest
/ AuthenticateUpdate · StageUpdate + Ready --> Updating : UpdateRequest
/ AuthenticateStageUpdate Updating --> Ready : UpdateVerified / ActivateUpdate Updating --> Ready : UpdateRejected / DiscardStaged Ready --> Recovering : CorruptionDetected
/ RestoreGoldenImage @@ -189,7 +189,7 @@ only a fresh `Rot` on `PowerOnReset` releases it. An update is in progress. -**Entry action**: emit `AuthenticateUpdate` + `StageUpdate`. +**Entry action**: emit `AuthenticateStageUpdate`. > **Rejected** here has a specific meaning from the CSA authenticated-update > sequence: the staged candidate failed verification — its signature did not diff --git a/docs/src/design/orchestrator/orchestrator-model.md b/docs/src/design/orchestrator/orchestrator-model.md index 3d39187d..4891825f 100644 --- a/docs/src/design/orchestrator/orchestrator-model.md +++ b/docs/src/design/orchestrator/orchestrator-model.md @@ -419,7 +419,7 @@ policy deployments configure. delivered as `PowerOnResult` in `Event::PowerGood`. - **Attestation** (`AttestationChallenge` / `SignAttestation`): handled in the `SupervisingPlatform` superstate, not part of the boot-time verification chain. -- **Firmware update verification** (`AuthenticateUpdate`): handled in the +- **Firmware update verification** (`AuthenticateStageUpdate`): handled in the `Updating` state, distinct from boot-time chain verification. - **Multiple intermediate boot-progress checkpoints per component**: the CSA architecture allows platform policy to require multiple intermediate diff --git a/services/orchestrator/driver/src/driver.rs b/services/orchestrator/driver/src/driver.rs index 2bb1ffa2..45117543 100644 --- a/services/orchestrator/driver/src/driver.rs +++ b/services/orchestrator/driver/src/driver.rs @@ -110,7 +110,7 @@ impl PlatformDriver { /// The frontend half of the update handshake: record `target` as the /// component the staged candidate is for. Must succeed BEFORE - /// [`Event::UpdateRequest`] is dispatched; `StageUpdate` with no stored + /// [`Event::UpdateRequest`] is dispatched; `AuthenticateStageUpdate` with no stored /// job fails closed. Refuses an unknown id and a second submit while /// one update is in flight; nothing is stored on refusal, so a refused /// request can never surface as an update event. @@ -381,12 +381,11 @@ impl Platform for PlatformDriver { // No board capability is composed for these seams yet, so they // fail closed here instead of behind stub methods. Each group // gains an executor when its capability joins - // [`BoardCapabilities`], as BootControl did above: update - // staging, authentication and trial activation for the update - // quartet; evidence signing for SignAttestation; the terminal - // latch for LatchLockdown. - Effect::AuthenticateUpdate - | Effect::StageUpdate + // [`BoardCapabilities`], as BootControl did above: staging + // plus verification, trial activation and discard for the + // update effects; evidence signing for SignAttestation; the + // terminal latch for LatchLockdown. + Effect::AuthenticateStageUpdate | Effect::ActivateUpdate | Effect::DiscardStaged | Effect::SignAttestation @@ -402,7 +401,7 @@ impl Platform for PlatformDriver { /// The connection between an update frontend and the SM: called (by the /// event loop, on the frontend's behalf) once a complete candidate for /// `target` sits in the staging region. Records the job first, then injects -/// [`Event::UpdateRequest`]; that order is load-bearing, `StageUpdate` can +/// [`Event::UpdateRequest`]; that order is load-bearing, `AuthenticateStageUpdate` can /// never run without a target. On refusal no event is injected and the /// frontend answers the requester over its own protocol. pub fn request_update( diff --git a/services/orchestrator/driver/src/tests.rs b/services/orchestrator/driver/src/tests.rs index a443cc3e..f49c9165 100644 --- a/services/orchestrator/driver/src/tests.rs +++ b/services/orchestrator/driver/src/tests.rs @@ -1315,7 +1315,7 @@ fn submit_update_refuses_a_second_in_flight() { // The frontend connection end to end: request_update records the job and // the SM receives UpdateRequest. Ready accepts it and enters Updating, -// whose entry effects (AuthenticateUpdate, StageUpdate) have no executors +// whose entry effect (AuthenticateStageUpdate) has no executor // yet, so the machine latches Locked — that latch is the proof the event // arrived. Flips to an Updating/Ready assertion when the pump lands. #[test] diff --git a/services/orchestrator/sm/src/lib.rs b/services/orchestrator/sm/src/lib.rs index 53abfa8b..5ed572e2 100644 --- a/services/orchestrator/sm/src/lib.rs +++ b/services/orchestrator/sm/src/lib.rs @@ -978,8 +978,7 @@ impl Rot { // A new update supersedes any activated-but-not-committed image; // the prior commit window is void. self.pending_commit = false; - ctx.emit(Effect::AuthenticateUpdate); - ctx.emit(Effect::StageUpdate); + ctx.emit(Effect::AuthenticateStageUpdate); } State::Recovering(failed) => { // Recovery voids any activated-but-not-committed image: the diff --git a/services/orchestrator/sm/src/model.rs b/services/orchestrator/sm/src/model.rs index a7774bdc..5e67e3b8 100644 --- a/services/orchestrator/sm/src/model.rs +++ b/services/orchestrator/sm/src/model.rs @@ -337,8 +337,9 @@ pub enum Effect { /// component is gated without triggering (or continuing) a recovery cycle. AssertReset(ComponentId), SignAttestation, - AuthenticateUpdate, - StageUpdate, + /// Stage the candidate, then verify it. The driver knows the protocol + /// order; the SM does not split these into sub-phases. + AuthenticateStageUpdate, ActivateUpdate, DiscardStaged, /// Advance the anti-rollback (SVN) floor past `id`'s now-confirmed image. diff --git a/services/orchestrator/sm/src/tests.rs b/services/orchestrator/sm/src/tests.rs index 17a1d585..88d1b7b7 100644 --- a/services/orchestrator/sm/src/tests.rs +++ b/services/orchestrator/sm/src/tests.rs @@ -156,14 +156,10 @@ fn update_rollback_is_not_recovery() { Event::UpdateRejected, ], ); - let tail = &effects[effects.len() - 3..]; + let tail = &effects[effects.len() - 2..]; assert_eq!( tail, - &[ - Effect::AuthenticateUpdate, - Effect::StageUpdate, - Effect::DiscardStaged - ], + &[Effect::AuthenticateStageUpdate, Effect::DiscardStaged], ); assert_eq!(state, State::Ready); assert!(!effects.contains(&Effect::LatchLockdown)); @@ -2465,7 +2461,7 @@ fn corruption_during_update_discards_staged() { BOOT, Event::VerificationPassed(C0), Event::VerificationPassed(C1), // → Ready - Event::UpdateRequest, // → Updating (AuthenticateUpdate, StageUpdate) + Event::UpdateRequest, // → Updating (AuthenticateStageUpdate) Event::CorruptionDetected(C1), // Required corruption preempts the update ], );