made_core/entities/ceremony_instance/
guard_decisions.rs1use super::{
2 AuditActorKind, CeremonyDefinition, CeremonyGuardApproval, CeremonyGuardDeferral,
3 CeremonyGuardDeferralContent, CeremonyInstance, DomainError, GuardCondition, GuardName,
4 OffsetDateTime, RoleId,
5};
6
7impl CeremonyInstance {
8 pub fn approve_guard(
17 &mut self,
18 definition: &CeremonyDefinition,
19 guard_name: &GuardName,
20 approved_by: RoleId,
21 approved_by_kind: AuditActorKind,
22 now: OffsetDateTime,
23 ) -> Result<(), DomainError> {
24 self.require_active(
25 definition,
26 "terminal ceremony instances cannot approve guards",
27 )?;
28 let guard = definition
29 .guards()
30 .get(guard_name)
31 .ok_or(DomainError::NotFound {
32 what: "ceremony_guard",
33 })?;
34 if !matches!(guard.condition(), GuardCondition::HumanApproval) {
35 return Err(DomainError::InvariantViolated {
36 reason: "only human approval guards can be approved",
37 });
38 }
39 self.require_declared_role(definition, &approved_by)?;
40 self.context = self.context.clone().with_guard_approval(guard_name)?;
41 self.guard_approvals.push(CeremonyGuardApproval::record(
42 guard_name.clone(),
43 approved_by,
44 approved_by_kind,
45 now,
46 ));
47 self.updated_at = now;
48 Ok(())
49 }
50
51 pub fn defer_guard(
52 &mut self,
53 definition: &CeremonyDefinition,
54 guard_name: GuardName,
55 content: CeremonyGuardDeferralContent,
56 deferred_by: RoleId,
57 deferred_by_kind: AuditActorKind,
58 now: OffsetDateTime,
59 ) -> Result<(), DomainError> {
60 self.require_active(
61 definition,
62 "terminal ceremony instances cannot defer guard decisions",
63 )?;
64 let guard = definition
65 .guards()
66 .get(&guard_name)
67 .ok_or(DomainError::NotFound {
68 what: "ceremony_guard",
69 })?;
70 if !matches!(guard.condition(), GuardCondition::HumanApproval) {
71 return Err(DomainError::InvariantViolated {
72 reason: "only human approval guards can be deferred",
73 });
74 }
75 if self.context.is_guard_approved(&guard_name) {
76 return Err(DomainError::InvariantViolated {
77 reason: "approved human guards cannot be deferred",
78 });
79 }
80 let is_currently_required = definition
81 .available_transitions(&self.current_state)
82 .any(|transition| transition.required_guards().contains(&guard_name));
83 if !is_currently_required {
84 return Err(DomainError::InvariantViolated {
85 reason: "human guard is not required from the current state",
86 });
87 }
88
89 self.require_declared_role(definition, &deferred_by)?;
90 self.guard_deferrals.push(CeremonyGuardDeferral::record(
91 guard_name,
92 deferred_by,
93 deferred_by_kind,
94 content,
95 now,
96 ));
97 self.updated_at = now;
98 Ok(())
99 }
100}