1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use stack_ids::{
4 ApplicabilityContextId, CompiledObligationSetId, CompositionConflictSetId,
5 CompositionReceiptId, CompositionRuleSetId, ContentDigest, EffectiveConstitutionId,
6 PolicyImpactDiffId, ProfileExceptionBundleId, ProfileSetId,
7};
8
9use crate::rules::{CompiledObligationKindV1, FoldClassV1};
10
11pub const COMPOSITION_RECEIPT_V1_SCHEMA: &str = "composition_receipt_v1";
12pub const EFFECTIVE_CONSTITUTION_V1_SCHEMA: &str = "effective_constitution_v1";
13pub const COMPILED_OBLIGATION_SET_V1_SCHEMA: &str = "compiled_obligation_set_v1";
14pub const COMPOSITION_CONFLICT_SET_V1_SCHEMA: &str = "composition_conflict_set_v1";
15pub const POLICY_IMPACT_DIFF_V1_SCHEMA: &str = "policy_impact_diff_v1";
16
17#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
18pub struct CompositionReceiptV1 {
19 pub schema_version: String,
20 pub composition_receipt_id: CompositionReceiptId,
21 pub applicability_context_ref: ApplicabilityContextId,
22 pub profile_set_ref: ProfileSetId,
23 pub composition_rule_set_ref: CompositionRuleSetId,
24 #[serde(default, skip_serializing_if = "Option::is_none")]
25 pub effective_constitution_ref: Option<EffectiveConstitutionId>,
26 #[serde(default, skip_serializing_if = "Option::is_none")]
27 pub compiled_obligation_set_ref: Option<CompiledObligationSetId>,
28 #[serde(default, skip_serializing_if = "Option::is_none")]
29 pub composition_conflict_set_ref: Option<CompositionConflictSetId>,
30 #[serde(default, skip_serializing_if = "Vec::is_empty")]
31 pub degradation_markers: Vec<String>,
32 #[serde(default, skip_serializing_if = "Option::is_none")]
33 pub execution_context_ref: Option<String>,
34 pub replay_handle: String,
35 pub normalized_input_digest: ContentDigest,
36 pub generated_at: String,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
40#[serde(rename_all = "snake_case")]
41pub enum ConstitutionModeV1 {
42 Normal,
43 Incident,
44 AdvisoryOnly,
45 Blocked,
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
49pub struct EffectiveConstitutionV1 {
50 pub schema_version: String,
51 pub effective_constitution_id: EffectiveConstitutionId,
52 pub applicability_context_ref: ApplicabilityContextId,
53 pub profile_set_ref: ProfileSetId,
54 pub composition_rule_set_ref: CompositionRuleSetId,
55 #[serde(default, skip_serializing_if = "Vec::is_empty")]
56 pub base_law_refs: Vec<String>,
57 #[serde(default, skip_serializing_if = "Vec::is_empty")]
58 pub doctrine_refs: Vec<String>,
59 #[serde(default, skip_serializing_if = "Vec::is_empty")]
60 pub admitted_profile_refs: Vec<String>,
61 #[serde(default, skip_serializing_if = "Vec::is_empty")]
62 pub admitted_exception_refs: Vec<ProfileExceptionBundleId>,
63 pub current_mode_classification: ConstitutionModeV1,
64 #[serde(default, skip_serializing_if = "Vec::is_empty")]
65 pub hard_block_summary: Vec<String>,
66 #[serde(default, skip_serializing_if = "Vec::is_empty")]
67 pub active_warning_summary: Vec<String>,
68 #[serde(default, skip_serializing_if = "Vec::is_empty")]
69 pub approval_requirements: Vec<String>,
70 #[serde(default, skip_serializing_if = "Vec::is_empty")]
71 pub disclosure_obligations: Vec<String>,
72 #[serde(default, skip_serializing_if = "Vec::is_empty")]
73 pub residency_obligations: Vec<String>,
74 #[serde(default, skip_serializing_if = "Vec::is_empty")]
75 pub tenancy_obligations: Vec<String>,
76 #[serde(default, skip_serializing_if = "Vec::is_empty")]
77 pub assurance_obligations: Vec<String>,
78 #[serde(default, skip_serializing_if = "Vec::is_empty")]
79 pub monitoring_obligations: Vec<String>,
80 #[serde(default, skip_serializing_if = "Vec::is_empty")]
81 pub continuity_obligations: Vec<String>,
82 #[serde(default, skip_serializing_if = "Vec::is_empty")]
83 pub effect_obligations: Vec<String>,
84 #[serde(default, skip_serializing_if = "Vec::is_empty")]
85 pub delegation_obligations: Vec<String>,
86 #[serde(default, skip_serializing_if = "Vec::is_empty")]
87 pub replay_obligations: Vec<String>,
88 pub valid_as_of: String,
89 pub recorded_as_of: String,
90 pub explanation_summary: String,
91}
92
93#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
94pub struct CompiledObligationEntryV1 {
95 pub obligation_entry_id: String,
96 pub obligation_family: String,
97 pub obligation_key: String,
98 pub output_kind: CompiledObligationKindV1,
99 pub fold_class: FoldClassV1,
100 #[serde(default, skip_serializing_if = "Vec::is_empty")]
101 pub string_values: Vec<String>,
102 #[serde(default, skip_serializing_if = "Option::is_none")]
103 pub numeric_value: Option<i64>,
104 #[serde(default, skip_serializing_if = "Option::is_none")]
105 pub expiry_at: Option<String>,
106 pub blocking: bool,
107 #[serde(default, skip_serializing_if = "Vec::is_empty")]
108 pub source_profile_refs: Vec<String>,
109 #[serde(default, skip_serializing_if = "Vec::is_empty")]
110 pub source_exception_refs: Vec<ProfileExceptionBundleId>,
111 pub explanation: String,
112}
113
114#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
115pub struct BlockEntryV1 {
116 pub block_key: String,
117 pub reason: String,
118 #[serde(default, skip_serializing_if = "Vec::is_empty")]
119 pub source_profile_refs: Vec<String>,
120 #[serde(default, skip_serializing_if = "Vec::is_empty")]
121 pub admissible_exception_classes: Vec<String>,
122}
123
124#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
125pub struct CompiledObligationSetV1 {
126 pub schema_version: String,
127 pub compiled_obligation_set_id: CompiledObligationSetId,
128 pub effective_constitution_ref: EffectiveConstitutionId,
129 #[serde(default, skip_serializing_if = "Vec::is_empty")]
130 pub obligation_entries: Vec<CompiledObligationEntryV1>,
131 #[serde(default, skip_serializing_if = "Vec::is_empty")]
132 pub block_entries: Vec<BlockEntryV1>,
133 #[serde(default, skip_serializing_if = "Vec::is_empty")]
134 pub required_approvals: Vec<String>,
135 #[serde(default, skip_serializing_if = "Vec::is_empty")]
136 pub required_checks: Vec<String>,
137 #[serde(default, skip_serializing_if = "Vec::is_empty")]
138 pub required_monitors: Vec<String>,
139 #[serde(default, skip_serializing_if = "Vec::is_empty")]
140 pub required_evidence_obligations: Vec<String>,
141 #[serde(default, skip_serializing_if = "Vec::is_empty")]
142 pub required_disclosure_obligations: Vec<String>,
143 #[serde(default, skip_serializing_if = "Vec::is_empty")]
144 pub required_rollback_obligations: Vec<String>,
145 #[serde(default, skip_serializing_if = "Vec::is_empty")]
146 pub required_compensation_obligations: Vec<String>,
147 #[serde(default, skip_serializing_if = "Vec::is_empty")]
148 pub required_post_hoc_review_obligations: Vec<String>,
149 pub promotion_eligibility_summary: String,
150 pub release_eligibility_summary: String,
151 pub effect_eligibility_summary: String,
152 #[serde(default, skip_serializing_if = "Vec::is_empty")]
153 pub unresolved_dependency_refs: Vec<String>,
154}
155
156#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
157pub struct CompositionConflictV1 {
158 pub obligation_family: String,
159 pub obligation_key: String,
160 pub conflict_class: String,
161 pub blocking: bool,
162 #[serde(default, skip_serializing_if = "Vec::is_empty")]
163 pub source_profile_refs: Vec<String>,
164 #[serde(default, skip_serializing_if = "Vec::is_empty")]
165 pub implicated_values: Vec<String>,
166 #[serde(default, skip_serializing_if = "Vec::is_empty")]
167 pub admissible_exception_classes: Vec<String>,
168 pub review_path: String,
169 pub explanation: String,
170}
171
172#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
173pub struct CompositionConflictSetV1 {
174 pub schema_version: String,
175 pub composition_conflict_set_id: CompositionConflictSetId,
176 #[serde(default, skip_serializing_if = "Option::is_none")]
177 pub effective_constitution_ref: Option<EffectiveConstitutionId>,
178 #[serde(default, skip_serializing_if = "Option::is_none")]
179 pub composition_receipt_ref: Option<CompositionReceiptId>,
180 #[serde(default, skip_serializing_if = "Vec::is_empty")]
181 pub conflicts: Vec<CompositionConflictV1>,
182 pub blocking: bool,
183}
184
185#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
186pub struct PolicyImpactDiffV1 {
187 pub schema_version: String,
188 pub policy_impact_diff_id: PolicyImpactDiffId,
189 pub from_effective_constitution_ref: EffectiveConstitutionId,
190 pub to_effective_constitution_ref: EffectiveConstitutionId,
191 #[serde(default, skip_serializing_if = "Vec::is_empty")]
192 pub changed_obligation_families: Vec<String>,
193 #[serde(default, skip_serializing_if = "Vec::is_empty")]
194 pub unchanged_obligation_families: Vec<String>,
195 #[serde(default, skip_serializing_if = "Vec::is_empty")]
196 pub newly_blocked_paths: Vec<String>,
197 #[serde(default, skip_serializing_if = "Vec::is_empty")]
198 pub newly_admitted_paths: Vec<String>,
199 #[serde(default, skip_serializing_if = "Vec::is_empty")]
200 pub changed_approval_behavior: Vec<String>,
201 #[serde(default, skip_serializing_if = "Vec::is_empty")]
202 pub changed_monitoring_behavior: Vec<String>,
203 #[serde(default, skip_serializing_if = "Vec::is_empty")]
204 pub changed_disclosure_behavior: Vec<String>,
205 #[serde(default, skip_serializing_if = "Vec::is_empty")]
206 pub changed_residency_behavior: Vec<String>,
207 #[serde(default, skip_serializing_if = "Vec::is_empty")]
208 pub changed_incident_behavior: Vec<String>,
209 #[serde(default, skip_serializing_if = "Vec::is_empty")]
210 pub migration_consequences: Vec<String>,
211 pub simulation_only: bool,
212 pub explanation_summary: String,
213}