from .models import Finding, FindingGuidance, Severity _RULES: dict[str, tuple[str, str, str, str]] = { "security.secret-assignment": ( "security remediation", "A credential-shaped assignment was found in tracked content.", "Move the value to a secret store or runtime environment and rotate it if it was genuine.", "high", ), "security.env-committed": ( "security remediation", "A live environment file is tracked, so its contents require deliberate review.", "Remove the live file from version control and retain a sanitized .env.example template.", "high", ), "testing.none-detected": ( "test coverage", "No conventionally named test source was detected for a repository with source files.", "Add a focused deterministic smoke test, or record a repository policy that explains why tests do not apply.", "medium", ), "testing.no-ci": ( "delivery evidence", "No repository workflow was found that contains a validation command.", "Add a CI validation workflow that runs the repository's deterministic checks.", "medium", ), "dependency.no-lockfile": ( "dependency reproducibility", "A JavaScript manifest was found without a lockfile in its package or workspace root.", "Commit the package-manager lockfile used by the build.", "high", ), "hygiene.missing-gitignore": ( "repository hygiene", "The repository has no root ignore policy.", "Add a minimal .gitignore for generated files, local settings and build outputs.", "high", ), } def _default_rule(finding: Finding) -> tuple[str, str, str, str]: if finding.code.startswith("dependency."): return ( "dependency hygiene", "The dependency declaration has a deterministic hygiene signal.", "Review the declared version and lockfile semantics, then make the smallest reproducible correction.", "medium", ) if finding.code.startswith("architecture."): return ( "architecture review", "The bounded static graph has a structural signal.", "Inspect the affected module boundary before planning a contained refactor.", "medium", ) return ( "engineering hygiene", "A deterministic repository rule produced this signal.", "Review the retained evidence and make the smallest safe correction.", "medium", ) def enrich_finding(finding: Finding) -> Finding: remediation_class, why, action, confidence = _RULES.get(finding.code, _default_rule(finding)) severity_weight = {Severity.BLOCKER: 700, Severity.WARNING: 400, Severity.INFO: 100}[finding.severity] priority = min(1000, severity_weight + finding.deduction * 5) rationale = f"{finding.severity.value.title()} signal; {finding.deduction} health-point impact." guidance = FindingGuidance( remediation_class=remediation_class, confidence=confidence, why=why, recommended_action=action, priority=priority, priority_rationale=rationale, ) return finding.model_copy(update={"guidance": guidance}) def enrich_findings(findings: list[Finding]) -> list[Finding]: return [enrich_finding(item) for item in findings]