Skip to main content

gonzalo_domain/fleet/
mod.rs

1//! Fleet access-control records: people, the external accounts bound to them,
2//! role grants, per-channel configuration, one-time link tokens, and the audit
3//! trail. See ADR 0022, amended for channel configuration by ADR 0023. One-time
4//! link tokens store only a hash of their secret.
5//!
6//! These are typed views only. gonzalo stores the records but never evaluates
7//! the roles in them; consumers such as Ariel read them and decide, including
8//! the two-key rule `effective = min(person_role, channel_ceiling)`. A person is
9//! never resolved by email or handle, so nothing here offers that lookup.
10
11mod atomic;
12mod audit;
13mod keys;
14mod link;
15mod records;
16
17pub use audit::{AuditEntry, AuditResult};
18pub use keys::FleetKeyError;
19pub use link::{Consumption, LinkSecret, LinkSecretError, LinkToken, RedeemError};
20pub use records::{
21    BindingOrigin, ChannelConfig, EmptyFollowSet, Follows, IdentityBinding, NotifyPreset, Person,
22    RoleGrant, VerifiedEmail,
23};
24
25use serde::{Deserialize, Serialize};
26
27/// Namespace for people, bindings, grants, channel configs and link tokens.
28pub const FLEET_NAMESPACE: &str = "fleet";
29/// Namespace for audit entries, kept apart so daemon auth (ADR 0015) can scope
30/// audit access separately.
31pub const FLEET_AUDIT_NAMESPACE: &str = "fleet-audit";
32pub const PEOPLE_COLLECTION: &str = "people";
33pub const IDENTITY_BINDINGS_COLLECTION: &str = "identity-bindings";
34pub const ROLE_GRANTS_COLLECTION: &str = "role-grants";
35pub const CHANNELS_COLLECTION: &str = "channels";
36pub const LINK_TOKENS_COLLECTION: &str = "link-tokens";
37pub const AUDIT_ENTRIES_COLLECTION: &str = "entries";
38
39/// A fleet role, ordered `Viewer < Operator < Admin`. Defaults to `Viewer`, the
40/// least privileged, so an omitted ceiling grants nothing extra (ADR 0023).
41#[derive(
42    Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
43)]
44pub enum FleetRole {
45    #[default]
46    Viewer,
47    Operator,
48    Admin,
49}
50
51/// Where a role grant or link token applies.
52#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
53pub enum GrantScope {
54    Fleet,
55    /// One workspace, by the name prospero reports for it (ADR 0023).
56    Workspace(String),
57}
58
59/// The system that authenticated an external account.
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
61pub enum Authenticator {
62    Discord,
63    Slack,
64    Teams,
65    Oidc { issuer: String },
66    Other(String),
67}
68
69/// Who did something: a person, an account not yet linked to one, or a service.
70#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
71pub enum FleetActor {
72    /// A person id.
73    Person(String),
74    Unlinked {
75        authenticator: Authenticator,
76        subject: String,
77    },
78    /// A service name, such as `"ariel"` or `"ariel-cli"`.
79    Service(String),
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn roles_are_ordered_viewer_operator_admin() {
88        assert!(FleetRole::Viewer < FleetRole::Operator);
89        assert!(FleetRole::Operator < FleetRole::Admin);
90        assert_eq!(
91            FleetRole::Admin.min(FleetRole::Viewer),
92            FleetRole::Viewer,
93            "a viewer-ceiling channel caps an admin"
94        );
95    }
96}