Skip to main content

aegis_scan/
types.rs

1use std::fmt;
2use std::path::{Path, PathBuf};
3
4use serde::{Deserialize, Serialize};
5
6use crate::registry::package::PackageMetadata;
7
8/// Severity level for a finding
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
10pub enum Severity {
11    Info,
12    Low,
13    Medium,
14    High,
15    Critical,
16}
17
18impl fmt::Display for Severity {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        match self {
21            Severity::Info => write!(f, "INFO"),
22            Severity::Low => write!(f, "LOW"),
23            Severity::Medium => write!(f, "MEDIUM"),
24            Severity::High => write!(f, "HIGH"),
25            Severity::Critical => write!(f, "CRITICAL"),
26        }
27    }
28}
29
30/// A single security finding from an analyzer
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct Finding {
33    pub severity: Severity,
34    pub category: FindingCategory,
35    pub title: String,
36    pub description: String,
37    /// File where the finding was detected (relative to package root)
38    pub file: Option<String>,
39    /// Line number in the file
40    pub line: Option<usize>,
41    /// The matched code snippet
42    pub snippet: Option<String>,
43}
44
45/// Categories of security findings
46#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
47pub enum FindingCategory {
48    /// eval(), Function(), Buffer.from + eval patterns
49    CodeExecution,
50    /// http.request, fetch, dns.lookup, net.connect
51    NetworkAccess,
52    /// child_process, exec, spawn, execSync
53    ProcessSpawn,
54    /// fs operations on sensitive paths
55    FileSystemAccess,
56    /// Obfuscated/encoded code (high entropy, hex strings)
57    Obfuscation,
58    /// Suspicious preinstall/postinstall scripts
59    InstallScript,
60    /// Environment variable harvesting
61    EnvAccess,
62    /// Suspicious patterns that don't fit other categories
63    Suspicious,
64    /// Maintainer changes (ownership transfers, new accounts, etc.)
65    MaintainerChange,
66    /// Package looks like an AI-hallucinated name (typosquat / fake package)
67    HallucinatedPackage,
68    /// Known vulnerability (CVE) from OSV.dev
69    KnownVulnerability,
70    /// Risks in the transitive dependency tree
71    DependencyRisk,
72    /// Provenance verification (npm tarball vs GitHub source)
73    Provenance,
74    /// Binary/executable files detected in package
75    BinaryFile,
76    /// Multi-step data flow analysis (taint tracking)
77    DataFlow,
78}
79
80impl fmt::Display for FindingCategory {
81    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82        match self {
83            FindingCategory::CodeExecution => write!(f, "Code Execution"),
84            FindingCategory::NetworkAccess => write!(f, "Network Access"),
85            FindingCategory::ProcessSpawn => write!(f, "Process Spawn"),
86            FindingCategory::FileSystemAccess => write!(f, "File System Access"),
87            FindingCategory::Obfuscation => write!(f, "Obfuscation"),
88            FindingCategory::InstallScript => write!(f, "Install Script"),
89            FindingCategory::EnvAccess => write!(f, "Env Access"),
90            FindingCategory::Suspicious => write!(f, "Suspicious"),
91            FindingCategory::MaintainerChange => write!(f, "Maintainer Change"),
92            FindingCategory::HallucinatedPackage => write!(f, "Hallucinated Package"),
93            FindingCategory::KnownVulnerability => write!(f, "Known Vulnerability"),
94            FindingCategory::DependencyRisk => write!(f, "Dependency Risk"),
95            FindingCategory::Provenance => write!(f, "Provenance"),
96            FindingCategory::BinaryFile => write!(f, "Binary File"),
97            FindingCategory::DataFlow => write!(f, "Data Flow"),
98        }
99    }
100}
101
102/// Complete analysis report for a package
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct AnalysisReport {
105    pub package_name: String,
106    pub version: String,
107    pub findings: Vec<Finding>,
108    pub risk_score: f64,
109    pub risk_label: RiskLabel,
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
113pub enum RiskLabel {
114    Clean,
115    Low,
116    Medium,
117    High,
118    Critical,
119}
120
121/// Context passed to unified analyzers, containing all data needed for analysis.
122pub struct AnalysisContext<'a> {
123    pub name: &'a str,
124    pub version: &'a str,
125    pub files: &'a [(PathBuf, String)],
126    pub package_json: &'a serde_json::Value,
127    pub metadata: &'a PackageMetadata,
128    pub package_dir: &'a Path,
129}
130
131impl fmt::Display for RiskLabel {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        match self {
134            RiskLabel::Clean => write!(f, "CLEAN"),
135            RiskLabel::Low => write!(f, "LOW RISK"),
136            RiskLabel::Medium => write!(f, "MEDIUM RISK"),
137            RiskLabel::High => write!(f, "HIGH RISK"),
138            RiskLabel::Critical => write!(f, "DO NOT INSTALL"),
139        }
140    }
141}