The global pre-push hook, the /sh-security-review prompt, and finding.schema.json previously lived only in ~/.config/git and ~/.claude (untracked) — unreproducible. Source them here: add hooks/pre-push, rewrite install-hooks.sh with a --global mode (lays down both hooks, sets core.hooksPath, links skill+schema into ~/.claude) and a per-repo mode. Align pre-commit with pre-push (honor skip marker + suppressions). Add semgrep p/javascript so the scanners cover the org's Node/.NET repos.
69 lines
3 KiB
JSON
69 lines
3 KiB
JSON
{
|
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
"title": "Sea Haven security-review finding",
|
|
"description": "Structured finding contract for /sh-security-review. Same shape for interactive (Path A) and automated (Path B) runs, and the input review.sh reads to make the block decision.",
|
|
"type": "object",
|
|
"required": ["findings", "summary"],
|
|
"properties": {
|
|
"findings": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"required": ["id", "title", "severity", "cwe", "file", "category", "data_flow", "proof", "status"],
|
|
"properties": {
|
|
"id": { "type": "string", "description": "stable slug, e.g. sqli-payment-handler-get-payment" },
|
|
"title": { "type": "string" },
|
|
"severity": {
|
|
"type": "string",
|
|
"enum": ["critical", "high", "medium", "low", "info", "unverified"],
|
|
"description": "unverified = a claim with no accepted proof; auto-downgraded from its claimed severity"
|
|
},
|
|
"claimed_severity": {
|
|
"type": "string",
|
|
"enum": ["critical", "high", "medium", "low", "info"],
|
|
"description": "the detector's original severity before the verifier ruled"
|
|
},
|
|
"cwe": { "type": "string", "pattern": "^CWE-[0-9]+$" },
|
|
"file": { "type": "string" },
|
|
"line": { "type": ["integer", "null"] },
|
|
"category": {
|
|
"type": "string",
|
|
"enum": ["injection", "authz", "secrets-crypto", "iac-iam", "web-client", "logic", "other"]
|
|
},
|
|
"data_flow": {
|
|
"type": "string",
|
|
"description": "numbered plain-English trace from untrusted source to dangerous sink"
|
|
},
|
|
"proof": {
|
|
"type": "object",
|
|
"required": ["input", "outcome"],
|
|
"properties": {
|
|
"input": { "type": "string", "description": "concrete malicious input / trigger" },
|
|
"outcome": { "type": "string", "description": "the specific bad result it produces" },
|
|
"test": { "type": ["string", "null"], "description": "optional failing-test sketch" }
|
|
}
|
|
},
|
|
"status": {
|
|
"type": "string",
|
|
"enum": ["confirmed", "unverified", "suppressed"],
|
|
"description": "confirmed = verifier accepted proof; unverified = no accepted proof; suppressed = dismissed with justification"
|
|
},
|
|
"suppression_justification": {
|
|
"type": ["string", "null"],
|
|
"description": "REQUIRED when status=suppressed; logged and surfaced in the report"
|
|
},
|
|
"recommendation": { "type": "string" }
|
|
}
|
|
}
|
|
},
|
|
"summary": {
|
|
"type": "object",
|
|
"required": ["confirmed_critical", "confirmed_high", "block"],
|
|
"properties": {
|
|
"confirmed_critical": { "type": "integer" },
|
|
"confirmed_high": { "type": "integer" },
|
|
"block": { "type": "boolean", "description": "true if any confirmed critical/high is unsuppressed (the gate condition)" }
|
|
}
|
|
}
|
|
}
|
|
}
|