Require planning before activation replay
This commit is contained in:
+48
-1
@@ -340,6 +340,12 @@ fn hydrate_session(
|
|||||||
record.sequence
|
record.sequence
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if runtime_state != RuntimeState::Planning {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"commitment activation requires planning runtime at sequence {}",
|
||||||
|
record.sequence
|
||||||
|
));
|
||||||
|
}
|
||||||
if record.runtime_state != RuntimeState::Active {
|
if record.runtime_state != RuntimeState::Active {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
"commitment activation runtime mismatch at sequence {}",
|
"commitment activation runtime mismatch at sequence {}",
|
||||||
@@ -951,7 +957,48 @@ mod tests {
|
|||||||
let err = SessionController::new(&path)
|
let err = SessionController::new(&path)
|
||||||
.expect_err("standalone commitment without policy must be rejected");
|
.expect_err("standalone commitment without policy must be rejected");
|
||||||
|
|
||||||
assert!(error_chain_contains(&err, "active policy"));
|
assert!(error_chain_contains(&err, "planning"));
|
||||||
|
fs::remove_file(path).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rejects_commitment_created_before_planning_transition_on_replay() {
|
||||||
|
let path = temp_log_path("commitment-before-planning");
|
||||||
|
let commitment_id = "commitment-test";
|
||||||
|
{
|
||||||
|
let mut log = EventLog::open(&path).unwrap();
|
||||||
|
log.append_batch([
|
||||||
|
PendingEventRecord {
|
||||||
|
event_type: EventType::CommitmentCreated,
|
||||||
|
runtime_state: RuntimeState::Active,
|
||||||
|
commitment_id: Some(commitment_id.to_string()),
|
||||||
|
payload_json: commitment_payload(commitment_id, CommitmentState::Active),
|
||||||
|
},
|
||||||
|
PendingEventRecord {
|
||||||
|
event_type: EventType::RuntimeTransition,
|
||||||
|
runtime_state: RuntimeState::Planning,
|
||||||
|
commitment_id: None,
|
||||||
|
payload_json: json!({
|
||||||
|
"schema_version": POLICY_SCHEMA_VERSION,
|
||||||
|
"action": "enter_planning",
|
||||||
|
"from": "locked",
|
||||||
|
"to": "planning",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
PendingEventRecord {
|
||||||
|
event_type: EventType::PolicyApplied,
|
||||||
|
runtime_state: RuntimeState::Active,
|
||||||
|
commitment_id: Some(commitment_id.to_string()),
|
||||||
|
payload_json: policy_payload(commitment_id),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let err = SessionController::new(&path)
|
||||||
|
.expect_err("commitment activation before planning must be rejected");
|
||||||
|
|
||||||
|
assert!(error_chain_contains(&err, "planning"));
|
||||||
fs::remove_file(path).unwrap();
|
fs::remove_file(path).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user