clawft_kernel/licence/
store_accept.rs1use super::store::{CheckoutGrantStore, Held};
7use super::{
8 AdmissionPosture, BindState, BindingExtraCheck, CheckoutGrant, GRANT_SKEW_SECS, LicenceError,
9 LicenceEvent, MAX_GRANT_SLOTS, Outcome, SignedBinding, SignedGrant, verify_binding_member,
10 verify_grant,
11};
12use crate::workload_pkg::codec::hex_decode_exact;
13
14impl CheckoutGrantStore {
15 pub fn accept_binding(
18 &self,
19 signed: &SignedBinding,
20 posture: AdmissionPosture,
21 extra: &dyn BindingExtraCheck,
22 ) -> Result<Outcome, LicenceError> {
23 self.run(|inner, ev| {
24 if let Some(p) = &inner.poisoned {
25 return Err(LicenceError::Poisoned(p.clone()));
26 }
27 if let Err(e) = posture.check() {
28 ev.push(LicenceEvent::BindingRefused(e.to_string()));
29 return Err(e);
30 }
31 let local = self.local.get().ok_or(LicenceError::NoLocalMesh)?;
32 let rec = verify_binding_member(signed, &self.anchors, &local)?;
33 extra.check(&rec)?;
34 let mut next = inner.clone();
35 if let Some(cur) = &inner.binding {
36 if rec.seq < cur.body.seq {
37 return Ok(Outcome::Ignored);
38 }
39 if rec.seq == cur.body.seq {
40 if cur.signed.payload == signed.payload {
41 return Ok(Outcome::Duplicate);
42 }
43 ev.push(LicenceEvent::BindingConflict(rec.seq));
44 return Err(LicenceError::Conflict(rec.seq));
45 }
46 if cur.body.grant_pubkey != rec.grant_pubkey {
47 next.slots.clear(); }
49 }
50 let key = rec.grant_pubkey.clone();
51 next.floors.retain(|k, _| *k == key); let restrictive = rec.state == BindState::Unbound;
53 next.binding = Some(Held { signed: signed.clone(), body: rec });
54 next.orphan_reported = false;
55 if restrictive {
56 return Ok(self.commit_restrictive(inner, next));
57 }
58 self.commit(inner, next)?;
59 self.note_bound();
60 Ok(Outcome::Applied)
61 })
62 }
63
64 pub fn accept_grant(&self, signed: &SignedGrant) -> Result<Outcome, LicenceError> {
66 self.run(|inner, ev| {
67 let b = self.binding_in_effect(inner, ev)?;
68 let pk = hex_decode_exact::<32>(&b.grant_pubkey)
69 .ok_or_else(|| LicenceError::Malformed("bound grant key".into()))?;
70 if self.key_revoked(&b.grant_pubkey) {
71 return Err(LicenceError::KeyRevoked);
72 }
73 let local = self.local.get().ok_or(LicenceError::NoLocalMesh)?;
74 let g = verify_grant(signed, &pk, &local)?;
75 let eff = self.eff_now(inner, &b.grant_pubkey);
76 if g.issued_at > eff.saturating_add(GRANT_SKEW_SECS) {
77 return Err(LicenceError::NotYetValid);
78 }
79 let key = (g.cog_id.clone(), g.version.clone());
80 if !inner.slots.contains_key(&key) && inner.slots.len() >= MAX_GRANT_SLOTS {
81 return Err(LicenceError::Full);
82 }
83 let held = Held { signed: signed.clone(), body: g };
84 let seq = held.body.seq;
85 let (cur, conflicted) = match inner.slots.get(&key) {
86 Some(s) => (s.current.clone(), s.conflicted.contains(&seq)),
87 None => (None, false),
88 };
89 if conflicted {
90 return Err(LicenceError::Conflict(seq));
91 }
92 let mut next = inner.clone();
93 if let Some(cur) = &cur {
94 if seq < cur.body.seq {
95 return Ok(Outcome::Ignored);
96 }
97 if seq == cur.body.seq {
98 if cur.signed.payload == held.signed.payload {
99 return Ok(Outcome::Duplicate);
100 }
101 let wd = [cur, &held].into_iter().find(|h| h.body.is_withdrawal()).cloned();
105 let slot = next.slots.entry(key).or_default();
106 slot.conflicted.push(seq);
107 match wd {
108 Some(w) => {
109 slot.current = Some(w);
110 slot.previous = None;
111 }
112 None => slot.current = slot.previous.take(),
113 }
114 ev.push(LicenceEvent::GrantConflict {
115 cog_id: held.body.cog_id,
116 version: held.body.version,
117 seq,
118 });
119 let _ = self.commit_restrictive(inner, next);
120 return Err(LicenceError::Conflict(seq));
121 }
122 check_union(&cur.body, &held.body)?;
123 }
124 let issued = held.body.issued_at;
125 let restrictive = held.body.is_withdrawal();
126 let slot = next.slots.entry(key).or_default();
127 slot.previous = slot.current.take();
128 slot.current = Some(held);
129 next.floors.entry(b.grant_pubkey).or_default().note_issued(issued);
130 if restrictive {
131 return Ok(self.commit_restrictive(inner, next));
132 }
133 self.commit(inner, next)?;
134 Ok(Outcome::Applied)
135 })
136 }
137}
138
139fn check_union(cur: &CheckoutGrant, new: &CheckoutGrant) -> Result<(), LicenceError> {
141 for a in &cur.artifacts {
142 match new.artifact(&a.arch) {
143 None => return Err(LicenceError::DropsArch(a.arch.clone())),
144 Some(n) if n != a => return Err(LicenceError::ChangesArtifact(a.arch.clone())),
145 Some(_) => {}
146 }
147 }
148 Ok(())
149}