use std::collections::HashMap;
use std::path::PathBuf;
use crate::models::{AnalysisContext, Comparison, Score};
#[derive(Debug, Clone)]
pub struct Finding {
pub id: FindingId,
pub suspect: SuspectValue,
pub location: SourceLocation,
pub usage: Option<Usage>,
pub context: AnalysisContext,
pub score: Score,
pub explanation: String,
pub remediation: Option<String>,
pub metadata: HashMap<String, String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FindingId(pub String);
impl FindingId {
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
pub fn generate(location: &SourceLocation, name: &str) -> Self {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
location.file.hash(&mut hasher);
location.line.hash(&mut hasher);
name.hash(&mut hasher);
Self(format!("SEC-{:016x}", hasher.finish()))
}
}
#[derive(Debug, Clone)]
pub enum SuspectValue {
Constant {
name: String,
value: String,
type_annotation: Option<String>,
},
Static {
name: String,
value: String,
is_mut: bool,
},
InlineLiteral { value: String },
EnvDefault {
var_name: String,
default_value: String,
},
}
impl SuspectValue {
pub fn name(&self) -> Option<&str> {
match self {
Self::Constant { name, .. } => Some(name),
Self::Static { name, .. } => Some(name),
Self::InlineLiteral { .. } => None,
Self::EnvDefault { var_name, .. } => Some(var_name),
}
}
pub fn value(&self) -> &str {
match self {
Self::Constant { value, .. } => value,
Self::Static { value, .. } => value,
Self::InlineLiteral { value } => value,
Self::EnvDefault { default_value, .. } => default_value,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SourceLocation {
pub file: PathBuf,
pub line: u32,
pub column: u32,
pub span_start: usize,
pub span_end: usize,
}
impl SourceLocation {
pub fn new(file: PathBuf, line: u32, column: u32) -> Self {
Self {
file,
line,
column,
span_start: 0,
span_end: 0,
}
}
pub fn from_span(file: PathBuf, span: proc_macro2::Span) -> Self {
let start = span.start();
Self {
file,
line: start.line as u32,
column: start.column as u32,
span_start: 0,
span_end: 0,
}
}
}
#[derive(Debug, Clone)]
pub enum Usage {
Comparison(Comparison),
FunctionArgument {
function_name: String,
argument_position: usize,
},
MethodArgument {
receiver: String,
method_name: String,
argument_position: usize,
},
ReturnValue { function_name: String },
StructFieldInit {
struct_name: Option<String>,
field_name: String,
},
FieldAssignment {
struct_name: Option<String>,
field_name: String,
},
MatchArm {
match_arm_index: usize,
in_guard: bool,
},
PatternMatch { match_arm_index: usize },
ClosureCapture {
passed_to: Option<String>,
},
ArrayElement {
index: usize,
array_len: usize,
},
MacroArgument {
macro_name: String,
argument_position: usize,
},
BuilderMethod {
method_name: String,
builder_type: Option<String>,
},
Definition,
}