Skip to content

Detector Development Guide

Detectors scan project files for patterns related to CRA requirements and produce findings. Each detector handles one or more requirement ID prefixes (e.g., CRYPTO-*, NET-*).

src/assessment/detect.rs
pub trait Detector: Send + Sync {
/// Human-readable name (e.g., "crypto", "network")
fn name(&self) -> &str;
/// Requirement ID prefixes this detector handles (e.g., ["CRYPTO-"])
fn handles_prefixes(&self) -> &[&str];
/// Run detection against the project
fn detect(
&self,
catalog: &CatalogIndex,
context: &ProjectContext,
files: &ProjectFiles,
) -> Vec<Finding>;
}
src/assessment/detectors/my_detector.rs
use regex::Regex;
use crate::assessment::catalog::CatalogIndex;
use crate::assessment::detect::*;
pub struct MyDetector;
impl Detector for MyDetector {
fn name(&self) -> &str { "my_detector" }
fn handles_prefixes(&self) -> &[&str] { &["MYPREFIX-"] }
fn detect(
&self,
_catalog: &CatalogIndex,
_context: &ProjectContext,
files: &ProjectFiles,
) -> Vec<Finding> {
let mut findings = Vec::new();
for (relative, content) in super::walk_source_files(files.root()) {
// Your detection logic here
let pattern = Regex::new(r"dangerous_function\(").unwrap();
for (line_num, line) in content.lines().enumerate() {
if pattern.is_match(line) {
findings.push(Finding {
requirement_id: "MYPREFIX-01-R1".to_string(),
risk_id: "MYPREFIX-01".to_string(),
status: FindingStatus::Fail,
confidence: 0.80,
detector: "my_detector".to_string(),
message: "Dangerous function usage detected".to_string(),
source_locations: vec![SourceLocation {
file: relative.clone(),
line: line_num + 1,
snippet: line.trim().to_string(),
}],
});
}
}
}
findings
}
}
pub mod my_detector;
pub fn register_all(registry: &mut DetectorRegistry) {
// ... existing detectors ...
registry.register(Box::new(my_detector::MyDetector));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn detects_dangerous_function() {
// Test with inline code string
}
#[test]
fn ignores_safe_code() {
// Verify no false positives
}
}

The detectors/mod.rs provides helpers:

Helper Purpose
walk_source_files(root) Yields (relative_path, content) for all source + config files
is_source_file(path) Check if file extension is a recognized source language
is_config_file(path) Check if file is a config file (yml, toml, json, env, Dockerfile)
should_skip_dir(name) Check if directory should be skipped (node_modules, .git, etc.)
Status When to Use
FindingStatus::Pass Scanner can confirm the requirement is satisfied
FindingStatus::Fail Scanner detects a clear violation
FindingStatus::NeedsReview Pattern detected but human/LLM judgment needed
FindingStatus::NotApplicable Requirement doesn’t apply (e.g., no AI usage -> AI-* is N/A)
Range Meaning
0.90 - 1.00 High confidence — clear pattern match (e.g., security.txt exists)
0.70 - 0.89 Good confidence — strong pattern match (e.g., MD5 usage in security context)
0.50 - 0.69 Moderate — pattern match but context uncertain
0.30 - 0.49 Low — heuristic match, likely needs review
< 0.30 Very low — speculative
  1. Use r#""# for regex with quotes: Rust’s regex crate doesn’t support look-ahead ((?!...)). Use post-match filtering instead.

  2. Skip comments: Always filter out comment lines before matching.

  3. Skip test files: Don’t flag patterns in test code unless relevant.

  4. Redact secrets: If a finding involves credentials, use [REDACTED] in the snippet.

  5. Use NeedsReview generously: When in doubt, flag for review rather than auto-passing or auto-failing.

Detector File Prefixes Key Patterns
crypto crypto.rs CRYPTO- Weak algorithms, hardcoded keys, insecure PRNG
network network.rs NET- Hardcoded credentials, HTTP URLs, API keys, debug endpoints
auth auth.rs AUTH- Password logging, JWT alg:none, token logging
input input.rs INPUT-, UPLOAD- Command injection, SQL construction, path traversal
storage storage.rs STOR- Public buckets, hardcoded encryption keys
update update.rs UPD- HTTP update channels, hash/signature verification
logging logging.rs LOG- Passwords/tokens in logs, structured logging
supply_chain supply_chain.rs SBOM-, OSS-, etc. Lockfiles, vendored dirs, CI vuln scanning
config config.rs CONFIG- Default passwords, debug mode, verbose errors
vuln_handling vuln_handling.rs VH- security.txt, SECURITY.md, disclosure policy
ai ai.rs AI- ML frameworks, prompt injection, model loading