Skip to main content

typesec_odrl/
model.rs

1//! Serde data model for ODRL YAML policies.
2
3use serde::{Deserialize, Serialize};
4
5/// Root document: a collection of ODRL policies.
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct OdrlDocument {
8    /// The policies in this document.
9    pub policies: Vec<OdrlPolicy>,
10}
11
12impl OdrlDocument {
13    /// Parse from YAML.
14    pub fn from_yaml(yaml: &str) -> Result<Self, serde_yaml::Error> {
15        serde_yaml::from_str(yaml)
16    }
17}
18
19/// An ODRL Policy.
20///
21/// A policy bundles related rules under a unique identifier.
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct OdrlPolicy {
24    /// Unique identifier (e.g., `"policy:ai-agent-001"`).
25    pub uid: String,
26    /// Policy type — `Set`, `Offer`, or `Agreement`.
27    #[serde(rename = "type")]
28    pub policy_type: String,
29    /// The rules in this policy.
30    pub rules: Vec<OdrlRule>,
31}
32
33/// An ODRL Rule (permission, prohibition, or duty).
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct OdrlRule {
36    /// Rule type: `"permission"`, `"prohibition"`, or `"duty"`.
37    #[serde(rename = "type")]
38    pub rule_type: OdrlRuleType,
39    /// The party granting permission (optional for prohibitions).
40    #[serde(default)]
41    pub assigner: Option<String>,
42    /// The party the rule applies to.
43    pub assignee: String,
44    /// The action this rule covers.
45    pub action: RuleAction,
46    /// The asset this rule applies to.
47    pub target: String,
48    /// Constraints that must hold for the rule to apply.
49    #[serde(default)]
50    pub constraints: Vec<OdrlConstraint>,
51}
52
53/// The type of an ODRL rule.
54#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
55#[serde(rename_all = "lowercase")]
56pub enum OdrlRuleType {
57    /// Grants the assignee the action on the target (if constraints hold).
58    Permission,
59    /// Denies the assignee the action on the target (if constraints hold).
60    Prohibition,
61    /// Obligates the assignee to perform the action.
62    Duty,
63}
64
65/// An ODRL action.
66///
67/// Maps to our `Permission::name()` strings plus the special `"use"` wildcard.
68#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
69#[serde(rename_all = "lowercase")]
70pub enum RuleAction {
71    /// Read access.
72    Read,
73    /// Write access.
74    Write,
75    /// Delete access.
76    Delete,
77    /// Execute access.
78    Execute,
79    /// Delegation.
80    Delegate,
81    /// Read sensitive data.
82    #[serde(rename = "read_sensitive")]
83    ReadSensitive,
84    /// Write sensitive data.
85    #[serde(rename = "write_sensitive")]
86    WriteSensitive,
87    /// AI inference.
88    #[serde(rename = "ai:infer")]
89    AiInfer,
90    /// AI training.
91    #[serde(rename = "ai:train")]
92    AiTrain,
93    /// Data exfiltration.
94    #[serde(rename = "exfiltrate")]
95    Exfiltrate,
96    /// Wildcard — applies to all actions.
97    Use,
98}
99
100impl RuleAction {
101    /// Convert to the `Permission::name()` string.
102    pub fn as_permission_name(&self) -> &str {
103        match self {
104            RuleAction::Read => "read",
105            RuleAction::Write => "write",
106            RuleAction::Delete => "delete",
107            RuleAction::Execute => "execute",
108            RuleAction::Delegate => "delegate",
109            RuleAction::ReadSensitive => "read_sensitive",
110            RuleAction::WriteSensitive => "write_sensitive",
111            RuleAction::AiInfer => "ai:infer",
112            RuleAction::AiTrain => "ai:train",
113            RuleAction::Exfiltrate => "ai:exfiltrate",
114            RuleAction::Use => "*",
115        }
116    }
117
118    /// Returns `true` if this action matches the given permission name.
119    pub fn matches_action(&self, action: &str) -> bool {
120        self == &RuleAction::Use || self.as_permission_name() == action
121    }
122}
123
124/// An ODRL constraint on a rule.
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct OdrlConstraint {
127    /// The left operand (e.g., `"purpose"`, `"dateTime"`, `"count"`).
128    #[serde(rename = "leftOperand")]
129    pub left_operand: String,
130    /// The comparison operator.
131    pub operator: ConstraintOperator,
132    /// The right operand value (string representation).
133    #[serde(rename = "rightOperand")]
134    pub right_operand: String,
135}
136
137/// ODRL constraint operators.
138#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
139#[serde(rename_all = "camelCase")]
140pub enum ConstraintOperator {
141    /// Equal.
142    Eq,
143    /// Not equal.
144    Neq,
145    /// Less than.
146    Lt,
147    /// Less than or equal.
148    Lteq,
149    /// Greater than.
150    Gt,
151    /// Greater than or equal.
152    Gteq,
153    /// Is in a comma-separated list.
154    #[serde(rename = "isPartOf")]
155    IsPartOf,
156}