Skip to main content

regorus/
target.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3#![allow(dead_code)]
4use crate::{Rc, Schema, Value, Vec};
5use alloc::collections::BTreeMap;
6use serde::Deserialize;
7
8mod deserialize;
9mod error;
10mod resource_schema_selector;
11
12type String = Rc<str>;
13
14use deserialize::{deserialize_effects, deserialize_resource_schemas};
15pub use error::TargetError;
16
17/// A target defines the domain for which a set of policies are written.
18/// It specifies the types of input resources, possible policy effects,
19/// and configuration for policy evaluation.
20#[derive(Debug, Clone, Deserialize)]
21#[serde(deny_unknown_fields)]
22pub struct Target {
23    /// Name of the target domain
24    /// A Rego module can specify a target by defining a rule named `__target__`:
25    ///       __target__ = "my_target"
26    pub name: String,
27
28    /// Description of what this target is for
29    pub description: Option<String>,
30
31    /// Version of the target
32    pub version: String,
33
34    /// Types of input resources that policies can evaluate
35    #[serde(deserialize_with = "deserialize_resource_schemas")]
36    pub resource_schemas: Vec<Rc<Schema>>,
37
38    /// The discriminator property that can be used to select
39    /// a specific resource schema
40    pub resource_schema_selector: String,
41
42    /// Set of effects that policies can produce
43    #[serde(deserialize_with = "deserialize_effects")]
44    pub effects: BTreeMap<String, Rc<Schema>>,
45    /// Lookup table for resource schemas by discrimiator values.
46    #[serde(skip)]
47    pub resource_schema_lookup: BTreeMap<Value, Rc<Schema>>,
48
49    /// Resource chemas that cannot be distinguished by the discriminator
50    #[serde(skip)]
51    pub default_resource_schema: Option<Rc<Schema>>,
52}
53
54impl Target {
55    pub fn from_json_str(json: &str) -> Result<Self, TargetError> {
56        let mut target: Target = serde_json::from_str(json).map_err(TargetError::from)?;
57
58        // Validate that resource schemas is not empty
59        if target.resource_schemas.is_empty() {
60            return Err(TargetError::EmptyResourceSchemas(
61                "Target must have at least one resource schema defined".into(),
62            ));
63        }
64
65        if target.effects.is_empty() {
66            return Err(TargetError::EmptyEffectSchemas(
67                "Target must have at least one effect defined".into(),
68            ));
69        }
70
71        resource_schema_selector::populate_target_lookup_fields(&mut target)?;
72        Ok(target)
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    mod deserialize;
79}