1use serde::{Deserialize, Serialize};
4use std::fmt;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
11#[serde(rename_all = "UPPERCASE")]
12pub enum RiskLevel {
13 Low,
14 Medium,
15 High,
16 Critical,
17}
18
19impl fmt::Display for RiskLevel {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 match self {
22 RiskLevel::Low => write!(f, "LOW"),
23 RiskLevel::Medium => write!(f, "MEDIUM"),
24 RiskLevel::High => write!(f, "HIGH"),
25 RiskLevel::Critical => write!(f, "CRITICAL"),
26 }
27 }
28}
29
30impl RiskLevel {
31 pub fn from_score(score: u32) -> Self {
33 match score {
34 0..=20 => RiskLevel::Low,
35 21..=50 => RiskLevel::Medium,
36 51..=100 => RiskLevel::High,
37 _ => RiskLevel::Critical,
38 }
39 }
40
41 pub fn exit_code(self, fail_on: RiskLevel) -> i32 {
43 if self >= fail_on {
44 1
45 } else {
46 0
47 }
48 }
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct DetectedOperation {
58 pub description: String,
60 pub tables: Vec<String>,
62 pub risk_level: RiskLevel,
64 pub score: u32,
66 pub warning: Option<String>,
68 pub acquires_lock: bool,
70 pub index_rebuild: bool,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct FkImpact {
80 pub constraint_name: String,
81 pub from_table: String,
82 pub to_table: String,
83 pub cascade: bool,
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
96#[serde(rename_all = "lowercase")]
97pub enum ActorKind {
98 Human,
99 Ci,
100 Agent,
101}
102
103impl std::fmt::Display for ActorKind {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 match self {
106 ActorKind::Human => write!(f, "human (interactive terminal)"),
107 ActorKind::Ci => write!(f, "ci"),
108 ActorKind::Agent => write!(f, "agent"),
109 }
110 }
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize)]
115pub struct GuardDecision {
116 pub operation: String,
118 pub risk_level: RiskLevel,
120 pub score: u32,
122 pub impact_summary: String,
124 pub confirmed: bool,
126 pub typed_phrase: Option<String>,
128 pub timestamp: String,
130 pub actor: ActorKind,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct GuardAuditLog {
140 pub schemarisk_version: String,
141 pub file: String,
142 pub timestamp: String,
143 pub actor: ActorKind,
144 pub decisions: Vec<GuardDecision>,
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct MigrationReport {
149 pub file: String,
150 pub overall_risk: RiskLevel,
151 pub score: u32,
152 pub affected_tables: Vec<String>,
153 pub operations: Vec<DetectedOperation>,
154 pub warnings: Vec<String>,
155 pub recommendations: Vec<String>,
156 pub fk_impacts: Vec<FkImpact>,
157 pub estimated_lock_seconds: Option<u64>,
158 pub index_rebuild_required: bool,
159 pub requires_maintenance_window: bool,
160 pub analyzed_at: String,
161 pub pg_version: u32,
163 pub guard_required: bool,
165 pub guard_decisions: Vec<GuardDecision>,
167}