Skip to content

Commit effaf17

Browse files
montfortclaude
andauthored
fix: reduce false positives in validate REF-001 and SEC-001 rules (#38)
REF-001: Only validate related: references that look like DevTrail document IDs (AILOG-*, AIDEC-*, ADR-*, etc.). Skip task IDs (T025), requirement IDs (FR-019, US2), risk IDs (RISK-001), external paths, and other non-document references that caused noisy false positives. SEC-001: Move 'Bearer' and 'token:' from hard errors to soft warnings, since these patterns are common in documentation describing auth flows. Actual secret patterns (password:, api_key:, PRIVATE KEY, etc.) remain as errors. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 0ad9ede commit effaf17

1 file changed

Lines changed: 40 additions & 3 deletions

File tree

cli/src/validation.rs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,18 @@ const VALID_RISK_LEVELS: &[&str] = &["low", "medium", "high", "critical"];
4949
/// Valid confidence levels
5050
const VALID_CONFIDENCES: &[&str] = &["low", "medium", "high"];
5151

52-
/// Patterns that indicate sensitive information
52+
/// Patterns that indicate sensitive information.
53+
/// These are checked against the document body. Patterns should be specific enough
54+
/// to avoid false positives in documentation that describes auth flows.
5355
const SENSITIVE_PATTERNS: &[&str] = &[
54-
"password:", "api_key:", "secret:", "token:", "private_key:",
55-
"credentials:", "Bearer ", "AWS_SECRET", "PRIVATE KEY",
56+
"password:", "api_key:", "secret:", "private_key:",
57+
"credentials:", "AWS_SECRET", "PRIVATE KEY",
58+
];
59+
60+
/// Patterns that are suspicious but common in documentation describing auth flows.
61+
/// These produce warnings instead of errors.
62+
const SOFT_SENSITIVE_PATTERNS: &[&str] = &[
63+
"token:", "Bearer ",
5664
];
5765

5866
/// Validate all documents found under a .devtrail/ directory
@@ -489,12 +497,20 @@ fn check_type_specific(result: &mut ValidationResult, doc: &DevTrailDocument) {
489497
}
490498

491499
/// REF-001: Check that documents listed in related: exist
500+
/// Only validates references that look like DevTrail document IDs (e.g., AILOG-2025-01-27-001).
501+
/// Skips task IDs (T025), requirement IDs (FR-019, US2), risk IDs (RISK-001),
502+
/// external paths, and other non-document references to avoid false positives.
492503
fn check_related_exist(result: &mut ValidationResult, doc: &DevTrailDocument, devtrail_dir: &Path) {
493504
if let Some(related) = &doc.frontmatter.related {
494505
for rel_id in related {
495506
if rel_id.is_empty() {
496507
continue;
497508
}
509+
// Only validate references that look like DevTrail document IDs
510+
// (start with a known document type prefix followed by a dash)
511+
if !looks_like_devtrail_id(rel_id) {
512+
continue;
513+
}
498514
// Search for a file matching this id
499515
if !find_document_by_id(devtrail_dir, rel_id) {
500516
result.add(ValidationIssue {
@@ -509,6 +525,15 @@ fn check_related_exist(result: &mut ValidationResult, doc: &DevTrailDocument, de
509525
}
510526
}
511527

528+
/// Check if a reference looks like a DevTrail document ID.
529+
/// Matches patterns like "AILOG-2025-01-27-001" or "ADR-2025-01-27-001-title".
530+
/// Returns false for task IDs (T025), requirement IDs (FR-019, US2), paths, etc.
531+
fn looks_like_devtrail_id(id: &str) -> bool {
532+
DocType::ALL_PREFIXES.iter().any(|prefix| {
533+
id.starts_with(prefix) && id.get(prefix.len()..prefix.len() + 1) == Some("-")
534+
})
535+
}
536+
512537
/// META-004: Check that filename date matches created field
513538
fn check_date_consistency(result: &mut ValidationResult, doc: &DevTrailDocument) {
514539
let Some(created) = &doc.frontmatter.created else {
@@ -570,6 +595,18 @@ fn check_sensitive_info(result: &mut ValidationResult, doc: &DevTrailDocument) {
570595
});
571596
}
572597
}
598+
// Soft patterns: common in auth documentation, warn instead of error
599+
for pattern in SOFT_SENSITIVE_PATTERNS {
600+
if full_content.contains(pattern) {
601+
result.add(ValidationIssue {
602+
file: doc.path.clone(),
603+
rule: "SEC-001".to_string(),
604+
message: format!("Review for sensitive information: '{}' (may be documentation context)", pattern.trim()),
605+
severity: Severity::Warning,
606+
fix_hint: Some("Verify this is documentation context, not an actual secret".to_string()),
607+
});
608+
}
609+
}
573610
}
574611

575612
/// OBS-001: If document has tag 'observabilidad' or 'observability', check for relevant sections

0 commit comments

Comments
 (0)