Skip to main content

ai_coding_shield/
types.rs

1use serde::{Deserialize, Serialize};
2use std::path::PathBuf;
3
4/// Type of artifact being scanned
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
6pub enum ArtifactType {
7    Workflow,
8    Skill,
9    McpInfo,
10    Rule,
11    Mcp,
12    Script,
13}
14
15/// A scanned artifact (workflow, skill, etc.)
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct Artifact {
18    pub artifact_type: ArtifactType,
19    pub path: PathBuf,
20    pub content: String,
21    pub metadata: ArtifactMetadata,
22}
23
24/// Metadata extracted from artifact
25#[derive(Debug, Clone, Default, Serialize, Deserialize)]
26pub struct ArtifactMetadata {
27    pub name: Option<String>,
28    pub description: Option<String>,
29    pub has_auto_run: bool,
30    pub has_turbo_annotation: bool,
31    pub commands: Vec<String>,
32    pub permissions: Vec<String>,
33}
34
35/// Risk level for findings
36#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
37pub enum RiskLevel {
38    Low = 1,
39    Medium = 2,
40    High = 3,
41    Critical = 4,
42}
43
44impl RiskLevel {
45    pub fn as_str(&self) -> &str {
46        match self {
47            RiskLevel::Low => "LOW",
48            RiskLevel::Medium => "MEDIUM",
49            RiskLevel::High => "HIGH",
50            RiskLevel::Critical => "CRITICAL",
51        }
52    }
53
54    #[allow(dead_code)]
55    pub fn from_str(s: &str) -> Option<Self> {
56        match s.to_lowercase().as_str() {
57            "low" => Some(RiskLevel::Low),
58            "medium" => Some(RiskLevel::Medium),
59            "high" => Some(RiskLevel::High),
60            "critical" => Some(RiskLevel::Critical),
61            _ => None,
62        }
63    }
64}
65
66/// A security finding
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct Finding {
69    pub artifact_path: PathBuf,
70    pub threat_id: String,
71    pub threat_name: String,
72    pub risk_level: RiskLevel,
73    pub risk_score: u8,
74    pub line_number: Option<usize>,
75    pub matched_pattern: String,
76    pub description: String,
77    pub recommendation: String,
78    pub mitre_id: Option<String>,
79    pub cwe_id: Option<String>,
80    pub flags: Vec<String>,
81}
82
83/// Analysis result for an artifact
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct AnalysisResult {
86    pub artifact: Artifact,
87    pub findings: Vec<Finding>,
88    pub overall_risk_score: u8,
89    pub risk_level: RiskLevel,
90}
91
92impl AnalysisResult {
93    pub fn new(artifact: Artifact) -> Self {
94        Self {
95            artifact,
96            findings: Vec::new(),
97            overall_risk_score: 0,
98            risk_level: RiskLevel::Low,
99        }
100    }
101
102    pub fn add_finding(&mut self, finding: Finding) {
103        self.overall_risk_score = self.overall_risk_score.saturating_add(finding.risk_score);
104        self.risk_level = self.risk_level.max(finding.risk_level);
105        self.findings.push(finding);
106    }
107}