1use globset::{Glob, GlobSet, GlobSetBuilder};
2use serde::{Deserialize, Serialize};
3
4use crate::error::{AuthyError, Result};
5
6#[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 #[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 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 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}