Documentation
¶
Overview ¶
Package detect is the pure, dependency-free secret-detection engine behind Hanzo's native code-security surface. It scans source for hardcoded secrets with zero external tooling (no semgrep/gitleaks binary, no network) — the one Semgrep-class capability that ships complete today. The logic ports the concept behind hanzoai/guard (the LLM-boundary redactor) to code at rest, and is the substrate a native AST/SAST engine (on hanzoai/ast) grows onto per the plan of record in hanzoai/security POSTURE.md.
It is deliberately a LEAF: only the standard library is imported, and the API is pure functions over (path, content) → findings — no I/O, no store, no HTTP, no cloud deps. That decomplection is the point: the HTTP subsystem (clients/security) AND the `hanzo security scan` CLI both consume THIS engine, so the detection logic exists once and neither surface drags the other in.
THE ONE INVARIANT: a Finding NEVER carries the raw secret. It carries a masked preview (first/last few chars, middle starred) plus a SHA-256 fingerprint of the secret — enough to locate it, dedupe identical occurrences, and confirm a rotation happened, and nothing more. Persisting the plaintext would make the findings DB a secret store, exactly the thing we scan to prevent (global rule: never store secrets in the clear).
Index ¶
Constants ¶
const ( SeverityCritical = "critical" SeverityHigh = "high" SeverityMedium = "medium" SeverityLow = "low" )
Severity ranks a finding. Ordered so higher is worse; used for sorting and for the /v1/security/findings?minSeverity filter.
Variables ¶
This section is empty.
Functions ¶
func Fingerprint ¶
Fingerprint is the hex SHA-256 of a raw secret. Identical secrets across files/scans share a fingerprint (dedupe + rotation tracking); the original is not recoverable from it.
func RuleCount ¶
func RuleCount() int
RuleCount is the number of detection rules in the catalog (for health/log lines that report engine size without materializing the catalog).
func SeveritiesAtOrAbove ¶
SeveritiesAtOrAbove returns the severity names ranked >= min (unordered), so a store can build an `IN (...)` filter without reaching into the rank map. An unknown min yields every severity (rank 0 floor), which is the safe "no filter" behavior.
func SeverityRank ¶
SeverityRank exposes the ordering for callers that filter/sort findings.
Types ¶
type Finding ¶
type Finding struct {
RuleID string
RuleName string
Severity string
Path string
Line int
Preview string // masked: first/last chars kept, middle starred
Fingerprint string // hex SHA-256 of the raw secret — dedupe/rotation key
}
Finding is one detected secret. It is the redacted, storable record — it pins WHERE (path, line) and WHAT rule fired, and carries a masked Preview plus the SHA-256 Fingerprint of the raw secret, never the secret itself.
func ScanContent ¶
ScanContent runs every rule over one file's content and returns the findings, most severe first (then by line). It is pure and allocation-light: no I/O, safe to call concurrently. Path is echoed into each finding for locating; it is not read from disk. Findings are de-duplicated within the file by (rule, line, fingerprint) so a rule matching the same secret twice on one line yields one finding. (Named ScanContent, not Scan, so the engine entry point never collides with the store's Scan record type.)
type Rule ¶
type Rule struct {
ID string
Name string
Severity string
Description string
// contains filtered or unexported fields
}
Rule is one secret-detection pattern. A rule is EITHER a direct regex whose whole match is the secret (Pattern, with an optional Group capturing the secret sub-match), OR — when MinEntropy > 0 — an assignment rule that only fires when the captured value's Shannon entropy clears the threshold, which is how generic `secret = "..."` lines avoid flagging every lowercase word.