Documentation
¶
Overview ¶
Package security implements the opt-in deterministic security gate (spec 05). It scans the operator's own tracked files for accidentally committed secrets, prompt-injection payloads, and typosquatted dependencies. Every scanner is a pure function of tracked file contents + embedded rule data + the allowlist: no network, no LLM, stable finding order (R7).
Index ¶
- Constants
- func AppendException(root string, e Exception) error
- func ConfigForPolicy(cfg core.SecurityConfig, p PolicyV1) core.SecurityConfig
- func ExceptionDigest(raw []byte) string
- func GateFindings(result Result) []gates.Finding
- func LoadExceptions(root, revision, environment string, now time.Time) (ExceptionSet, []Finding)
- func ManifestDigest(root string) (string, error)
- func ValidateException(e Exception) error
- type DeclaredDep
- type DepEvidenceItem
- type DepEvidenceV1
- type DependencyPolicy
- type Exception
- type ExceptionSet
- type Finding
- type Gate
- type PolicyV1
- type RegressionCorpusV1
- type RegressionExpectedV1
- type RegressionIncidentV1
- type RegressionInputV1
- type RegressionTrend
- type Result
- type ScanInputV1
- type ScanKind
- type Scanner
- type TrackedFile
Constants ¶
const DepEvidenceSchema = "dep-evidence/v1"
DepEvidenceSchema pins the version of the offline adapter artifact this gate accepts. External vulnerability/provenance facts arrive as a pinned artifact produced out of band (scripts/dep-evidence.sh); the gate itself never touches the network — it validates and projects the pinned bytes (R6.2).
const PolicyVersion = "1"
const RegressionSchemaV1 = "security-regression/v1"
Variables ¶
This section is empty.
Functions ¶
func AppendException ¶ added in v0.4.0
func ConfigForPolicy ¶ added in v0.4.0
func ConfigForPolicy(cfg core.SecurityConfig, p PolicyV1) core.SecurityConfig
func ExceptionDigest ¶ added in v0.4.0
func GateFindings ¶
GateFindings projects an analysis Result to gate findings: allowlisted and off findings drop out; error/warn map to gate severities.
func LoadExceptions ¶ added in v0.4.0
func LoadExceptions(root, revision, environment string, now time.Time) (ExceptionSet, []Finding)
func ManifestDigest ¶ added in v0.4.0
ManifestDigest is the sha256 over the concatenated manifest bytes (go.mod then go.sum, each skipped when absent). It matches `cat go.mod go.sum | sha256sum` so scripts/dep-evidence.sh and this gate pin the same manifest state.
func ValidateException ¶ added in v0.4.0
Types ¶
type DeclaredDep ¶ added in v0.4.0
DeclaredDep is the operator's approved reason/source for one dependency, declared out of band (e.g. .specd/security/dependencies.json). Both fields are required — a dependency without a stated reason and a stated source is treated as unapproved (R6.1).
type DepEvidenceItem ¶ added in v0.4.0
type DepEvidenceItem struct {
Module string `json:"module"`
Severity string `json:"severity"`
Advisory string `json:"advisory"`
Summary string `json:"summary"`
}
DepEvidenceItem is one advisory/provenance fact from the pinned artifact.
type DepEvidenceV1 ¶ added in v0.4.0
type DepEvidenceV1 struct {
Schema string `json:"schema"`
GeneratedAt string `json:"generated_at"`
ManifestDigest string `json:"manifest_digest"`
Findings []DepEvidenceItem `json:"findings"`
}
DepEvidenceV1 is the offline dependency-evidence artifact. ManifestDigest ties the artifact to the exact manifests it was produced for: a mismatch means the evidence is stale and fails closed.
type DependencyPolicy ¶ added in v0.4.0
type DependencyPolicy struct {
Profile string
RegistryAllowlist []string
Declared map[string]DeclaredDep
}
DependencyPolicy governs the manifest-diff dependency gate. Profile selects finding severity (production → error, otherwise warn). RegistryAllowlist lists approved module path prefixes; empty means the host check is not enforced. Declared is the approved baseline — a dependency absent here is "new" and must carry a reason/source before it is allowed.
type Exception ¶ added in v0.4.0
type Exception struct {
Finding string `json:"finding"`
Action string `json:"action"`
Reason string `json:"reason"`
Ticket string `json:"ticket"`
Owner string `json:"owner"`
Scope string `json:"scope"`
Revision string `json:"revision"`
Environment string `json:"environment"`
IssuedAt string `json:"issued_at"`
ExpiresAt string `json:"expires_at"`
CompensatingControl string `json:"compensating_control"`
Approver string `json:"approver"`
}
Exception is one immutable, governed suppression record. Revocation is a new record with Action="revoke" and the same Finding; prior records remain audit history in the append-only JSONL ledger.
type ExceptionSet ¶ added in v0.4.0
type ExceptionSet struct {
Records []Exception
Digest string
// contains filtered or unexported fields
}
func (ExceptionSet) Allows ¶ added in v0.4.0
func (s ExceptionSet) Allows(finding string) bool
type Finding ¶
type Finding struct {
Scanner string `json:"scanner"`
Rule string `json:"rule"`
File string `json:"file"`
Line int `json:"line"`
Fingerprint string `json:"fingerprint"`
Excerpt string `json:"excerpt"`
// Severity is filled by the gate from config; empty until resolved.
Severity string `json:"severity,omitempty"`
// Allowlisted is set by the gate when an allow.json entry suppresses the
// finding. Recorded (not dropped) so reports show what was waived (R6).
Allowlisted bool `json:"allowlisted,omitempty"`
}
Finding is one scanner hit before severity resolution. Fingerprint pins the finding to (rule + path + matched content) so a reasoned allowlist entry survives the match moving lines but is invalidated by editing the match (R2). Excerpt is always redacted — a secrets scanner that prints secrets into CI logs creates the leak it exists to prevent (R1).
func ScanDangerous ¶ added in v0.4.0
ScanDangerous runs deterministic dangerous-change policies over a normalized diff (R6.3): destructive shell fragments, world-writable / unexpected-exec mode changes, auth/ownership policy changes, generated secret files, and symlink escapes. Profile selects severity (production → error); generated secrets and symlink escapes always fail closed at error. False positives are controlled by scanning only added/changed files, targeted patterns, script extension carve-outs, and the fingerprint allowlist reused by the caller.
func ScanDepEvidence ¶ added in v0.4.0
ScanDepEvidence validates a pinned offline artifact against the current manifest digest and projects its advisories to findings. Malformed, wrong schema, and stale (digest mismatch) all fail closed at error severity — the gate never trusts unvalidated or outdated supply-chain evidence.
func ScanManifest ¶ added in v0.4.0
func ScanManifest(files []TrackedFile, policy DependencyPolicy) []Finding
ScanManifest runs the dependency policy over the given manifests/lockfiles.
type Gate ¶
type Gate struct {
// contains filtered or unexported fields
}
Gate is the opt-in security gate registered by `check --security`. It scans tracked files and resolves per-scanner severity from config.
func New ¶
func New(cfg core.SecurityConfig) Gate
New builds the gate with the resolved per-scanner severity config.
type PolicyV1 ¶ added in v0.4.0
type PolicyV1 struct {
PolicyVersion string `json:"policy_version"`
Profile string `json:"profile"`
ScannerSeverities map[string]string `json:"scanner_severities"`
RequiredGates []string `json:"required_gates"`
SandboxRequired bool `json:"sandbox_required"`
NetworkDefault string `json:"network_default"`
PolicyDigest string `json:"policy_digest"`
}
func ResolvePolicy ¶ added in v0.4.0
func ResolvePolicy(cfg core.SecurityConfig) (PolicyV1, error)
type RegressionCorpusV1 ¶ added in v0.4.0
type RegressionCorpusV1 struct {
SchemaVersion string `json:"schema_version"`
PolicyDigest string `json:"policy_digest"`
Incidents []RegressionIncidentV1 `json:"incidents"`
}
func LoadIncidentCorpus ¶ added in v0.4.0
func LoadIncidentCorpus(path, policyDigest string) (RegressionCorpusV1, error)
LoadIncidentCorpus validates promoted incident attestations offline. Policy digest mismatch makes the entire corpus stale; partial reuse is forbidden.
func (RegressionCorpusV1) Trend ¶ added in v0.4.0
func (c RegressionCorpusV1) Trend() []RegressionTrend
type RegressionExpectedV1 ¶ added in v0.4.0
type RegressionIncidentV1 ¶ added in v0.4.0
type RegressionIncidentV1 struct {
ID string `json:"id"`
Provenance string `json:"provenance"`
Input RegressionInputV1 `json:"input"`
Expected RegressionExpectedV1 `json:"expected"`
}
type RegressionInputV1 ¶ added in v0.4.0
type RegressionTrend ¶ added in v0.4.0
type Result ¶
type Result struct {
Findings []Finding
}
Result is the full analysis: every scanner finding with severity resolved and allowlist status stamped. Consumed by the gate (for pass/fail) and by the caller (for recording under state.security).
type ScanInputV1 ¶ added in v0.4.0
type ScanInputV1 struct {
Root string `json:"root,omitempty"`
ItemRef string `json:"item_ref"`
Path string `json:"path"`
Kind ScanKind `json:"kind"`
Trust string `json:"trust"`
Digest string `json:"digest"`
Content []byte `json:"-"`
}
ScanInputV1 identifies exact bytes crossing the scanner trust boundary.
func NewScanInput ¶ added in v0.4.0
func NewScanInput(ref string, kind ScanKind, trust string, content []byte) ScanInputV1
type ScanKind ¶ added in v0.4.0
type ScanKind string
const ( ScanKindSpec ScanKind = "spec" ScanKindSteering ScanKind = "steering" ScanKindRole ScanKind = "role" ScanKindMemory ScanKind = "memory" ScanKindSource ScanKind = "source" ScanKindUntracked ScanKind = "untracked" ScanKindToolResult ScanKind = "tool_result" TrustTrustedInstruction = "trusted_instruction" TrustUntrustedData = "untrusted_data" )
type Scanner ¶
type Scanner interface {
Name() string
Exclude(input ScanInputV1) bool
Scan(files []ScanInputV1) []Finding
}
Scanner is the pure contract every detector satisfies. Scan must return findings in a stable order for identical input.
type TrackedFile ¶
type TrackedFile = ScanInputV1
TrackedFile keeps existing scanner fixtures source-compatible.