Skip to main content

authy/policy/
mod.rs

1use globset::{Glob, GlobSet, GlobSetBuilder};
2use serde::{Deserialize, Serialize};
3
4use crate::error::{AuthyError, Result};
5
6/// A policy defines which secrets a scope can access.
7/// Deny patterns override allow patterns. Default is deny.
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct Policy {
10    pub name: String,
11    pub description: Option<String>,
12    pub allow: Vec<String>,
13    pub deny: Vec<String>,
14    pub created_at: chrono::DateTime<chrono::Utc>,
15    pub modified_at: chrono::DateTime<chrono::Utc>,
16    /// When true, secrets can only be injected via `run` — `get`, `env`, `export` are blocked.
17    #[serde(default)]
18    pub run_only: bool,
19}
20
21impl Policy {
22    pub fn new(name: String, allow: Vec<String>, deny: Vec<String>) -> Self {
23        let now = chrono::Utc::now();
24        Self {
25            name,
26            description: None,
27            allow,
28            deny,
29            created_at: now,
30            modified_at: now,
31            run_only: false,
32        }
33    }
34
35    /// Check if a secret name is allowed by this policy.
36    /// Deny overrides allow. Default deny.
37    pub fn can_read(&self, secret_name: &str) -> Result<bool> {
38        let deny_set = build_globset(&self.deny)?;
39        if deny_set.is_match(secret_name) {
40            return Ok(false);
41        }
42
43        let allow_set = build_globset(&self.allow)?;
44        Ok(allow_set.is_match(secret_name))
45    }
46
47    /// Return all secret names from a list that this policy allows.
48    pub fn filter_secrets<'a>(&self, names: &[&'a str]) -> Result<Vec<&'a str>> {
49        let mut allowed = Vec::new();
50        for name in names {
51            if self.can_read(name)? {
52                allowed.push(*name);
53            }
54        }
55        Ok(allowed)
56    }
57}
58
59fn build_globset(patterns: &[String]) -> Result<GlobSet> {
60    let mut builder = GlobSetBuilder::new();
61    for pattern in patterns {
62        let glob = Glob::new(pattern)
63            .map_err(|e| AuthyError::Other(format!("Invalid glob pattern '{}': {}", pattern, e)))?;
64        builder.add(glob);
65    }
66    builder
67        .build()
68        .map_err(|e| AuthyError::Other(format!("Failed to build glob set: {}", e)))
69}