Critical bug fixes and recall improvements (#68)

This commit is contained in:
Eli Peter 2026-05-11 12:42:39 -04:00 committed by GitHub
parent 7d0e7320e2
commit 55247b7fcd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
352 changed files with 60069 additions and 900 deletions

View file

@ -137,7 +137,7 @@ mod tests {
AppState {
scan_root: scan_root.clone(),
config_dir: scan_root.clone(),
database_dir: scan_root.clone(),
database_dir: scan_root,
security: LocalServerSecurity::new(port),
config: Arc::new(RwLock::new(Config::default())),
job_manager: Arc::new(JobManager::new(4, 8 * 1024 * 1024)),

View file

@ -1187,6 +1187,18 @@ fn type_kind_tag(k: &TypeKind) -> String {
TypeKind::Template => "Template".into(),
TypeKind::Dto(_) => "Dto".into(),
TypeKind::NullPrototypeObject => "NullPrototypeObject".into(),
TypeKind::FileSystemPromisesNs => "FileSystemPromisesNs".into(),
TypeKind::Sequelize => "Sequelize".into(),
TypeKind::TypeOrmRepo => "TypeOrmRepo".into(),
TypeKind::TypeOrmManager => "TypeOrmManager".into(),
TypeKind::MikroOrmEm => "MikroOrmEm".into(),
TypeKind::Request => "Request".into(),
TypeKind::SqlAlchemySession => "SqlAlchemySession".into(),
TypeKind::DjangoQuerySet => "DjangoQuerySet".into(),
TypeKind::ActiveRecordRelation => "ActiveRecordRelation".into(),
TypeKind::GormDb => "GormDb".into(),
TypeKind::SqlxDb => "SqlxDb".into(),
TypeKind::HibernateSession => "HibernateSession".into(),
}
}
@ -1565,6 +1577,10 @@ pub fn analyse_function_taint(
auto_seed_handler_params: matches!(lang, Lang::JavaScript | Lang::TypeScript),
cross_file_bodies: global_summaries.and_then(|gs| gs.bodies_by_key()),
pointer_facts: None,
cross_package_imports: None,
entry_kind: None,
param_route_capture: None,
recording_summary: false,
};
crate::taint::ssa_transfer::run_ssa_taint_full_with_exits(ssa, cfg, &transfer)
@ -1628,7 +1644,7 @@ pub fn analyse_file_summaries(
config: &Config,
) -> Result<GlobalSummaries, StatusCode> {
let bytes = std::fs::read(file_path).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let (func_summaries, ssa_rows, _ssa_bodies, auth_rows) =
let (func_summaries, ssa_rows, _ssa_bodies, auth_rows, cross_pkg_imports) =
crate::ast::extract_all_summaries_from_bytes(&bytes, file_path, config, None)
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
@ -1640,6 +1656,9 @@ pub fn analyse_file_summaries(
for (key, auth_summary) in auth_rows {
global.insert_auth(key, auth_summary);
}
if let Some((ns, map)) = cross_pkg_imports {
global.insert_cross_package_imports(ns, map);
}
Ok(global)
}
@ -1883,6 +1902,7 @@ function consume() {
typed_call_receivers: vec![],
validated_params_to_return: smallvec::SmallVec::new(),
param_to_gate_filters: vec![],
entry_kind: None,
},
);
@ -2039,6 +2059,7 @@ async function recentAuditLogs() {
field_writes: std::collections::HashMap::new(),
synthetic_externals: std::collections::HashSet::new(),
slot_scoped_assigns: std::collections::HashSet::new(),
};
let facts = analyse_body(&body, BodyId(0));

View file

@ -169,7 +169,7 @@ impl JobManager {
started_at: Some(chrono::Utc::now().to_rfc3339()),
finished_at: None,
duration_secs: None,
engine_version: Some(engine_version.clone()),
engine_version: Some(engine_version),
languages: None,
files_scanned: None,
files_skipped: None,
@ -261,7 +261,7 @@ impl JobManager {
let languages: Vec<String> = progress_snap.languages.keys().cloned().collect();
let files_scanned = progress_snap.files_discovered;
let files_skipped = progress_snap.files_skipped;
let timing = progress_snap.timing.clone();
let timing = progress_snap.timing;
let finished_at = chrono::Utc::now();
// Prepare the final state outside the lock.
@ -292,9 +292,9 @@ impl JobManager {
if let Some(job) = jobs.get_mut(&jid) {
job.finished_at = Some(finished_at);
job.duration_secs = Some(elapsed);
job.languages = Some(languages.clone());
job.languages = Some(languages);
job.files_scanned = Some(files_scanned);
job.timing = Some(timing.clone());
job.timing = Some(timing);
job.status = status.clone();
job.findings = diags;
job.error = error_str.clone();
@ -590,7 +590,7 @@ handleRequest({ query: { name: '<b>x</b>' } }, { send() {} });
let id = manager
.start_scan(
project_dir.clone(),
project_dir,
test_config(),
tx,
Some(Arc::clone(&pool)),

View file

@ -161,7 +161,7 @@ async fn add_rule(
.or_default();
let new_rule = crate::utils::config::ConfigLabelRule {
matchers: rule.matchers.clone(),
matchers: rule.matchers,
kind: rule_kind,
cap: cap_name,
case_sensitive: false,
@ -242,7 +242,7 @@ async fn add_terminator(
.entry(term.lang.clone())
.or_default();
if !lang_cfg.terminators.contains(&term.name) {
lang_cfg.terminators.push(term.name.clone());
lang_cfg.terminators.push(term.name);
}
}

View file

@ -447,6 +447,7 @@ mod tests {
typed_call_receivers: vec![],
validated_params_to_return: smallvec::SmallVec::new(),
param_to_gate_filters: vec![],
entry_kind: None,
},
)],
)
@ -520,6 +521,7 @@ mod tests {
field_writes: std::collections::HashMap::new(),
synthetic_externals: std::collections::HashSet::new(),
slot_scoped_assigns: std::collections::HashSet::new(),
},
false,
false,
@ -544,6 +546,7 @@ mod tests {
field_writes: std::collections::HashMap::new(),
synthetic_externals: std::collections::HashSet::new(),
slot_scoped_assigns: std::collections::HashSet::new(),
},
true,
true,
@ -568,6 +571,7 @@ mod tests {
field_writes: std::collections::HashMap::new(),
synthetic_externals: std::collections::HashSet::new(),
slot_scoped_assigns: std::collections::HashSet::new(),
},
true,
false,
@ -666,6 +670,7 @@ mod tests {
typed_call_receivers: vec![],
validated_params_to_return: smallvec::SmallVec::new(),
param_to_gate_filters: vec![],
entry_kind: None,
},
)],
)

View file

@ -149,7 +149,7 @@ async fn overview(State(state): State<AppState>) -> Json<OverviewResponse> {
latest_scan_id,
latest_scan_at,
by_severity: summary.by_severity.clone(),
by_category: summary.by_category.clone(),
by_category: summary.by_category,
by_language,
top_files,
top_directories,

View file

@ -309,13 +309,12 @@ async fn get_scan_findings(
let per_page = query.per_page.unwrap_or(50).min(200);
let start = (page - 1) * per_page;
let scan_root = state.scan_root.clone();
let page_findings: Vec<FindingView> = filtered
.into_iter()
.enumerate()
.skip(start)
.take(per_page)
.map(|(i, d)| models::finding_from_diag_with_context(i, d, &scan_root))
.map(|(i, d)| models::finding_from_diag_with_context(i, d, &state.scan_root))
.collect();
Ok(Json(serde_json::json!({
@ -361,8 +360,6 @@ async fn compare_scans(
.push((i, d));
}
let scan_root = state.scan_root.clone();
let mut new_findings = Vec::new();
let mut fixed_findings = Vec::new();
let mut changed_findings = Vec::new();
@ -378,7 +375,7 @@ async fn compare_scans(
for i in 0..matched {
let (idx, diag) = right_group[i];
let (_, left_diag) = left_group[i];
let view = models::finding_from_diag_with_context(idx, diag, &scan_root);
let view = models::finding_from_diag_with_context(idx, diag, &state.scan_root);
let changes = compute_field_changes(left_diag, diag);
if changes.is_empty() {
unchanged_findings.push(ComparedFinding {
@ -397,7 +394,7 @@ async fn compare_scans(
for &(idx, diag) in &right_group[matched..] {
new_findings.push(ComparedFinding {
fingerprint: fp.clone(),
finding: models::finding_from_diag_with_context(idx, diag, &scan_root),
finding: models::finding_from_diag_with_context(idx, diag, &state.scan_root),
});
}
} else {
@ -405,7 +402,7 @@ async fn compare_scans(
for &(idx, diag) in right_group {
new_findings.push(ComparedFinding {
fingerprint: fp.clone(),
finding: models::finding_from_diag_with_context(idx, diag, &scan_root),
finding: models::finding_from_diag_with_context(idx, diag, &state.scan_root),
});
}
}
@ -419,7 +416,7 @@ async fn compare_scans(
for &(idx, diag) in &left_group[start..] {
fixed_findings.push(ComparedFinding {
fingerprint: fp.clone(),
finding: models::finding_from_diag_with_context(idx, diag, &scan_root),
finding: models::finding_from_diag_with_context(idx, diag, &state.scan_root),
});
}
}