mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-09 19:45:13 +02:00
[pitboss/grind] deferred session-0002 (20260521T201327Z-3848)
This commit is contained in:
parent
159a779f31
commit
d99361cff6
18 changed files with 499 additions and 144 deletions
|
|
@ -1,5 +1,5 @@
|
|||
use crate::commands::scan::Diag;
|
||||
use crate::evidence::{Confidence, Evidence};
|
||||
use crate::evidence::{Confidence, Evidence, VerifyResult, VerifyStatus};
|
||||
use crate::patterns::{FindingCategory, Severity};
|
||||
use crate::utils::path::{DEFAULT_UI_MAX_FILE_BYTES, open_repo_text_file};
|
||||
use serde::Serialize;
|
||||
|
|
@ -26,6 +26,15 @@ pub const VALID_TRIAGE_STATES: &[&str] = &[
|
|||
"fixed",
|
||||
];
|
||||
|
||||
/// Valid dynamic verification states for findings.
|
||||
pub const VALID_DYNAMIC_VERIFICATION_STATES: &[&str] = &[
|
||||
"Confirmed",
|
||||
"NotConfirmed",
|
||||
"Inconclusive",
|
||||
"Unsupported",
|
||||
"Unverified",
|
||||
];
|
||||
|
||||
/// Check if a string is a valid triage state.
|
||||
pub fn is_valid_triage_state(s: &str) -> bool {
|
||||
VALID_TRIAGE_STATES.contains(&s)
|
||||
|
|
@ -64,6 +73,8 @@ pub struct FindingView {
|
|||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub evidence: Option<Evidence>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_verdict: Option<VerifyResult>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub guard_kind: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub rank_reason: Option<Vec<(String, String)>>,
|
||||
|
|
@ -199,6 +210,7 @@ pub struct FilterValues {
|
|||
pub languages: Vec<String>,
|
||||
pub rules: Vec<String>,
|
||||
pub statuses: Vec<String>,
|
||||
pub verification_statuses: Vec<String>,
|
||||
}
|
||||
|
||||
/// Collect distinct filter values from a slice of diagnostics.
|
||||
|
|
@ -209,6 +221,7 @@ pub fn collect_filter_values(findings: &[Diag]) -> FilterValues {
|
|||
let mut languages = BTreeSet::new();
|
||||
let mut rules = BTreeSet::new();
|
||||
let mut statuses = BTreeSet::new();
|
||||
let mut verification_statuses = BTreeSet::new();
|
||||
|
||||
for d in findings {
|
||||
severities.insert(d.severity.as_db_str().to_string());
|
||||
|
|
@ -221,12 +234,16 @@ pub fn collect_filter_values(findings: &[Diag]) -> FilterValues {
|
|||
}
|
||||
rules.insert(d.id.clone());
|
||||
statuses.insert(status_for_diag(d).to_string());
|
||||
verification_statuses.insert(dynamic_status_for_diag(d).unwrap_or("Unverified").to_string());
|
||||
}
|
||||
|
||||
// Always include all valid triage states so the filter dropdown is complete
|
||||
for s in VALID_TRIAGE_STATES {
|
||||
statuses.insert(s.to_string());
|
||||
}
|
||||
for s in VALID_DYNAMIC_VERIFICATION_STATES {
|
||||
verification_statuses.insert(s.to_string());
|
||||
}
|
||||
|
||||
FilterValues {
|
||||
severities: severities.into_iter().collect(),
|
||||
|
|
@ -235,6 +252,7 @@ pub fn collect_filter_values(findings: &[Diag]) -> FilterValues {
|
|||
languages: languages.into_iter().collect(),
|
||||
rules: rules.into_iter().collect(),
|
||||
statuses: statuses.into_iter().collect(),
|
||||
verification_statuses: verification_statuses.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -267,6 +285,24 @@ fn status_for_diag(d: &Diag) -> &'static str {
|
|||
}
|
||||
}
|
||||
|
||||
/// Human-readable dynamic status used by API filters and table rows.
|
||||
pub fn dynamic_status_label(status: VerifyStatus) -> &'static str {
|
||||
match status {
|
||||
VerifyStatus::Confirmed => "Confirmed",
|
||||
VerifyStatus::NotConfirmed => "NotConfirmed",
|
||||
VerifyStatus::Inconclusive => "Inconclusive",
|
||||
VerifyStatus::Unsupported => "Unsupported",
|
||||
}
|
||||
}
|
||||
|
||||
/// Dynamic verification status for a diagnostic, when a verdict exists.
|
||||
pub fn dynamic_status_for_diag(d: &Diag) -> Option<&'static str> {
|
||||
d.evidence
|
||||
.as_ref()
|
||||
.and_then(|ev| ev.dynamic_verdict.as_ref())
|
||||
.map(|verdict| dynamic_status_label(verdict.status))
|
||||
}
|
||||
|
||||
pub(crate) fn is_zero_u64(v: &u64) -> bool {
|
||||
*v == 0
|
||||
}
|
||||
|
|
@ -296,6 +332,10 @@ pub fn finding_from_diag(index: usize, d: &Diag) -> FindingView {
|
|||
triage_note: String::new(),
|
||||
code_context: None,
|
||||
evidence: None,
|
||||
dynamic_verdict: d
|
||||
.evidence
|
||||
.as_ref()
|
||||
.and_then(|ev| ev.dynamic_verdict.clone()),
|
||||
guard_kind: None,
|
||||
rank_reason: None,
|
||||
sanitizer_status: None,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use crate::server::app::{AppState, CachedFindings};
|
|||
use crate::server::error::{ApiError, ApiResult};
|
||||
use crate::server::models::{
|
||||
FilterValues, FindingSummary, FindingView, collect_filter_values, finding_from_diag,
|
||||
finding_from_diag_with_detail, overlay_triage_states, summarize_findings,
|
||||
finding_from_diag_with_detail, dynamic_status_label, overlay_triage_states, summarize_findings,
|
||||
};
|
||||
use axum::extract::{Path, Query, State};
|
||||
use axum::routing::get;
|
||||
|
|
@ -139,6 +139,7 @@ struct FindingsQuery {
|
|||
language: Option<String>,
|
||||
confidence: Option<String>,
|
||||
status: Option<String>,
|
||||
verification: Option<String>,
|
||||
sort_by: Option<String>,
|
||||
sort_dir: Option<String>,
|
||||
page: Option<usize>,
|
||||
|
|
@ -187,6 +188,17 @@ async fn list_findings(
|
|||
let status_lower = status.to_ascii_lowercase();
|
||||
views.retain(|f| f.status.to_ascii_lowercase() == status_lower);
|
||||
}
|
||||
if let Some(ref verification) = query.verification {
|
||||
let verification_lower = verification.to_ascii_lowercase();
|
||||
views.retain(|f| {
|
||||
let status = f
|
||||
.dynamic_verdict
|
||||
.as_ref()
|
||||
.map(|verdict| dynamic_status_label(verdict.status))
|
||||
.unwrap_or("Unverified");
|
||||
status.to_ascii_lowercase() == verification_lower
|
||||
});
|
||||
}
|
||||
if let Some(ref search) = query.search {
|
||||
let needle = search.to_ascii_lowercase();
|
||||
views.retain(|f| {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue