Files

84 lines
3.3 KiB
Python

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]