use geth_types::{AuthOpId, Capability, GroupId, PrincipalId, ResourceId, SecretId, UnixMillis}; use serde::{Deserialize, Serialize}; pub const AUTH_SIGNATURE_NAMESPACE: &str = "geth.auth-op.v1@geth.local"; pub const RESOURCE_GRANT_SIGNATURE_NAMESPACE: &str = "geth.resource-grant.v1@geth.local"; pub const REVOCATION_SIGNATURE_NAMESPACE: &str = "geth.revocation.v1@geth.local"; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct AuthOp { pub id: AuthOpId, pub resource: ResourceId, pub created_at: UnixMillis, pub kind: AuthOpKind, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "kind", rename_all = "kebab-case")] pub enum AuthOpKind { ResourceCreate, ResourceAuthoritySet { authority: ResourceId, }, GrantCreate { grant_id: String, principal: PrincipalId, capabilities: Vec, }, GrantRevoke { grant_id: String, }, BearerAccessCreate { secret: SecretId, capabilities: Vec, expires_at: Option, }, BearerAccessRevoke { secret: SecretId, }, GroupCreate { group: GroupId, }, GroupAddMember { group: GroupId, principal: PrincipalId, }, GroupRemoveMember { group: GroupId, principal: PrincipalId, }, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct AuthExplanation { pub subject: String, pub resource: String, pub capability: String, pub allowed: bool, pub reason: String, pub evaluated_ops: usize, } impl AuthExplanation { #[must_use] pub fn stub(subject: String, resource: String, capability: String) -> Self { Self { subject, resource, capability, allowed: false, reason: "authorization logs are scaffolded; no grant reducer is active yet".to_owned(), evaluated_ops: 0, } } } #[cfg(test)] mod tests { use super::*; #[test] fn auth_structs_roundtrip() { let op = AuthOp { id: "op:auth:1".into(), resource: "resource:notes".into(), created_at: UnixMillis(10), kind: AuthOpKind::GrantCreate { grant_id: "grant:1".to_owned(), principal: "node:laptop".into(), capabilities: vec!["kv.read".into(), "kv.write_prefix:apps/foo/".into()], }, }; let json = serde_json::to_string(&op).expect("json"); let decoded: AuthOp = serde_json::from_str(&json).expect("decode"); assert_eq!(decoded, op); } }