road-runner-common 0.8.0

Shared Rust utilities for exchange ecosystem backend services.
Documentation
//! Permission-catalog self-registration payload.
//!
//! A service declares the permissions it enforces so cex-policy can surface drift
//! (granted-but-undeclared / declared-but-ungranted). This is **advisory** — never
//! load-bearing for enforcement — so road-runner stays HTTP-free: it builds the body,
//! the service performs the `POST /internal/authz/manifest` (with whatever client and
//! retry policy it already uses).

use serde::Serialize;

#[derive(Debug, Clone, Serialize)]
pub struct ManifestEntry {
    pub permission: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub min_acr: Option<String>,
    #[serde(default)]
    pub requires_quorum: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
}

impl ManifestEntry {
    pub fn new(permission: impl Into<String>) -> Self {
        Self {
            permission: permission.into(),
            min_acr: None,
            requires_quorum: false,
            description: None,
        }
    }

    pub fn min_acr(mut self, acr: impl Into<String>) -> Self {
        self.min_acr = Some(acr.into());
        self
    }

    pub fn requires_quorum(mut self, v: bool) -> Self {
        self.requires_quorum = v;
        self
    }

    pub fn description(mut self, d: impl Into<String>) -> Self {
        self.description = Some(d.into());
        self
    }
}

#[derive(Debug, Clone, Serialize)]
pub struct PermissionManifest {
    pub service: String,
    pub permissions: Vec<ManifestEntry>,
}

impl PermissionManifest {
    pub fn new(service: impl Into<String>) -> Self {
        Self { service: service.into(), permissions: Vec::new() }
    }

    pub fn with(mut self, entry: ManifestEntry) -> Self {
        self.permissions.push(entry);
        self
    }

    /// The JSON body to POST to `/internal/authz/manifest`.
    pub fn to_json(&self) -> serde_json::Value {
        serde_json::json!({ "service": self.service, "permissions": self.permissions })
    }
}