mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-21 20:18:06 +02:00
Feat/configurable sanitizers and js precision (#32)
* chore: Exclude CLAUDE.md from Cargo.toml * feat: Add configurable analysis rules and CLI commands for custom sanitizers and terminators * feat: Enhance resource management and analysis efficiency - Implemented parallel summary merging in `scan_filesystem` using rayon for improved performance. - Introduced `GlobalSummaries::merge()` for efficient merging of summaries. - Optimized file reading and hashing to eliminate redundant I/O operations. - Added `should_scan_with_hash()` and `upsert_file_with_hash()` methods to streamline file processing. - Enhanced taint analysis with in-place mutations to reduce memory allocations. - Updated resource acquisition patterns to exclude false positives for `freopen` and wrapper functions. * feat: Implement severity downgrade for findings in non-production paths and add source kind inference * feat: Update versioning information in SECURITY.md for new stable line * feat: Update categories in Cargo.toml to include parser-implementations and text-processing * feat: Update dependencies in Cargo.lock for improved compatibility and performance * feat: Update dependencies in Cargo.lock and Cargo.toml for improved compatibility
This commit is contained in:
parent
f96a89e7c1
commit
19b578c5c4
37 changed files with 3775 additions and 432 deletions
152
src/output.rs
Normal file
152
src/output.rs
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
use crate::commands::scan::Diag;
|
||||
use crate::patterns::{self, Severity};
|
||||
use once_cell::sync::Lazy;
|
||||
use serde_json::{Value, json};
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
/// Lazily-built global map: pattern ID → description from all language registries.
|
||||
static PATTERN_DESCRIPTIONS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
|
||||
let mut map = HashMap::new();
|
||||
for lang in &[
|
||||
"rust",
|
||||
"c",
|
||||
"cpp",
|
||||
"java",
|
||||
"go",
|
||||
"php",
|
||||
"python",
|
||||
"ruby",
|
||||
"javascript",
|
||||
"typescript",
|
||||
] {
|
||||
for p in patterns::load(lang) {
|
||||
map.entry(p.id).or_insert(p.description);
|
||||
}
|
||||
}
|
||||
map
|
||||
});
|
||||
|
||||
/// CFG rule descriptions for rules not in the pattern registry.
|
||||
fn cfg_rule_description(id: &str) -> Option<&'static str> {
|
||||
match id {
|
||||
"cfg-unguarded-sink" => Some("Dangerous sink reachable without prior guard or sanitizer"),
|
||||
"cfg-unreachable-sink" => Some("Sink in unreachable code"),
|
||||
"cfg-auth-gap" => Some("Entry-point handler reaches sink without authentication check"),
|
||||
"cfg-error-fallthrough" => {
|
||||
Some("Error check does not terminate; dangerous call follows on error path")
|
||||
}
|
||||
"cfg-resource-leak" => Some("Resource acquired but not released on all exit paths"),
|
||||
"cfg-lock-not-released" => Some("Lock acquired but not released on all exit paths"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Look up a human-readable description for any rule ID.
|
||||
fn rule_description(id: &str) -> &str {
|
||||
// Strip taint-specific suffix for lookup (e.g. "taint-unsanitised-flow:foo.rs:42" → base)
|
||||
let base_id = if id.starts_with("taint-") {
|
||||
"taint-unsanitised-flow"
|
||||
} else {
|
||||
id
|
||||
};
|
||||
|
||||
if let Some(desc) = PATTERN_DESCRIPTIONS.get(base_id) {
|
||||
return desc;
|
||||
}
|
||||
if let Some(desc) = cfg_rule_description(base_id) {
|
||||
return desc;
|
||||
}
|
||||
if base_id == "taint-unsanitised-flow" {
|
||||
return "Unsanitised data flows from source to sink";
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
fn severity_to_level(sev: Severity) -> &'static str {
|
||||
match sev {
|
||||
Severity::High => "error",
|
||||
Severity::Medium => "warning",
|
||||
Severity::Low => "note",
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a SARIF 2.1.0 JSON value from a list of diagnostics.
|
||||
pub fn build_sarif(diags: &[Diag], scan_root: &Path) -> Value {
|
||||
// Deduplicate rule IDs and build rules array.
|
||||
let mut rule_ids: Vec<String> = Vec::new();
|
||||
let mut rule_index_map: HashMap<String, usize> = HashMap::new();
|
||||
|
||||
for d in diags {
|
||||
let base = if d.id.starts_with("taint-") {
|
||||
"taint-unsanitised-flow".to_string()
|
||||
} else {
|
||||
d.id.clone()
|
||||
};
|
||||
if !rule_index_map.contains_key(&base) {
|
||||
let idx = rule_ids.len();
|
||||
rule_index_map.insert(base.clone(), idx);
|
||||
rule_ids.push(base);
|
||||
}
|
||||
}
|
||||
|
||||
let rules: Vec<Value> = rule_ids
|
||||
.iter()
|
||||
.map(|id| {
|
||||
json!({
|
||||
"id": id,
|
||||
"shortDescription": { "text": rule_description(id) },
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
let results: Vec<Value> = diags
|
||||
.iter()
|
||||
.map(|d| {
|
||||
let base = if d.id.starts_with("taint-") {
|
||||
"taint-unsanitised-flow"
|
||||
} else {
|
||||
&d.id
|
||||
};
|
||||
let rule_index = rule_index_map[base];
|
||||
|
||||
// Make path relative to scan root if possible
|
||||
let uri = Path::new(&d.path)
|
||||
.strip_prefix(scan_root)
|
||||
.map(|p| p.to_string_lossy().to_string())
|
||||
.unwrap_or_else(|_| d.path.clone());
|
||||
|
||||
json!({
|
||||
"ruleId": base,
|
||||
"ruleIndex": rule_index,
|
||||
"level": severity_to_level(d.severity),
|
||||
"message": { "text": rule_description(base) },
|
||||
"locations": [{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": { "uri": uri },
|
||||
"region": {
|
||||
"startLine": d.line,
|
||||
"startColumn": d.col
|
||||
}
|
||||
}
|
||||
}]
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
json!({
|
||||
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json",
|
||||
"version": "2.1.0",
|
||||
"runs": [{
|
||||
"tool": {
|
||||
"driver": {
|
||||
"name": "nyx",
|
||||
"version": env!("CARGO_PKG_VERSION"),
|
||||
"informationUri": env!("CARGO_PKG_HOMEPAGE"),
|
||||
"rules": rules
|
||||
}
|
||||
},
|
||||
"results": results
|
||||
}]
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue