git-ents.gitmain
⌘K
foforge
policy.rs62 lines · 2.4 KB · rusthistorycomment on this file
1//! Policy loading: the member set, read from `refs/meta/member/*`
2//! through the read half of the ref store (`gate.policy-as-state`).
3//!
4//! The gate consults no state outside `refs/meta/*`: the member set,
5//! each member's current state, and the epoch (`crate::config`) are all
6//! repository state, so any frontend with a clone evaluates the actual
7//! policy offline, staleness bounded only by the age of its last fetch.
8
9use ents_model::{Member, MemberId};
10use gix_hash::ObjectId;
11use gix_object::Find;
12use gix_ref_store::RefStoreRead;
13
14use crate::error::{Error, Result};
15use crate::object::expect_commit;
16
17/// One enrolled member: its id (from the refname) and its ref's tip.
18#[derive(Debug, Clone)]
19pub(crate) struct Enrolled {
20 /// The member id, i.e. the `<id>` of `refs/meta/member/<id>`.
21 pub id: MemberId,
22 /// The member ref's current tip commit.
23 pub tip: ObjectId,
24}
25
26/// Every ref under `refs/meta/member/`, in store order.
27// @relation(gate.policy-as-state, scope=function)
28pub(crate) fn members(refs: &dyn RefStoreRead) -> Result<Vec<Enrolled>> {
29 let mut out = Vec::new();
30 for entry in refs.iter_prefix("refs/meta/member/")? {
31 let (name, tip) = entry?;
32 let path = name.as_bstr().to_string();
33 let id = path
34 .strip_prefix("refs/meta/member/")
35 .unwrap_or(&path)
36 .to_owned();
37 out.push(Enrolled {
38 id: MemberId::new(id),
39 tip,
40 });
41 }
42 Ok(out)
43}
44
45/// The member entity currently in force: the typed tree behind `tip`,
46/// the member ref's tip as read in the same verification snapshot.
47///
48/// Admission consults only this current entity
49/// (`model.member-revocation`): a revoked key's new pushes are refused
50/// from the moment the revocation lands, regardless of any committer
51/// timestamp the pushed commit claims — a backdated commit changes
52/// nothing, because no commit-supplied time participates in the
53/// judgment. Refs accepted before a revocation stay valid because
54/// acceptance is never re-judged; reconstructing what a past acceptance
55/// saw is an audit function over the deployment's out-of-scope op log,
56/// not a gate path.
57// @relation(model.member-revocation, gate.policy-as-state, scope=function)
58pub(crate) fn member_current(objects: &dyn Find, tip: ObjectId) -> Result<Member> {
59 let commit = expect_commit(objects, tip)?;
60 facet_git_tree::deserialize(&commit.tree, objects)
61 .map_err(|source| Error::Entity { oid: tip, source })
62}