diff --git a/src/ast_differ.rs b/src/ast_differ.rs index d5ae034..e312394 100644 --- a/src/ast_differ.rs +++ b/src/ast_differ.rs @@ -93,6 +93,14 @@ pub fn diff_symbols( } } + // Sort for deterministic output: by file, then function, then change_type + results.sort_by(|a, b| { + a.file + .cmp(&b.file) + .then(a.function.cmp(&b.function)) + .then(a.change_type.cmp(&b.change_type)) + }); + results } diff --git a/src/db.rs b/src/db.rs index 41cb653..6a210f8 100644 --- a/src/db.rs +++ b/src/db.rs @@ -11,7 +11,7 @@ pub struct VulnDb { } /// A single vulnerability entry with function-level detail. -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct VulnEntry { pub advisory_id: String, pub package: String, @@ -42,7 +42,24 @@ impl VulnDb { } pub fn write_json(&self, path: &Path) -> anyhow::Result<()> { - let json = serde_json::to_string_pretty(self)?; + // Sort for deterministic output to minimize diff noise + let mut sorted = self.entries.clone(); + sorted.sort_by(|a, b| a.advisory_id.cmp(&b.advisory_id)); + for entry in &mut sorted { + entry.vulnerable_symbols.sort_by(|a, b| { + a.file + .cmp(&b.file) + .then(a.function.cmp(&b.function)) + .then(a.change_type.cmp(&b.change_type)) + }); + } + + let sorted_db = VulnDb { + generated_at: self.generated_at.clone(), + entries: sorted, + }; + let mut json = serde_json::to_string_pretty(&sorted_db)?; + json.push('\n'); std::fs::write(path, json)?; Ok(()) } diff --git a/src/diff_analyzer.rs b/src/diff_analyzer.rs index 83894f6..c244d3a 100644 --- a/src/diff_analyzer.rs +++ b/src/diff_analyzer.rs @@ -18,11 +18,11 @@ pub struct VulnerableSymbol { pub change_type: ChangeType, } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)] pub enum ChangeType { - Modified, Added, Deleted, + Modified, } /// Extract function signatures by fetching full file contents and AST-diffing. diff --git a/src/main.rs b/src/main.rs index 4e41863..807b99b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -395,8 +395,10 @@ fn run_enrich(args: EnrichArgs) -> Result<()> { println!(); } - // Update timestamp - vuln_db.update_timestamp(); + // Only update timestamp if we actually changed something + if new_count > 0 || re_enriched_count > 0 { + vuln_db.update_timestamp(); + } // Step 6: Write output let entries_with_symbols = vuln_db