sca

package
v0.2.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2026 License: Apache-2.0 Imports: 60 Imported by: 0

Documentation

Overview

Package sca orchestrates the Software Composition Analysis pipeline. Scope and the engagement authorization window are enforced HERE (the execution layer), before any tool runs – never as a skippable check.

Index

Constants

View Source
const (
	BlindFPTriagePacketSchema     = "synapse-fp-triage-blind-packet-v1"
	BlindFPTriageSubmissionSchema = "synapse-fp-triage-blind-submission-v1"
	BlindFPTriageJoinedSchema     = "synapse-fp-triage-blind-joined-v1"
)
View Source
const (
	AIEvaluationReleaseManifestSchema = "synapse-ai-triage-release-manifest-v1"

	AIEvaluationReleasePromote  = "promote"
	AIEvaluationReleaseRollback = "rollback"
)
View Source
const (
	ScanModeFull            = "full"
	ScanModeVulnerabilities = "vulnerabilities"
	ScanModeLicenses        = "licenses"
)
View Source
const (
	// DetectionComprehensive is the default: every detected vulnerability at/above the floor is an
	// actionable finding (current behavior). DetectionPrecise raises the ACTIONABLE bar – a single-source,
	// uncorroborated, non-KEV vulnerability finding is quarantined into a needs-verify queue (still reported
	// + evidence-sealed, just exempt from the --fail-on gate) rather than dropped, so recall is retained
	// with the lower-confidence set clearly separated. KEV + multi-source findings are never quarantined.
	DetectionComprehensive = "comprehensive"
	DetectionPrecise       = "precise"
)
View Source
const (
	AIEvaluationFeedbackManifestSchema = "synapse-ai-triage-feedback-curation-v1"
)
View Source
const ScanJobKind = "sca"

ScanJobKind is the durable-queue Kind for an SCA scan.

Variables

This section is empty.

Functions

func AIEvaluationFeedbackReviewDigest added in v0.1.8

func AIEvaluationFeedbackReviewDigest(review aitriagereview.Review, manifest AIEvaluationFeedbackManifest, c AIEvaluationFeedbackCase) (string, error)

AIEvaluationFeedbackReviewDigest binds a human review decision to both the exact review snapshot and the manifest header under which the curated context will be used. Both approval steps must cite this digest.

func AIEvaluationReleaseReviewDigest added in v0.1.8

func AIEvaluationReleaseReviewDigest(ledger AIEvaluationReleaseLedger, evidence *AIEvaluationPromotionEvidence, manifest AIEvaluationReleaseManifest) (string, error)

AIEvaluationReleaseReviewDigest returns the exact digest PM and Security approve. It binds the current ledger head, so an approval cannot be replayed after another release decision lands.

func EvaluationPolicyVersion added in v0.1.8

func EvaluationPolicyVersion() string

EvaluationPolicyVersion returns the immutable policy identity for evaluation report metadata without exporting the authorization constant as part of the package API.

func MarshalCycloneDX added in v0.1.8

func MarshalCycloneDX(doc *sbom.SBOM, target string, created time.Time) ([]byte, error)

MarshalCycloneDX renders one SBOM as a deterministic CycloneDX JSON document, without going through an engagement or a store.

It exists so the RELEASE pipeline can emit an SBOM for each published artifact using this project's own engine (#412 req 5). That is deliberately the same code path a customer scan uses: a producer we would not trust to describe our own release has no business describing theirs, and a separate release-only SBOM path would let the two drift without anyone noticing.

func ParseCycloneDXComponents added in v0.2.0

func ParseCycloneDXComponents(data []byte) ([]sbom.Component, error)

ParseCycloneDXComponents returns the components of a CycloneDX document: name, version, PURL and licences, as the import path reads them. Read-side callers (a host's package list) use it to show what an imported SBOM contains without re-running the pipeline.

func ReproDigest

func ReproDigest(res *ScanResult) string

ReproDigest is a stable content fingerprint of a scan's REPRODUCIBLE output (the swappability invariant as a verifiable feature): the SBOM component SET + the promoted findings (with each vuln finding's advisory content – fix version + CVSS vector – folded in), hashed over a canonical (sorted, order-independent) form. It makes reproducibility CHECKABLE – the SAME inputs (same target, pinned SBOM producer, pinned advisory/vuln-DB snapshot) yield the SAME digest; two scans match ⟺ their digests match, and a DIFFERENT advisory DB (new fix version, changed CVSS, new/dropped vuln) changes the digest.

Scope (deliberate): it fingerprints the component SET + finding identity/severity/fix/CVSS – NOT the SBOM dependency-graph EDGES and NOT raw component license strings (denied-license *outcomes* re-enter as their own license findings, so policy results are captured). It EXCLUDES per-run/timestamped data so the digest reflects only what is reproducible: no ToolVersions / VulnDBSnapshot (both embed the scan time / feed-sync date), no finding id (engagement-derived), no Audit timestamps. Field separator is NUL (\x00), which the inputs (PURLs, "vuln:id:component:version" dedup keys, enum kinds/severities) never contain.

It is a provenance/regression fingerprint, NOT a security hash – it carries no secret and proves nothing on its own; a human/CI compares two digests to assert a scan reproduced.

Types

type AIEvaluationCase added in v0.1.8

type AIEvaluationCase struct {
	ID          string            `json:"id"`
	Label       AIEvaluationLabel `json:"label"`
	Language    string            `json:"language"`
	Framework   string            `json:"framework"`
	Adversarial bool              `json:"adversarial,omitempty"`
	// CounterfactualGroup pairs one clean control with one or more adversarially perturbed
	// versions of the same finding. Role is required whenever Group is present.
	CounterfactualGroup string                         `json:"counterfactual_group,omitempty"`
	CounterfactualRole  AIEvaluationCounterfactualRole `json:"counterfactual_role,omitempty"`
	Kind                finding.Kind                   `json:"kind"`
	Severity            shared.Severity                `json:"severity"`
	CWE                 string                         `json:"cwe"`
	Title               string                         `json:"title"`
	Description         string                         `json:"description"`
	File                string                         `json:"file"`
	Line                int                            `json:"line"`
	Source              string                         `json:"source"`
}

AIEvaluationCase contains only synthetic/review-approved source context. It deliberately mirrors the finding fields used by the production prompt and policy, while keeping production scan data out of CI.

type AIEvaluationCaseChange added in v0.1.8

type AIEvaluationCaseChange struct {
	CaseID    string                  `json:"case_id"`
	Label     AIEvaluationLabel       `json:"label"`
	Language  string                  `json:"language"`
	CWE       string                  `json:"cwe"`
	Baseline  AIEvaluationCaseOutcome `json:"baseline"`
	Candidate AIEvaluationCaseOutcome `json:"candidate"`
}

AIEvaluationCaseChange makes model behavior changes reviewable without copying source or prompt text into the comparison artifact.

type AIEvaluationCaseOutcome added in v0.1.8

type AIEvaluationCaseOutcome struct {
	Covered                bool   `json:"covered"`
	ConsensusFalsePositive bool   `json:"consensus_false_positive"`
	WouldGateExempt        bool   `json:"would_gate_exempt"`
	Verdict                string `json:"verdict,omitempty"`
	Driver                 string `json:"driver,omitempty"`
	Confidence             int    `json:"confidence,omitempty"`
	VerifierVerdict        string `json:"verifier_verdict,omitempty"`
	VerifierDriver         string `json:"verifier_driver,omitempty"`
	VerifierConfidence     int    `json:"verifier_confidence,omitempty"`
}

AIEvaluationCaseOutcome is the source-free typed behavior exposed for one changed golden case.

type AIEvaluationComparison added in v0.1.8

type AIEvaluationComparison struct {
	SchemaVersion    string                                             `json:"schema_version"`
	ComparisonID     string                                             `json:"comparison_id"`
	Status           string                                             `json:"status"`
	ApprovalRequired bool                                               `json:"approval_required"`
	DatasetVersion   string                                             `json:"dataset_version"`
	DatasetSHA256    string                                             `json:"dataset_sha256"`
	Provenance       string                                             `json:"provenance"`
	Reviewer         string                                             `json:"reviewer"`
	BaselineRunID    string                                             `json:"baseline_run_id"`
	CandidateRunID   string                                             `json:"candidate_run_id"`
	BaselineRun      AIEvaluationRun                                    `json:"baseline_run"`
	CandidateRun     AIEvaluationRun                                    `json:"candidate_run"`
	Policy           AIEvaluationPromotionPolicy                        `json:"policy"`
	Metrics          AIEvaluationMetricComparison                       `json:"metrics"`
	Robustness       AIEvaluationRobustnessComparison                   `json:"robustness"`
	Breakdowns       map[string]map[string]AIEvaluationMetricComparison `json:"breakdowns"`
	CaseChanges      []AIEvaluationCaseChange                           `json:"case_changes"`
	Failures         []AIEvaluationPromotionFailure                     `json:"failures"`
}

AIEvaluationComparison is deterministic CI evidence for a candidate-vs-baseline decision. A clean comparison has status review_required: automatic promotion is deliberately not represented.

func CompareAIEvaluationReports added in v0.1.8

func CompareAIEvaluationReports(baseline, candidate AIEvaluationReport, policy AIEvaluationPromotionPolicy) (AIEvaluationComparison, error)

CompareAIEvaluationReports compares a candidate against the exact same golden corpus and policy. It rejects apples-to-oranges inputs and returns a deterministic blocked/review_required artifact.

func LoadAIEvaluationComparison added in v0.1.8

func LoadAIEvaluationComparison(data []byte) (AIEvaluationComparison, error)

LoadAIEvaluationComparison strictly decodes and validates comparison identity and status.

func (AIEvaluationComparison) Validate added in v0.1.8

func (c AIEvaluationComparison) Validate() error

Validate rechecks the deterministic comparison identity and promotion-review invariants.

type AIEvaluationCounterfactualRole added in v0.1.8

type AIEvaluationCounterfactualRole string

AIEvaluationCounterfactualRole identifies the reviewed control and adversarial challenge in a semantic-equivalence group. The source may differ, but the finding and human label may not.

const (
	AIEvaluationCounterfactualControl   AIEvaluationCounterfactualRole = "control"
	AIEvaluationCounterfactualChallenge AIEvaluationCounterfactualRole = "challenge"
)

type AIEvaluationDataset added in v0.1.8

type AIEvaluationDataset struct {
	SchemaVersion string             `json:"schema_version"`
	Version       string             `json:"version"`
	Provenance    string             `json:"provenance"`
	Reviewer      string             `json:"reviewer"`
	Cases         []AIEvaluationCase `json:"cases"`
}

AIEvaluationDataset is a versioned, non-production corpus used to measure triage quality. Provenance and reviewer are required so an anonymous or unreviewed label cannot silently become a promotion gate.

func CurateAIEvaluationFeedback added in v0.1.8

func CurateAIEvaluationFeedback(reviews []aitriagereview.Review, manifest AIEvaluationFeedbackManifest) (AIEvaluationDataset, error)

CurateAIEvaluationFeedback converts only doubly-approved review outcomes into a normal evaluation dataset. It has no runtime-policy side effects: callers receive data and must explicitly pass that dataset to the existing evaluation command.

func LoadAIEvaluationDataset added in v0.1.8

func LoadAIEvaluationDataset(data []byte) (AIEvaluationDataset, error)

LoadAIEvaluationDataset decodes and validates a golden dataset.

func (AIEvaluationDataset) Validate added in v0.1.8

func (d AIEvaluationDataset) Validate() error

Validate rejects incomplete or ambiguously labelled datasets before any model call is made.

type AIEvaluationFeedbackApproval added in v0.1.8

type AIEvaluationFeedbackApproval struct {
	Reviewer       string    `json:"reviewer"`
	Approved       bool      `json:"approved"`
	Rationale      string    `json:"rationale"`
	ReviewedAt     time.Time `json:"reviewed_at"`
	ReviewedSHA256 string    `json:"reviewed_sha256"`
}

AIEvaluationFeedbackApproval is one human approval over the exact review outcome and curated evaluation context. ReviewedSHA256 is produced by AIEvaluationFeedbackReviewDigest and prevents approval reuse after edits.

type AIEvaluationFeedbackCase added in v0.1.8

type AIEvaluationFeedbackCase struct {
	ReviewID           shared.ID                    `json:"review_id"`
	Label              AIEvaluationLabel            `json:"label"`
	Language           string                       `json:"language"`
	Framework          string                       `json:"framework"`
	Kind               finding.Kind                 `json:"kind"`
	Title              string                       `json:"title"`
	Description        string                       `json:"description,omitempty"`
	File               string                       `json:"file"`
	Line               int                          `json:"line"`
	Source             string                       `json:"source"`
	Adversarial        bool                         `json:"adversarial,omitempty"`
	PrivacyReview      AIEvaluationFeedbackApproval `json:"privacy_review"`
	LabelQualityReview AIEvaluationFeedbackApproval `json:"label_quality_review"`
}

AIEvaluationFeedbackCase selects one durable human review outcome and supplies only the context explicitly approved for evaluation use. ReviewID never enters the resulting dataset; the output case ID is an opaque digest-derived token.

type AIEvaluationFeedbackDigest added in v0.1.8

type AIEvaluationFeedbackDigest struct {
	Case     int       `json:"case"`
	ReviewID shared.ID `json:"-"`
	SHA256   string    `json:"sha256"`
}

AIEvaluationFeedbackDigest is safe to print for reviewers: Case maps the digest to manifest order while ReviewID is retained only in-process and never serialized.

func AIEvaluationFeedbackReviewDigests added in v0.1.8

func AIEvaluationFeedbackReviewDigests(reviews []aitriagereview.Review, manifest AIEvaluationFeedbackManifest) ([]AIEvaluationFeedbackDigest, error)

AIEvaluationFeedbackReviewDigests computes the exact digests that privacy and label-quality reviewers must approve. It does not require approvals to exist yet.

type AIEvaluationFeedbackManifest added in v0.1.8

type AIEvaluationFeedbackManifest struct {
	SchemaVersion  string                     `json:"schema_version"`
	DatasetVersion string                     `json:"dataset_version"`
	Provenance     string                     `json:"provenance"`
	Curator        string                     `json:"curator"`
	Cases          []AIEvaluationFeedbackCase `json:"cases"`
}

AIEvaluationFeedbackManifest is an offline, operator-owned curation manifest. It is deliberately separate from runtime triage policy and never changes model, prompt, threshold, or gate settings.

type AIEvaluationLabel added in v0.1.8

type AIEvaluationLabel string

AIEvaluationLabel is the human-reviewed ground truth for one golden-dataset case.

const (
	AIEvaluationTruePositive  AIEvaluationLabel = "true_positive"
	AIEvaluationFalsePositive AIEvaluationLabel = "false_positive"
	AIEvaluationUncertain     AIEvaluationLabel = "uncertain"
)

type AIEvaluationMetricComparison added in v0.1.8

type AIEvaluationMetricComparison struct {
	Baseline                            AIEvaluationMetrics `json:"baseline"`
	Candidate                           AIEvaluationMetrics `json:"candidate"`
	PrecisionDeltaBasisPoints           int                 `json:"precision_delta_basis_points"`
	RecallDeltaBasisPoints              int                 `json:"recall_delta_basis_points"`
	FalseNegativeEscapeDeltaBasisPoints int                 `json:"false_negative_escape_delta_basis_points"`
	DisagreementDeltaBasisPoints        int                 `json:"disagreement_delta_basis_points"`
	CoverageDeltaBasisPoints            int                 `json:"coverage_delta_basis_points"`
	VerifierCoverageDeltaBasisPoints    int                 `json:"verifier_coverage_delta_basis_points"`
}

AIEvaluationMetricComparison records exact counters plus integer basis-point deltas. Integer deltas avoid float-tolerance ambiguity in CI and promotion approval records.

type AIEvaluationMetrics added in v0.1.8

type AIEvaluationMetrics struct {
	Total                   int     `json:"total"`
	Covered                 int     `json:"covered"`
	HumanFalsePositives     int     `json:"human_false_positives"`
	HumanTruePositives      int     `json:"human_true_positives"`
	ExemptibleTruePositives int     `json:"exemptible_true_positives"`
	ConsensusFalsePositives int     `json:"consensus_false_positives"`
	CorrectFalsePositives   int     `json:"correct_false_positives"`
	TruePositiveEscapes     int     `json:"true_positive_escapes"`
	VerifierComparisons     int     `json:"verifier_comparisons"`
	VerifierDisagreements   int     `json:"verifier_disagreements"`
	Precision               float64 `json:"precision"`
	Recall                  float64 `json:"recall"`
	FalseNegativeEscapeRate float64 `json:"false_negative_escape_rate"`
	ExemptibleEscapeRate    float64 `json:"exemptible_escape_rate"`
	DisagreementRate        float64 `json:"disagreement_rate"`
	Coverage                float64 `json:"coverage"`
}

AIEvaluationMetrics are computed over a whole run or one segment. Precision/recall describe verified false-positive consensus; escape rate describes real bugs the deterministic policy would exempt.

Two escape rates are reported because they answer different questions. FalseNegativeEscapeRate is the corpus-wide rate: escapes over every human true positive, including the ones a human-review floor makes ineligible for exemption. It is stable to read across datasets but it dilutes — adding a High-severity true positive lowers it while changing nothing about the gate. ExemptibleEscapeRate divides by ExemptibleTruePositives, the true positives the deterministic policy could actually have exempted, and is the rate a safety threshold should be set against.

type AIEvaluationPromotionEvidence added in v0.1.8

type AIEvaluationPromotionEvidence struct {
	BaselineReport  AIEvaluationReport     `json:"baseline_report"`
	CandidateReport AIEvaluationReport     `json:"candidate_report"`
	Comparison      AIEvaluationComparison `json:"comparison"`
}

AIEvaluationPromotionEvidence keeps both shadow reports beside their comparison so the release boundary can recompute every metric and invariant instead of trusting a stored status or digest.

func (AIEvaluationPromotionEvidence) Validate added in v0.1.8

func (e AIEvaluationPromotionEvidence) Validate() error

type AIEvaluationPromotionFailure added in v0.1.8

type AIEvaluationPromotionFailure struct {
	Rule                 string `json:"rule"`
	Scope                string `json:"scope"`
	Segment              string `json:"segment,omitempty"`
	CaseID               string `json:"case_id,omitempty"`
	BaselineBasisPoints  int    `json:"baseline_basis_points"`
	CandidateBasisPoints int    `json:"candidate_basis_points"`
	LimitBasisPoints     int    `json:"limit_basis_points"`
	BaselineCount        int    `json:"baseline_count,omitempty"`
	CandidateCount       int    `json:"candidate_count,omitempty"`
	LimitCount           int    `json:"limit_count,omitempty"`
}

AIEvaluationPromotionFailure is a stable machine-readable reason a candidate cannot proceed to human promotion review. Scope is "overall", "case", or a report breakdown dimension.

A failure carries exactly one of two numeric triples, so a consumer never has to read a value in a unit it did not expect. Rate rules populate the basis-point fields, which always hold a rate in 0..10000. Precondition rules constrain the size of a population rather than a rate, and populate the count fields instead while leaving the basis-point fields zero. LimitCount is non-zero on every emitted count rule, because a precondition with a zero minimum cannot fail, so its presence identifies the shape without the consumer needing a list of rule names.

type AIEvaluationPromotionPolicy added in v0.1.8

type AIEvaluationPromotionPolicy struct {
	MinimumPrecisionBasisPoints                       int `json:"minimum_precision_basis_points"`
	MaximumFalseNegativeEscapeRateBasisPoints         int `json:"maximum_false_negative_escape_rate_basis_points"`
	MaximumPrecisionDropBasisPoints                   int `json:"maximum_precision_drop_basis_points"`
	MaximumRecallDropBasisPoints                      int `json:"maximum_recall_drop_basis_points"`
	MaximumCoverageDropBasisPoints                    int `json:"maximum_coverage_drop_basis_points"`
	MaximumVerifierCoverageDropBasisPoints            int `json:"maximum_verifier_coverage_drop_basis_points"`
	MaximumDisagreementIncreaseBasisPoints            int `json:"maximum_disagreement_increase_basis_points"`
	MinimumCounterfactualCoverageBasisPoints          int `json:"minimum_counterfactual_coverage_basis_points"`
	MinimumCounterfactualVerifierCoverageBasisPoints  int `json:"minimum_counterfactual_verifier_coverage_basis_points"`
	MaximumCounterfactualProposerFlipRateBasisPoints  int `json:"maximum_counterfactual_proposer_flip_rate_basis_points"`
	MaximumCounterfactualVerifierFlipRateBasisPoints  int `json:"maximum_counterfactual_verifier_flip_rate_basis_points"`
	MaximumCounterfactualConsensusFlipRateBasisPoints int `json:"maximum_counterfactual_consensus_flip_rate_basis_points"`
	MaximumCounterfactualPolicyFlipRateBasisPoints    int `json:"maximum_counterfactual_policy_flip_rate_basis_points"`
	// MinimumGateReachableCounterfactualPairs is a precondition rather than a rate. The policy and
	// consensus flip criteria are satisfied by a zero numerator, and a corpus whose adversarial
	// challenges all sit above a human-review floor produces that zero no matter how the candidate
	// behaves. Requiring at least one pair the deterministic policy could exempt keeps those criteria
	// from passing vacuously.
	MinimumGateReachableCounterfactualPairs int `json:"minimum_gate_reachable_counterfactual_pairs"`
}

AIEvaluationPromotionPolicy is an operator-approved, deterministic quality gate for comparing a candidate shadow run with a baseline run. Passing this policy only makes the candidate eligible for human promotion review; it never changes runtime configuration or grants gate authority.

func DefaultAIEvaluationPromotionPolicy added in v0.1.8

func DefaultAIEvaluationPromotionPolicy() AIEvaluationPromotionPolicy

DefaultAIEvaluationPromotionPolicy returns the conservative proposed threshold from the AI-triage epic: at least 95% precision, zero true-positive escapes, and no regression versus the baseline. PM/Security must still approve the policy values and every promotion decision.

func (AIEvaluationPromotionPolicy) Validate added in v0.1.8

func (p AIEvaluationPromotionPolicy) Validate() error

Validate rejects ambiguous or impossible basis-point thresholds.

type AIEvaluationReleaseApproval added in v0.1.8

type AIEvaluationReleaseApproval struct {
	Role           string    `json:"role"`
	Reviewer       string    `json:"reviewer"`
	Approved       bool      `json:"approved"`
	Rationale      string    `json:"rationale"`
	ReviewedAt     time.Time `json:"reviewed_at"`
	ReviewedSHA256 string    `json:"reviewed_sha256"`
}

AIEvaluationReleaseApproval records one independent human approval over the exact release manifest, comparison, and current ledger head. PM and Security must approve separately.

type AIEvaluationReleaseDecision added in v0.1.8

type AIEvaluationReleaseDecision struct {
	DecisionID            string                        `json:"decision_id"`
	Sequence              int                           `json:"sequence"`
	Version               string                        `json:"version"`
	Action                string                        `json:"action"`
	Status                string                        `json:"status"`
	Provenance            string                        `json:"provenance"`
	PreviousDecisionID    string                        `json:"previous_decision_id,omitempty"`
	ComparisonID          string                        `json:"comparison_id,omitempty"`
	RollbackTo            string                        `json:"rollback_to,omitempty"`
	BaselineEvaluationRun *AIEvaluationRun              `json:"baseline_evaluation_run,omitempty"`
	BaselineEvaluationID  string                        `json:"baseline_evaluation_run_id,omitempty"`
	PromotionPolicy       *AIEvaluationPromotionPolicy  `json:"promotion_policy,omitempty"`
	PreviousActiveRunID   string                        `json:"previous_active_run_id"`
	ActiveRun             AIEvaluationRun               `json:"active_run"`
	ActiveRunID           string                        `json:"active_run_id"`
	ApprovalDigest        string                        `json:"approval_digest"`
	Approvals             []AIEvaluationReleaseApproval `json:"approvals"`
}

AIEvaluationReleaseDecision is an append-only, versioned governance event. It has no runtime authority: operators apply the approved configuration through their normal deployment controls.

type AIEvaluationReleaseLedger added in v0.1.8

type AIEvaluationReleaseLedger struct {
	SchemaVersion  string                        `json:"schema_version"`
	InitialRun     AIEvaluationRun               `json:"initial_run"`
	InitialRunID   string                        `json:"initial_run_id"`
	HeadDecisionID string                        `json:"head_decision_id"`
	Decisions      []AIEvaluationReleaseDecision `json:"decisions"`
}

AIEvaluationReleaseLedger is a deterministic hash-chained promotion/rollback history.

func ApplyAIEvaluationRelease added in v0.1.8

func ApplyAIEvaluationRelease(ledger AIEvaluationReleaseLedger, evidence *AIEvaluationPromotionEvidence, manifest AIEvaluationReleaseManifest, allowedHumanApprovers []string) (AIEvaluationReleaseLedger, error)

ApplyAIEvaluationRelease appends an approved promotion or rollback. It does not mutate runtime configuration, model clients, prompts, thresholds, findings, or gate state.

allowedHumanApprovers is the operator-owned allowlist an approver identity must appear in. The manifest is operator-supplied input that names its own approvers, so on its own "these two are human" is a claim the manifest makes about itself: the machine-prefix denylist can only reject the identity families this codebase already mints, and fails open on any other. The allowlist is what admits an identity from outside the artifact being validated.

It is required here, at admission, and deliberately not consulted by Validate. A decision keeps the approvers it was admitted with, so an approver who later leaves the allowlist must not retroactively invalidate the ledger they signed, nor stop that ledger from loading.

func LoadAIEvaluationReleaseLedger added in v0.1.8

func LoadAIEvaluationReleaseLedger(data []byte) (AIEvaluationReleaseLedger, error)

func (AIEvaluationReleaseLedger) Validate added in v0.1.8

func (l AIEvaluationReleaseLedger) Validate() error

type AIEvaluationReleaseManifest added in v0.1.8

type AIEvaluationReleaseManifest struct {
	SchemaVersion string                        `json:"schema_version"`
	Version       string                        `json:"version"`
	Action        string                        `json:"action"`
	Provenance    string                        `json:"provenance"`
	ComparisonID  string                        `json:"comparison_id,omitempty"`
	RollbackTo    string                        `json:"rollback_to,omitempty"`
	Approvals     []AIEvaluationReleaseApproval `json:"approvals"`
}

AIEvaluationReleaseManifest is operator-owned approval input. A promotion binds a passing comparison; a rollback binds an earlier approved decision (or the initial baseline).

func LoadAIEvaluationReleaseManifest added in v0.1.8

func LoadAIEvaluationReleaseManifest(data []byte) (AIEvaluationReleaseManifest, error)

type AIEvaluationReport added in v0.1.8

type AIEvaluationReport struct {
	SchemaVersion  string                                    `json:"schema_version"`
	RunID          string                                    `json:"run_id"`
	DatasetVersion string                                    `json:"dataset_version"`
	DatasetSHA256  string                                    `json:"dataset_sha256"`
	Provenance     string                                    `json:"provenance"`
	Reviewer       string                                    `json:"reviewer"`
	Run            AIEvaluationRun                           `json:"run"`
	Metrics        AIEvaluationMetrics                       `json:"metrics"`
	Robustness     AIEvaluationRobustness                    `json:"robustness"`
	Breakdowns     map[string]map[string]AIEvaluationMetrics `json:"breakdowns"`
	Results        []AIEvaluationResult                      `json:"results"`
}

AIEvaluationReport is stable, machine-readable CI output. RunID hashes the dataset/version metadata and ordered decisions; no clock is included, so identical inputs and model replies produce identical bytes and the same ID.

func EvaluateFPTriage added in v0.1.8

func EvaluateFPTriage(ctx context.Context, dataset AIEvaluationDataset, run AIEvaluationRun, triager ports.FPTriager) (AIEvaluationReport, error)

EvaluateFPTriage runs the normal injected triager and the normal deterministic policy in shadow mode. It cannot produce gate authority: the report is rejected if any result sets GateExempt.

func LoadAIEvaluationReport added in v0.1.8

func LoadAIEvaluationReport(data []byte) (AIEvaluationReport, error)

LoadAIEvaluationReport strictly decodes and revalidates a report before it is used for a promotion decision. Metrics, breakdowns, shadow invariants, model identity, and run ID are all recomputed.

func (AIEvaluationReport) Validate added in v0.1.8

func (r AIEvaluationReport) Validate() error

Validate checks that an evaluation report is internally consistent and remains a shadow-only artifact. It is intentionally strict because the comparison can become promotion evidence.

type AIEvaluationResult added in v0.1.8

type AIEvaluationResult struct {
	CaseID                 string                         `json:"case_id"`
	Label                  AIEvaluationLabel              `json:"label"`
	Language               string                         `json:"language"`
	Framework              string                         `json:"framework"`
	Kind                   finding.Kind                   `json:"kind"`
	Severity               shared.Severity                `json:"severity"`
	CWE                    string                         `json:"cwe"`
	Adversarial            bool                           `json:"adversarial"`
	CounterfactualGroup    string                         `json:"counterfactual_group,omitempty"`
	CounterfactualRole     AIEvaluationCounterfactualRole `json:"counterfactual_role,omitempty"`
	Covered                bool                           `json:"covered"`
	ConsensusFalsePositive bool                           `json:"consensus_false_positive"`
	WouldGateExempt        bool                           `json:"would_gate_exempt"`
	GateExempt             bool                           `json:"gate_exempt"`
	Critique               ports.AICritique               `json:"critique"`
}

AIEvaluationResult keeps the human label beside both model consensus and deterministic shadow-policy output. GateExempt is included as a tripwire and must always be false in an evaluation report.

type AIEvaluationRobustness added in v0.1.8

type AIEvaluationRobustness struct {
	Metrics AIEvaluationRobustnessMetrics `json:"metrics"`
	Pairs   []AIEvaluationRobustnessPair  `json:"pairs"`
}

AIEvaluationRobustness is deterministic, source-free adversarial invariance evidence.

type AIEvaluationRobustnessComparison added in v0.1.8

type AIEvaluationRobustnessComparison struct {
	Baseline                          AIEvaluationRobustnessMetrics `json:"baseline"`
	Candidate                         AIEvaluationRobustnessMetrics `json:"candidate"`
	CoverageDeltaBasisPoints          int                           `json:"coverage_delta_basis_points"`
	VerifierCoverageDeltaBasisPoints  int                           `json:"verifier_coverage_delta_basis_points"`
	ProposerFlipRateDeltaBasisPoints  int                           `json:"proposer_flip_rate_delta_basis_points"`
	VerifierFlipRateDeltaBasisPoints  int                           `json:"verifier_flip_rate_delta_basis_points"`
	ConsensusFlipRateDeltaBasisPoints int                           `json:"consensus_flip_rate_delta_basis_points"`
	PolicyFlipRateDeltaBasisPoints    int                           `json:"policy_flip_rate_delta_basis_points"`
}

AIEvaluationRobustnessComparison records adversarial invariance deltas from exact pair counters.

type AIEvaluationRobustnessMetrics added in v0.1.8

type AIEvaluationRobustnessMetrics struct {
	TotalPairs            int     `json:"total_pairs"`
	CoveredPairs          int     `json:"covered_pairs"`
	VerifierRequiredPairs int     `json:"verifier_required_pairs"`
	VerifierComparedPairs int     `json:"verifier_compared_pairs"`
	ProposerVerdictFlips  int     `json:"proposer_verdict_flips"`
	VerifierVerdictFlips  int     `json:"verifier_verdict_flips"`
	ConsensusFlips        int     `json:"consensus_flips"`
	PolicyFlips           int     `json:"policy_flips"`
	UnsafePolicyFlips     int     `json:"unsafe_policy_flips"`
	GateReachablePairs    int     `json:"gate_reachable_pairs"`
	Coverage              float64 `json:"coverage"`
	VerifierCoverage      float64 `json:"verifier_coverage"`
	ProposerStability     float64 `json:"proposer_stability"`
	VerifierStability     float64 `json:"verifier_stability"`
	ConsensusStability    float64 `json:"consensus_stability"`
	PolicyStability       float64 `json:"policy_stability"`
}

AIEvaluationRobustnessMetrics measure pairwise invariance. Rates are included for operator readability; promotion decisions use the exact counters rather than these floats.

type AIEvaluationRobustnessPair added in v0.1.8

type AIEvaluationRobustnessPair struct {
	GroupID             string `json:"group_id"`
	ControlCaseID       string `json:"control_case_id"`
	ChallengeCaseID     string `json:"challenge_case_id"`
	Covered             bool   `json:"covered"`
	VerifierRequired    bool   `json:"verifier_required"`
	VerifierCompared    bool   `json:"verifier_compared"`
	ProposerVerdictFlip bool   `json:"proposer_verdict_flip"`
	VerifierVerdictFlip bool   `json:"verifier_verdict_flip"`
	ConsensusFlip       bool   `json:"consensus_flip"`
	PolicyFlip          bool   `json:"policy_flip"`
	UnsafePolicyFlip    bool   `json:"unsafe_policy_flip"`
	// GateReachable records whether the deterministic policy could exempt this pair's challenge at
	// all. A pair held back by a human-review floor can never report PolicyFlip or UnsafePolicyFlip,
	// so counting it as adversarial evidence would overstate what was tested.
	GateReachable bool `json:"gate_reachable"`
}

AIEvaluationRobustnessPair is source-free evidence that an adversarial challenge did or did not change model and policy behavior relative to its human-reviewed semantic control.

type AIEvaluationRun added in v0.1.8

type AIEvaluationRun struct {
	ProposerProvider   string                     `json:"proposer_provider"`
	ProposerModel      string                     `json:"proposer_model"`
	VerifierProvider   string                     `json:"verifier_provider"`
	VerifierModel      string                     `json:"verifier_model"`
	IndependencePolicy ports.AIIndependencePolicy `json:"independence_policy"`
	PromptVersion      string                     `json:"prompt_version"`
	PolicyVersion      string                     `json:"policy_version"`
}

AIEvaluationRun identifies the exact model/prompt/policy combination being evaluated.

type AIEvaluationSourceReader added in v0.1.8

type AIEvaluationSourceReader struct {
	// contains filtered or unexported fields
}

AIEvaluationSourceReader returns the reviewed source stored in a dataset, never production data.

func NewAIEvaluationSourceReader added in v0.1.8

func NewAIEvaluationSourceReader(dataset AIEvaluationDataset) AIEvaluationSourceReader

NewAIEvaluationSourceReader creates an in-memory reader suitable for fptriage.NewTriager.

func (AIEvaluationSourceReader) Snippet added in v0.1.8

func (r AIEvaluationSourceReader) Snippet(_ context.Context, file string, _, _ int) (string, error)

type AIEvidenceSealError added in v0.1.8

type AIEvidenceSealError struct {
	RevokedExemptions int
	Err               error
}

AIEvidenceSealError is returned when an evidence failure revoked AI gate authority. The scan remains failed before result persistence; callers may retry after the ledger recovers.

func (*AIEvidenceSealError) Error added in v0.1.8

func (e *AIEvidenceSealError) Error() string

func (*AIEvidenceSealError) Unwrap added in v0.1.8

func (e *AIEvidenceSealError) Unwrap() error

type AITriageAlert added in v0.1.8

type AITriageAlert struct {
	Metric               string `json:"metric"`
	ObservedBasisPoints  int    `json:"observed_basis_points"`
	BaselineBasisPoints  int    `json:"baseline_basis_points"`
	DeviationBasisPoints int    `json:"deviation_basis_points"`
	SampleSize           int    `json:"sample_size"`
	Message              string `json:"message"`
}

type AITriageBudget added in v0.1.8

type AITriageBudget struct {
	MaxFindings               int `json:"max_findings"`
	EligibleFindings          int `json:"eligible_findings"`
	AttemptedFindings         int `json:"attempted_findings"`
	SkippedFindings           int `json:"skipped_findings"`
	EvidenceSealFailures      int `json:"evidence_seal_failures,omitempty"`
	EvidenceRevokedExemptions int `json:"evidence_revoked_exemptions,omitempty"`
}

AITriageBudget records bounded per-scan AI coverage. The cap is on findings, so a configured distinct verifier can make at most two LLM calls per attempted finding. Unattempted findings retain their normal gate effect. EvidenceSealFailures and EvidenceRevokedExemptions are in-memory failure accounting for the revocation boundary; the scan fails before ScanResult persistence, so the operator-visible metric is emitted separately as a stable structured event by sealEvidenceFailClosed.

type AITriageDashboard added in v0.1.8

type AITriageDashboard struct {
	GeneratedAt  time.Time                    `json:"generated_at"`
	Totals       AITriageMetricRow            `json:"totals"`
	ByModel      []AITriageMetricRow          `json:"by_model"`
	ByPrompt     []AITriageMetricRow          `json:"by_prompt_version"`
	ByCWE        []AITriageMetricRow          `json:"by_cwe"`
	ByProject    []AITriageMetricRow          `json:"by_project"`
	Distribution AITriageDistributionSnapshot `json:"distribution"`
	Alerts       []AITriageDashboardAlert     `json:"alerts"`
}

type AITriageDashboardAlert added in v0.1.8

type AITriageDashboardAlert struct {
	ProjectID   string        `json:"project_id"`
	ProjectName string        `json:"project_name"`
	Alert       AITriageAlert `json:"alert"`
}

type AITriageDistributionSnapshot added in v0.1.8

type AITriageDistributionSnapshot struct {
	SchemaVersion string         `json:"schema_version"`
	SampleSize    int            `json:"sample_size"`
	Language      map[string]int `json:"language_basis_points"`
	CWE           map[string]int `json:"cwe_basis_points"`
	Project       map[string]int `json:"project_basis_points"`
}

AITriageDistributionSnapshot is a deterministic, source-free view of the population evaluated by AI triage. Every populated dimension sums to 10,000 basis points so snapshots can be compared across scan volumes.

func LoadAITriageDistributionSnapshot added in v0.1.8

func LoadAITriageDistributionSnapshot(data []byte) (AITriageDistributionSnapshot, error)

LoadAITriageDistributionSnapshot accepts either a snapshot or the saved JSON response from GET /api/v1/ai-triage/observability.

func (AITriageDistributionSnapshot) Validate added in v0.1.8

func (s AITriageDistributionSnapshot) Validate() error

type AITriageDriftAlert added in v0.1.8

type AITriageDriftAlert struct {
	Dimension                 string `json:"dimension"`
	TotalVariationBasisPoints int    `json:"total_variation_basis_points"`
	ThresholdBasisPoints      int    `json:"threshold_basis_points"`
	SampleSize                int    `json:"sample_size"`
	Message                   string `json:"message"`
}

type AITriageDriftBaseline added in v0.1.8

type AITriageDriftBaseline struct {
	SchemaVersion                    string                       `json:"schema_version"`
	Version                          string                       `json:"version"`
	Provenance                       string                       `json:"provenance"`
	ApprovedBy                       string                       `json:"approved_by"`
	MinimumSamples                   int                          `json:"minimum_samples"`
	MaximumTotalVariationBasisPoints int                          `json:"maximum_total_variation_basis_points"`
	Distribution                     AITriageDistributionSnapshot `json:"distribution"`
}

AITriageDriftBaseline is a versioned, human-approved reference population. It carries policy as data so CI cannot silently substitute a threshold.

func LoadAITriageDriftBaseline added in v0.1.8

func LoadAITriageDriftBaseline(data []byte) (AITriageDriftBaseline, error)

func (AITriageDriftBaseline) Validate added in v0.1.8

func (b AITriageDriftBaseline) Validate() error

type AITriageDriftReport added in v0.1.8

type AITriageDriftReport struct {
	SchemaVersion                    string                       `json:"schema_version"`
	ReportID                         string                       `json:"report_id"`
	Status                           string                       `json:"status"`
	ReviewRequired                   bool                         `json:"review_required"`
	BaselineVersion                  string                       `json:"baseline_version"`
	BaselineProvenance               string                       `json:"baseline_provenance"`
	BaselineApprovedBy               string                       `json:"baseline_approved_by"`
	MinimumSamples                   int                          `json:"minimum_samples"`
	MaximumTotalVariationBasisPoints int                          `json:"maximum_total_variation_basis_points"`
	Baseline                         AITriageDistributionSnapshot `json:"baseline"`
	Observed                         AITriageDistributionSnapshot `json:"observed"`
	Alerts                           []AITriageDriftAlert         `json:"alerts"`
}

AITriageDriftReport is deterministic CI evidence. It reports population change only; it cannot promote a model, change a prompt, or exempt a finding.

func DetectAITriageDistributionDrift added in v0.1.8

func DetectAITriageDistributionDrift(baseline AITriageDriftBaseline, observed AITriageDistributionSnapshot) (AITriageDriftReport, error)

type AITriageMetricRow added in v0.1.8

type AITriageMetricRow struct {
	Value                 string `json:"value"`
	RequestCount          int    `json:"request_count"`
	AverageLatencyMillis  int64  `json:"average_latency_ms"`
	TimeoutCount          int    `json:"timeout_count"`
	ParseFailureCount     int    `json:"parse_failure_count"`
	ProviderFailureCount  int    `json:"provider_failure_count"`
	CircuitOpenCount      int    `json:"circuit_open_count"`
	TotalTokens           int64  `json:"total_tokens"`
	EstimatedCostMicroUSD int64  `json:"estimated_cost_micro_usd"`
	Comparisons           int    `json:"comparisons"`
	Disagreements         int    `json:"disagreements"`
	GateExemptions        int    `json:"gate_exemptions"`
	Findings              int    `json:"findings"`
	// contains filtered or unexported fields
}

type BlindFPTriageAuthentication added in v0.2.0

type BlindFPTriageAuthentication struct {
	Algorithm string `json:"algorithm"`
	MAC       string `json:"mac"`
}

type BlindFPTriageAuthenticator added in v0.2.0

type BlindFPTriageAuthenticator struct {
	// contains filtered or unexported fields
}

BlindFPTriageAuthenticator holds an operator-supplied private HMAC key.

func NewBlindFPTriageAuthenticator added in v0.2.0

func NewBlindFPTriageAuthenticator(key []byte) (BlindFPTriageAuthenticator, error)

NewBlindFPTriageAuthenticator rejects short keys rather than offering misleading authentication.

type BlindFPTriageDecision added in v0.2.0

type BlindFPTriageDecision string
const (
	BlindFPTriageFalsePositive BlindFPTriageDecision = "false_positive"
	BlindFPTriageTruePositive  BlindFPTriageDecision = "true_positive"
	BlindFPTriageAbstain       BlindFPTriageDecision = "abstain"
)

type BlindFPTriageImportedSubmission added in v0.2.0

type BlindFPTriageImportedSubmission struct {
	BlindFPTriageSubmission
	Reviewer       string                      `json:"reviewer"`
	Authentication BlindFPTriageAuthentication `json:"authentication"`
}

BlindFPTriageImportedSubmission is an authenticated receipt binding reviewer identity, decisions, dataset, run, and packet.

func ImportBlindFPTriageSubmission added in v0.2.0

func ImportBlindFPTriageSubmission(packet BlindFPTriagePacket, submission BlindFPTriageSubmission, reviewer string, allowedHumanReviewers []string, proposer, verifier string, authenticator BlindFPTriageAuthenticator) (BlindFPTriageImportedSubmission, error)

ImportBlindFPTriageSubmission validates a reviewer response before it can be joined with the run.

type BlindFPTriageJoinedReport added in v0.2.0

type BlindFPTriageJoinedReport struct {
	SchemaVersion string               `json:"schema_version"`
	PacketID      string               `json:"packet_id"`
	DatasetSHA256 string               `json:"dataset_sha256"`
	RunSHA256     string               `json:"run_sha256"`
	Reviewer      string               `json:"reviewer"`
	Shadow        bool                 `json:"shadow"`
	GateExempt    bool                 `json:"gate_exempt"`
	Metrics       BlindFPTriageMetrics `json:"metrics"`
}

BlindFPTriageJoinedReport contains aggregate results only; it never republishes individual model output.

func JoinBlindFPTriageSubmission added in v0.2.0

func JoinBlindFPTriageSubmission(dataset AIEvaluationDataset, report AIEvaluationReport, packet BlindFPTriagePacket, submission BlindFPTriageImportedSubmission, allowedHumanReviewers []string, authenticator BlindFPTriageAuthenticator) (BlindFPTriageJoinedReport, error)

JoinBlindFPTriageSubmission joins an already imported submission with the locked data and run.

type BlindFPTriageMetrics added in v0.2.0

type BlindFPTriageMetrics struct {
	Total                   int     `json:"total"`
	Reviewed                int     `json:"reviewed"`
	HumanFalsePositives     int     `json:"human_false_positives"`
	DecidedFalsePositives   int     `json:"decided_false_positives"`
	CorrectFalsePositives   int     `json:"correct_false_positives"`
	Abstentions             int     `json:"abstentions"`
	Disagreements           int     `json:"disagreements"`
	DisagreementComparisons int     `json:"disagreement_comparisons"`
	PolicyExemptible        int     `json:"policy_exemptible"`
	Precision               float64 `json:"precision"`
	Recall                  float64 `json:"recall"`
	AbstentionRate          float64 `json:"abstention_rate"`
	DisagreementRate        float64 `json:"disagreement_rate"`
	PolicyExemptibleRate    float64 `json:"policy_exemptible_rate"`
}

BlindFPTriageMetrics measure a submitted human review against the locked ground truth only after join.

type BlindFPTriagePacket added in v0.2.0

type BlindFPTriagePacket struct {
	SchemaVersion  string                      `json:"schema_version"`
	PacketID       string                      `json:"packet_id"`
	DatasetVersion string                      `json:"dataset_version"`
	DatasetSHA256  string                      `json:"dataset_sha256"`
	RunSHA256      string                      `json:"run_sha256"`
	Shadow         bool                        `json:"shadow"`
	GateExempt     bool                        `json:"gate_exempt"`
	Cases          []BlindFPTriagePacketCase   `json:"cases"`
	Authentication BlindFPTriageAuthentication `json:"authentication"`
}

BlindFPTriagePacket is the reviewer-facing subset of an evaluation dataset and run. It deliberately excludes labels and every model output, identity, confidence, rationale, and experiment-arm field.

func ExportBlindFPTriagePacket added in v0.2.0

func ExportBlindFPTriagePacket(dataset AIEvaluationDataset, report AIEvaluationReport, seed string, authenticator BlindFPTriageAuthenticator) (BlindFPTriagePacket, error)

ExportBlindFPTriagePacket makes a shuffled, seed-reproducible reviewer packet from a locked dataset/run.

type BlindFPTriagePacketCase added in v0.2.0

type BlindFPTriagePacketCase struct {
	BlindID     string          `json:"blind_id"`
	Language    string          `json:"language"`
	Framework   string          `json:"framework"`
	Kind        finding.Kind    `json:"kind"`
	Severity    shared.Severity `json:"severity"`
	CWE         string          `json:"cwe"`
	Title       string          `json:"title"`
	Description string          `json:"description"`
	File        string          `json:"file"`
	Line        int             `json:"line"`
	Source      string          `json:"source"`
}

type BlindFPTriageReviewDecision added in v0.2.0

type BlindFPTriageReviewDecision struct {
	BlindID   string                `json:"blind_id"`
	Decision  BlindFPTriageDecision `json:"decision"`
	Rationale string                `json:"rationale,omitempty"`
}

type BlindFPTriageSubmission added in v0.2.0

type BlindFPTriageSubmission struct {
	SchemaVersion string                        `json:"schema_version"`
	PacketID      string                        `json:"packet_id"`
	DatasetSHA256 string                        `json:"dataset_sha256"`
	RunSHA256     string                        `json:"run_sha256"`
	Shadow        bool                          `json:"shadow"`
	GateExempt    bool                          `json:"gate_exempt"`
	Decisions     []BlindFPTriageReviewDecision `json:"decisions"`
}

BlindFPTriageSubmission is untrusted reviewer input. The trusted command boundary supplies reviewer identity separately.

type ComponentLicenseAudit

type ComponentLicenseAudit struct {
	Component          string               `json:"component"`
	Version            string               `json:"version"`
	VersionStatus      string               `json:"version_status"`
	PURL               string               `json:"purl"`
	Scope              string               `json:"scope"`
	Location           string               `json:"location"`
	Locations          []string             `json:"locations,omitempty"`
	DependencyType     string               `json:"dependency_type"`
	EvidenceStatus     string               `json:"evidence_status"`
	RawLicense         string               `json:"raw_license"`
	License            string               `json:"license"`
	DetectedExpression string               `json:"detected_expression"`
	Category           sbom.LicenseCategory `json:"category"`
	Verdict            ports.LicenseVerdict `json:"verdict"`
	OptionSeverity     string               `json:"option_severity"`
	EffectiveSeverity  string               `json:"effective_severity"`
	PolicyRuleID       string               `json:"policy_rule_id"`
	RecommendedChoice  string               `json:"recommended_choice"`
	SelectionReason    string               `json:"selection_reason"`
	Source             string               `json:"source"`
	Confidence         string               `json:"confidence"`
	UnknownReason      string               `json:"unknown_reason"`
}

type EvidenceReport

type EvidenceReport struct {
	Items       []evidence.Evidence   `json:"items"`
	Intact      bool                  `json:"intact"`
	Head        string                `json:"head"`
	Error       string                `json:"error,omitempty"`
	Verified    int                   `json:"verified"` // number of links verified
	Attestation *evidence.Attestation `json:"attestation,omitempty"`
	Anchored    bool                  `json:"anchored"` // external RFC-3161 timestamp present
	Timestamp   *ports.TimestampToken `json:"timestamp,omitempty"`
}

EvidenceReport is the engagement's evidence ledger plus its verification status.

type FindingQuality

type FindingQuality struct {
	ThirdParty           int     `json:"third_party"`            // actionable findings
	ThirdPartyCritical   int     `json:"third_party_critical"`   // critical, third-party only
	ThirdPartyHigh       int     `json:"third_party_high"`       // high, third-party only
	FirstPartyHistorical int     `json:"first_party_historical"` // informational, unversioned
	VersionCoveragePct   float64 `json:"version_coverage_pct"`
	PathCoveragePct      float64 `json:"path_coverage_pct"`
	Confidence           string  `json:"confidence"` // high | medium | low

	// Scope + priority breakdown: separates actionable from background
	// without hiding anything.
	RawFindings int            `json:"raw_findings"`
	Actionable  int            `json:"actionable"` // non-background, non-historical
	Background  int            `json:"background"` // example/test/fixture/etc + historical
	Production  int            `json:"production"`
	Development int            `json:"development"`
	ExampleTest int            `json:"example_test"` // example+test+fixture+benchmark+docs
	ByPriority  map[int]int    `json:"by_priority"`  // priority 1..5 -> count
	ByScope     map[string]int `json:"by_scope"`
}

FindingQuality is the honest finding breakdown shown before any vulnerability counts: actionable third-party findings vs first-party historical advisories, with coverage + confidence so the headline numbers aren't misread.

type LicenseCoverageBreakdown

type LicenseCoverageBreakdown struct {
	ByScope           map[string]sbom.LicenseCoverage `json:"by_scope"`
	ByEcosystem       map[string]sbom.LicenseCoverage `json:"by_ecosystem"`
	ProductionUnknown int                             `json:"production_unknown"`
}

type NeedsVerifyFinding

type NeedsVerifyFinding struct {
	DedupKey string `json:"dedup_key"`
	Title    string `json:"title"`
	Reason   string `json:"reason"`
}

NeedsVerifyFinding marks a vuln finding the precise detection-priority quarantined as lower-confidence (a single, uncorroborated detection source, and not KEV). The finding STAYS in Findings (reported + evidence-sealed); this only labels it needs-verify and exempts it from the --fail-on gate – the "quarantine into a verify queue, don't drop" alternative to Trivy dropping imprecise matches.

type ScanDrift

type ScanDrift struct {
	RunA        ports.ScanRun `json:"run_a"`
	RunB        ports.ScanRun `json:"run_b"`
	Added       []string      `json:"added"`       // finding keys in B not in A
	Removed     []string      `json:"removed"`     // finding keys in A not in B
	Unchanged   int           `json:"unchanged"`   // count present in both
	Explanation []string      `json:"explanation"` // manifest deltas that explain the drift
}

ScanDrift is the difference between two scan runs: which findings appeared or disappeared, and the manifest deltas that explain why.

type ScanOptions

type ScanOptions struct {
	Mode string `json:"mode"`
	// PolicyDir overrides where the repo-committed accepted-risk policy (.synapseignore / OpenVEX) is read
	// from. Empty ⇒ the scanned workspace (ws.Dir), correct for a source/repo scan where the policy travels
	// with the code. For an IMAGE scan the workspace is the materialized image, which does NOT carry the
	// operator's CI-repo governance, so the CLI sets this to the invocation CWD (the checked-out repo).
	PolicyDir string `json:"policy_dir,omitempty"`
	// DetectionPriority selects comprehensive (default) or precise; see the Detection* consts.
	DetectionPriority string `json:"detection_priority,omitempty"`
	CodeQuality       bool   `json:"code_quality,omitempty"`
	ProjectAnalysis   bool   `json:"project_analysis,omitempty"`
	// ProjectAnalysisID is assigned after the durable job is created. It is not
	// caller input and binds captured artifacts to the immutable analysis snapshot.
	ProjectAnalysisID string                  `json:"project_analysis_id,omitempty"`
	LineCoverage      *measure.CoverageReport `json:"line_coverage,omitempty"`
	Gate              qualitygate.Gate        `json:"gate,omitempty"`
}

func NormalizeScanOptions

func NormalizeScanOptions(opts ScanOptions) (ScanOptions, error)

type ScanResult

type ScanResult struct {
	Target       string                   `json:"target"`
	SourceRef    string                   `json:"source_ref,omitempty"`
	SourceCommit string                   `json:"source_commit,omitempty"`
	ScanMode     string                   `json:"scan_mode"`
	Languages    []ports.DetectedLanguage `json:"languages"`
	SBOM         *sbom.SBOM               `json:"sbom"`
	// Image carries container-image metadata (manifest digest, platform, ordered layer
	// stack with base-image classification) for image scans; nil otherwise. Every vuln on
	// an image is also attributed to its layer (Vulnerability.Layer*) – Epic D.
	Image *sbom.ImageInfo `json:"image,omitempty"`
	// Distro is the captured OS distribution (from OS-package PURLs) + its End-of-Life verdict;
	// nil when the target has no OS packages. An EOL distro receives no security updates – a
	// first-class posture signal for a container/host scan (Epic E).
	Distro            *distro.Status                `json:"distro,omitempty"`
	Vulnerabilities   []vulnerability.Vulnerability `json:"vulnerabilities"`
	Licenses          []ports.LicenseFinding        `json:"licenses"`
	ComponentLicenses []ComponentLicenseAudit       `json:"component_licenses"`
	Findings          []finding.Finding             `json:"findings"`
	// SLAs is populated only when SLA governance is enabled. Each entry joins immutable scoring
	// provenance with the separately human-owned remediation lifecycle.
	SLAs []sla.View `json:"slas,omitempty"`
	// MinSeverity + VulnsBelowThreshold make the severity floor VISIBLE: every detected vuln is
	// kept in Vulnerabilities, but only those at/above MinSeverity become promoted Findings.
	// VulnsBelowThreshold counts the detected-but-not-promoted vulns so a raised floor can never
	// silently hide them ("no silent gap"). Default floor = info ⇒ this is 0 (everything promoted).
	MinSeverity         shared.Severity `json:"min_severity"`
	VulnsBelowThreshold int             `json:"vulns_below_threshold"`
	// UnfixedSuppressed counts vulns not promoted ONLY because --ignore-unfixed is on and they
	// have no available fix (they remain in Vulnerabilities) – surfaced so it's never silent.
	UnfixedSuppressed int `json:"unfixed_suppressed"`
	// SourceWarnings flags a configured detection source that did NOT run (e.g. the Grype
	// binary/DB is missing), so a silently-degraded source can't masquerade as "0 vulns / clean".
	SourceWarnings []string `json:"source_warnings,omitempty"`
	// AnalysisCoverage makes semantic-analysis negative-proof coverage explicit. A partial analyzer can
	// still produce positive witnesses, but an empty result must not be interpreted as clean.
	AnalysisCoverage []ports.AnalysisCoverage `json:"analysis_coverage,omitempty"`
	// SuppressedFindings marks findings accepted by the repo's .synapseignore policy. The findings REMAIN in
	// Findings (reported, persisted, evidence-sealed – never hidden); this is only an accepted-risk
	// annotation a CI --fail-on gate consults to exempt them. Acceptance suppresses the GATE, not visibility.
	SuppressedFindings []SuppressedFinding `json:"suppressed_findings,omitempty"`
	// ExpiredSuppressions lists .synapseignore rule ids that have lapsed, surfaced so accepted risk gets
	// revisited rather than lingering – an expired rule no longer suppresses, so its finding re-surfaces.
	ExpiredSuppressions []string `json:"expired_suppressions,omitempty"`
	// MalformedSuppressions lists .synapseignore rule ids whose expiry could not be parsed; fail-safe, they
	// do NOT suppress (a date typo must not become a permanent silent acceptance) and are surfaced to fix.
	MalformedSuppressions []string `json:"malformed_suppressions,omitempty"`
	// Compliance is the owned AppSec-baseline benchmark re-projected onto this scan's findings (per-control
	// PASS/FAIL, LLM-free); nil unless compliance is enabled. Computed over ALL findings (an accepted-risk
	// finding still fails its control – compliance reflects what is present, not the CI-gate decision).
	Compliance *compliance.Report `json:"compliance,omitempty"`
	// NeedsVerification lists vuln findings the precise detection-priority quarantined as lower-confidence
	// (single uncorroborated source, non-KEV): still reported + sealed, but exempt from the --fail-on gate.
	// nil in comprehensive mode. Recall is retained; only the lower-confidence set is separated.
	NeedsVerification        []NeedsVerifyFinding     `json:"needs_verification,omitempty"`
	ToolVersions             map[string]string        `json:"tool_versions"`
	VulnDBSnapshot           string                   `json:"vuln_db_snapshot"`
	Completeness             ports.Completeness       `json:"completeness"`
	LicenseCoverage          sbom.LicenseCoverage     `json:"license_coverage"`
	LicenseCoverageBreakdown LicenseCoverageBreakdown `json:"license_coverage_breakdown"`
	Manifest                 ports.ScanManifest       `json:"manifest"`
	RiskMatches              map[string]int           `json:"risk_matches"` // kev/epss match counts (diagnostic)
	FindingQuality           FindingQuality           `json:"finding_quality"`
	CodeQuality              *codequality.Report      `json:"code_quality,omitempty"`
	LineCoverage             *measure.CoverageReport  `json:"line_coverage,omitempty"`
	Gate                     qualitygate.Gate         `json:"-"`
	// Coverage is the per-ecosystem component tally: components + resolved-version counts per
	// ecosystem, so a thin / partially-resolved ecosystem is VISIBLE rather than hidden behind the single
	// global Completeness number ("no silent gap").
	Coverage []sbom.EcosystemCoverage `json:"coverage"`
	// SBOMQuality scores the produced SBOM against the NTIA minimum elements + semantic-quality checks –
	// how well the components are DESCRIBED (supplier, unique id, checksum, license, dependency graph, ...),
	// distinct from Completeness (which judges scan COVERAGE). Surfaced so a thin, hard-to-share, or
	// non-regulation-minimum SBOM is a visible signal rather than a silent assumption. A consumer gates on
	// len(.Elements) > 0 (a nil-SBOM / recon-only run leaves it zero-valued = "not computed", not "graded 0"),
	// and any hard pass/fail gate keys off .NTIAMet / .NTIAScore, never the blended .Score.
	SBOMQuality sbom.QualityReport `json:"sbom_quality"`
	// ReproDigest is a stable content fingerprint of the reproducible output: same target + pinned
	// producer + pinned advisory/DB snapshot ⇒ same digest. Excludes timestamps + per-run metadata.
	ReproDigest string                 `json:"repro_digest"`
	DebugEvents []ports.ScanDebugEvent `json:"debug_events"`
	// AITriage holds optional LLM false-positive critiques plus the deterministic policy decision for each
	// finding. SuspectedFP is advisory; only GateExempt=true may affect a CI/project gate, and that requires
	// distinct-model consensus plus clearance of the high-risk human-review floor. Findings are never
	// deleted. The complete array is sealed into the scan evidence link.
	AITriage []ports.AICritique `json:"ai_triage,omitempty"`
	// AITriageBudget makes the bounded AI coverage explicit. AttemptedFindings were submitted to the
	// triager even when a provider error produced no critique; SkippedFindings never enter an LLM and
	// remain gating. nil means AI triage did not run for any eligible finding.
	AITriageBudget *AITriageBudget `json:"ai_triage_budget,omitempty"`
	// AITriageTelemetry contains source-free request, latency, provider outcome, token, cost, consensus,
	// and exemption observations for this scan. It is sealed with the policy decision.
	AITriageTelemetry *ports.FPTriageTelemetry `json:"ai_triage_telemetry,omitempty"`
	AITriageAlerts    []AITriageAlert          `json:"ai_triage_alerts,omitempty"`
	// SourceCapture is analysis-owned source availability metadata. Content is held by
	// ProjectSourceArtifactStore, never embedded in this scan result.
	SourceCapture *projectanalysis.SourceCapture `json:"source_capture,omitempty"`
	// Comparison is persisted scan-time Git metadata and base artifact inventory.
	// It is empty or unavailable for non-Git/first analyses.
	Comparison  projectanalysis.Comparison   `json:"comparison,omitempty"`
	FileChanges []projectanalysis.FileChange `json:"file_changes,omitempty"`
}

ScanResult is the aggregate output of an SCA scan.

func (*ScanResult) AIGateExemptKeys added in v0.1.8

func (r *ScanResult) AIGateExemptKeys() map[string]bool

AIGateExemptKeys returns only AI critiques that the server-owned policy authorized to affect a gate.

func (*ScanResult) AIGateExemptions added in v0.1.8

func (r *ScanResult) AIGateExemptions() map[string]ports.AIGateExemption

AIGateExemptions returns export-safe metadata only for decisions that still pass the complete server-owned authorization check. Consumers must use this projection instead of trusting persisted GateExempt flags directly; severity/profile changes and forged or stale decisions fail closed here.

func (*ScanResult) AIReviewRequiredKeys added in v0.1.8

func (r *ScanResult) AIReviewRequiredKeys() map[string]bool

AIReviewRequiredKeys returns suspected false positives held in the human-review floor.

func (*ScanResult) AIWouldGateExemptKeys added in v0.1.8

func (r *ScanResult) AIWouldGateExemptKeys() map[string]bool

AIWouldGateExemptKeys returns shadow observations that passed every enforced-policy check except the rollout-mode switch. This set is for evaluation/observability only and MUST NOT authorize a gate.

func (*ScanResult) GateExemptKeys

func (r *ScanResult) GateExemptKeys(items []finding.Finding) map[string]bool

GateExemptKeys returns retain-and-mark findings excluded from a Project quality gate.

func (*ScanResult) NeedsVerifyKeys

func (r *ScanResult) NeedsVerifyKeys() map[string]bool

NeedsVerifyKeys returns the dedup keys a CI gate should exempt from --fail-on (the needs-verify queue).

func (*ScanResult) SuppressedKeys

func (r *ScanResult) SuppressedKeys() map[string]bool

SuppressedKeys returns the dedup keys a CI gate should exempt from --fail-on (the accepted-risk set).

func (*ScanResult) SuspectedFPKeys

func (r *ScanResult) SuspectedFPKeys() map[string]bool

SuspectedFPKeys returns advisory model opinions. Consumers MUST NOT use this set to authorize a gate exemption; use AIGateExemptKeys, whose values have passed the deterministic P0 policy.

type ScanRunObserver added in v0.2.0

type ScanRunObserver interface {
	AssessmentScanRunSealed(context.Context, shared.ID, shared.ID, shared.ID) error
}

ScanRunObserver receives a successfully persisted immutable scan-run boundary. Implementations may create Snapshot, lineage, and comparison shadow artifacts.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service orchestrates the SCA pipeline over swappable ports.

func NewService

NewService wires the SCA use case. minSeverity is the lowest vuln severity that is promoted to a finding; timeout bounds a single scan (0 disables).

func (*Service) AIGateExemptions added in v0.1.8

func (s *Service) AIGateExemptions(ctx context.Context, engagementID shared.ID, findings []finding.Finding) ([]ports.AIGateExemption, error)

AIGateExemptions reads the latest durable scan and returns a stable projection revalidated against the exact findings being exported. Older scans with no AI triage naturally return an empty slice.

func (*Service) AITriageObservability added in v0.1.8

func (s *Service) AITriageObservability(ctx context.Context, tenantID shared.ID) (AITriageDashboard, error)

AITriageObservability aggregates the latest evidence-sealed result for each tenant-visible project. It never returns source, prompts, provider errors, or credentials.

func (*Service) AddManifestResolver

func (s *Service) AddManifestResolver(r ports.ManifestResolver)

AddManifestResolver registers a lockfile-less manifest resolver (composer/gem/poetry/...). Several may be added; each runs best-effort and no-ops when its manifest is absent or already locked.

func (*Service) AddReachabilityRecorder added in v0.2.0

func (s *Service) AddReachabilityRecorder(r ports.ReachabilityRecorder)

AddReachabilityRecorder composes an additional deterministic reachability recorder onto the scan pass. Each recorder runs independently over the same subjects/target: a no-coverage failure from one must not prevent another language engine from producing a positive proof. The scan pipeline already treats the aggregate recorder as best-effort; joined errors preserve diagnostics without changing that contract.

func (*Service) CompareRuns

func (s *Service) CompareRuns(ctx context.Context, engagementID shared.ID, runA, runB string) (ScanDrift, error)

CompareRuns computes the drift between two runs and explains it from the manifest deltas (chain-of-custody: "why does this differ from last month?").

func (*Service) CycloneDX

func (s *Service) CycloneDX(ctx context.Context, engagementID shared.ID) ([]byte, error)

CycloneDX returns the engagement's latest scan SBOM as a deterministic CycloneDX 1.6 JSON document. shared.ErrNotFound if no scan has run.

func (*Service) FailStrandedScanJob

func (s *Service) FailStrandedScanJob(ctx context.Context, payload []byte, cause error) error

FailStrandedScanJob marks the scan job behind a DEAD-LETTERED sca job failed if it has not already reached a terminal state – so a crash/lock-error that exhausts the retries leaves a terminal, operator-visible ScanJob (status=failed) instead of one stuck non-terminal with no result. It is the worker's DeadLetterer hook for SCA (parity with recon + agent). It takes the run lease so it never races a live redelivery and no-ops when the scan is already terminal.

func (*Service) ImportContextSBOM added in v0.2.0

func (s *Service) ImportContextSBOM(ctx context.Context, actor string, tenantID, engagementID shared.ID, filename string, data []byte) (*ScanResult, error)

ImportContextSBOM records a CycloneDX document on a machine-owned engagement context (a Project analysis context or a fleet host vulnerability context), which the tenant-scoped engagement read deliberately hides. It is not a request-path read: the caller resolved the context through its owning aggregate. The engagement must belong to tenantID and be internal, so an operator engagement can never be reached through this entry point.

func (*Service) ImportSBOM

func (s *Service) ImportSBOM(ctx context.Context, actor string, tenantID, engagementID shared.ID, data []byte) (*ScanResult, error)

ImportSBOM ingests a client-supplied CycloneDX SBOM (consultancies receive client SBOMs) as the engagement's scan result, so its components are visible, license-summarized, exportable (SPDX), and sealed into the evidence chain. It does NOT run vulnerability detection on the imported components – that reuses the post-SBOM half of the scan pipeline and is a follow-up; importing makes the client's inventory a first-class, attested artifact today. Audited.

func (*Service) ImportSBOMFile

func (s *Service) ImportSBOMFile(ctx context.Context, actor string, tenantID, engagementID shared.ID, filename string, data []byte) (*ScanResult, error)

ImportSBOMFile ingests a named client-supplied CycloneDX SBOM.

func (*Service) ImportedSBOMMetadata

func (s *Service) ImportedSBOMMetadata(ctx context.Context, tenantID, engagementID shared.ID) (importedsbom.Metadata, error)

ImportedSBOMMetadata returns safe metadata for the active imported SBOM.

func (*Service) LatestJob

func (s *Service) LatestJob(ctx context.Context, engagementID shared.ID) (ports.ScanJob, error)

LatestJob returns the engagement's most recent scan job (for the status poll).

func (*Service) LatestJobs

func (s *Service) LatestJobs(ctx context.Context, engagementIDs []shared.ID) (map[shared.ID]ports.ScanJob, error)

func (*Service) LatestResult

func (s *Service) LatestResult(ctx context.Context, engagementID shared.ID) ([]byte, error)

LatestResult returns the cached JSON of the engagement's most recent scan (SBOM, vulnerabilities, dependency graph, languages, provenance) so the UI can rehydrate the scan tabs after a page reload. shared.ErrNotFound if none.

func (*Service) ReportInsight

func (s *Service) ReportInsight(ctx context.Context, engagementID shared.ID) (ports.ReportInsight, error)

ReportInsight assembles the scan-level context the executive report needs: license coverage, completeness, reproducibility, and evidence integrity. Returns a zero-value (HasScan=false) insight when no scan has run.

func (*Service) RunScanJob

func (s *Service) RunScanJob(ctx context.Context, payload []byte) error

RunScanJob runs an SCA scan claimed from the durable queue (the worker handler calls this). A malformed payload is a hard error (dead-letters); pipeline failures are recorded on the ScanJob (not a job error), so the job completes.

func (*Service) SPDX

func (s *Service) SPDX(ctx context.Context, engagementID shared.ID) ([]byte, error)

SPDX returns the engagement's latest scan SBOM as a deterministic SPDX 2.3 JSON document. shared.ErrNotFound if no scan has run.

func (*Service) SPDX3

func (s *Service) SPDX3(ctx context.Context, engagementID shared.ID) ([]byte, error)

SPDX3 returns the engagement's latest scan SBOM as a deterministic SPDX 3.0.1 JSON-LD document. shared.ErrNotFound if no scan has run.

func (*Service) Scan

func (s *Service) Scan(ctx context.Context, actor string, engagementID shared.ID, req ports.AcquireRequest) (*ScanResult, error)

Scan runs the SCA pipeline synchronously and returns the result (used by the CLI). The API uses StartScan. Scope + the authorization window are enforced and the action audited BEFORE any tool runs.

func (*Service) ScanJob added in v0.2.0

func (s *Service) ScanJob(ctx context.Context, jobID string) (ports.ScanJob, error)

ScanJob returns one asynchronous scan by its stable job ID.

func (*Service) ScanRuns

func (s *Service) ScanRuns(ctx context.Context, engagementID shared.ID) ([]ports.ScanRun, error)

ScanRuns returns the engagement's scan-run history (newest first) for the reproducibility / drift UI.

func (*Service) ScanWithOptions

func (s *Service) ScanWithOptions(ctx context.Context, actor string, engagementID shared.ID, req ports.AcquireRequest, opts ScanOptions) (*ScanResult, error)

func (*Service) SetAITriageReviewRecorder added in v0.1.8

func (s *Service) SetAITriageReviewRecorder(r ports.AITriageReviewRecorder)

SetAITriageReviewRecorder materializes policy-held critiques after their scan evidence has been sealed. nil keeps CLI/standalone scans free of workflow state.

func (*Service) SetArtifactCataloger added in v0.1.4

func (s *Service) SetArtifactCataloger(c ports.ArtifactCataloger)

SetArtifactCataloger configures optional owned cataloging of standalone package/installer artifacts (a Windows Installer .msi) discovered under the workspace directory. nil ⇒ off. It runs on any target (file-target or source tree), independent of image-rootfs materialization.

func (*Service) SetAssessmentCycleMembership added in v0.2.0

func (s *Service) SetAssessmentCycleMembership(cycles ports.AssessmentCycleRepository, snapshots ports.AssessmentSnapshotDefaultReader)

func (*Service) SetCodeQuality

func (s *Service) SetCodeQuality(q interface {
	BuildReport(context.Context, string) (codequality.Report, error)
})

func (*Service) SetComplianceEnabled

func (s *Service) SetComplianceEnabled(on bool)

SetComplianceEnabled turns on attaching the owned AppSec-baseline compliance report (per-control PASS/FAIL over the scan's findings) to each scan result. Deterministic + LLM-free; off by default.

func (*Service) SetCorrelation

func (s *Service) SetCorrelation(r ports.CorrelationRecorder)

SetCorrelation configures the optional cross-check disagreement→judgment minter. nil ⇒ no correlation judgments. Best-effort + opt-in: a recorder error is ignored (the scan never fails). A setter keeps NewService call sites unchanged.

func (*Service) SetDBMaxAgeDays

func (s *Service) SetDBMaxAgeDays(days int)

SetDBMaxAgeDays sets the reference-DB freshness policy: a scan warns (SourceWarning) when a dated DB (KEV/EPSS catalog, vuln-DB build) is older than this many days. 0 (default) disables the check.

func (*Service) SetDetectionPriority

func (s *Service) SetDetectionPriority(p string)

SetDetectionPriority sets the server-level default detection priority (comprehensive|precise) applied when a scan request does not specify one – so a server-configured SYNAPSE_DETECTION_PRIORITY reaches the API scan path, which has no per-request priority field. Empty leaves the comprehensive default.

func (*Service) SetFPTriage

func (s *Service) SetFPTriage(t ports.FPTriager)

SetFPTriage injects the optional LLM false-positive triager. When set, the pipeline critiques the production-scope first-party source findings after they are built and records the advisory verdicts on ScanResult.AITriage. The deterministic AI gate policy separately decides whether a verified consensus clears the human-review floor; a suspected-FP opinion alone has no gate authority. Best-effort; nil = no triage. Implementations are trusted in-process components; policy revalidation contains buggy DTOs, not malicious code that already holds process authority.

func (*Service) SetFPTriageAlertPolicy added in v0.1.8

func (s *Service) SetFPTriageAlertPolicy(minSamples, disagreementBaseline, exemptionBaseline, parseFailureBaseline, deviation int)

SetFPTriageAlertPolicy configures scan-local baseline deviation alerts. Rates are basis points (10000 = 100%); invalid values restore conservative defaults.

func (*Service) SetFPTriageIndependence added in v0.1.8

func (s *Service) SetFPTriageIndependence(policy string)

SetFPTriageIndependence selects the deterministic verifier identity requirement. Unknown values disable verifier authority rather than silently falling back to a weaker policy.

func (*Service) SetFPTriageMaxFindings added in v0.1.8

func (s *Service) SetFPTriageMaxFindings(maxFindings int)

SetFPTriageMaxFindings sets the hard per-scan LLM candidate cap. Invalid values restore the finite default; zero never means unbounded. Findings beyond the cap remain reported and gating.

func (*Service) SetFPTriageMode added in v0.1.8

func (s *Service) SetFPTriageMode(mode string)

SetFPTriageMode selects shadow observation or enforced gate authorization. Unknown and empty values fail closed to shadow. This setting never changes the human-review floors.

func (*Service) SetFindingAttribution added in v0.1.8

func (s *Service) SetFindingAttribution(assets ports.AssetRepository, attributor ports.FindingAttributor) error

SetFindingAttribution enables explicit SCA producer attribution. A configured service resolves or creates the governed asset and records only persisted IDs.

func (*Service) SetGateDecoder

func (s *Service) SetGateDecoder(decoder ports.GateDecoder)

func (*Service) SetGoBinaryReachability added in v0.2.0

func (s *Service) SetGoBinaryReachability(r ports.ReachabilityRecorder)

SetGoBinaryReachability wires the raise-only Go binary reachability recorder.

func (*Service) SetGradleResolver

func (s *Service) SetGradleResolver(r ports.GradleResolver)

SetGradleResolver configures the optional Gradle transitive-tree resolver (`gradle dependencies`). nil ⇒ Gradle projects are scanned from the build script only (direct deps, often versionless, no transitive tree → under-reports, flagged INCOMPLETE). Best-effort + opt-in: a non-Gradle target / missing gradle / resolution error leaves the SBOM unchanged and never fails the scan.

func (*Service) SetGraphResolver

func (s *Service) SetGraphResolver(r ports.DependencyGraphResolver)

SetGraphResolver configures the optional transitive-edge resolver (Go via `go mod graph`). nil ⇒ no resolved Go edges. Best-effort + opt-in: a non-Go target / no module cache / tool error adds no edges and never fails the scan. A setter keeps NewService call sites unchanged.

func (*Service) SetIgnoreUnfixed

func (s *Service) SetIgnoreUnfixed(v bool)

SetIgnoreUnfixed controls whether vulnerabilities with no available fix are promoted to findings. true = suppress them (Trivy's --ignore-unfixed); they stay in the vuln inventory.

func (*Service) SetImageConfigChecker added in v0.2.0

func (s *Service) SetImageConfigChecker(c ports.ImageConfigChecker)

SetImageConfigChecker configures the optional owned image config + build-history hardening checker. nil ⇒ off.

func (*Service) SetImportedSBOMStore

func (s *Service) SetImportedSBOMStore(store ports.ImportedSBOMStore)

SetImportedSBOMStore configures the engagement-scoped client SBOM artifact store.

func (*Service) SetIncludeTestSecrets

func (s *Service) SetIncludeTestSecrets(v bool)

SetIncludeTestSecrets controls whether secret hits in test/fixture/docs/detector-pattern paths are reported. Default false: they are suppressed (they are overwhelmingly fake credentials, not leaked production secrets), so a customer report is not flooded with test-double noise.

func (*Service) SetInstalledPackageCataloger

func (s *Service) SetInstalledPackageCataloger(c ports.InstalledPackageCataloger)

SetInstalledPackageCataloger configures optional owned installed-package cataloging (Go binaries, Python dist-info) from a materialized image rootfs. nil ⇒ off. It only runs when a rootfs was materialized.

func (*Service) SetJSReachability added in v0.1.8

func (s *Service) SetJSReachability(r jsSBOMReachabilityRecorder)

SetJSReachability configures the optional deterministic Tier-1 JavaScript import-reachability prover. A dependency declared but never imported becomes not_reachable, which the export path turns into an OpenVEX not_affected justification. Best-effort and opt-in; nil disables it.

func (*Service) SetJSSymbolReachability added in v0.1.8

func (s *Service) SetJSSymbolReachability(r jsSBOMReachabilityRecorder)

SetJSSymbolReachability configures the optional deterministic TIER-2 JavaScript prover: not "is this package imported" but "is the affected EXPORT reached". It runs alongside Tier-1 rather than replacing it — a Tier-2 answer supersedes the Tier-1 judgment for the same subject under the existing stronger-tier-wins rule, and a subject Tier-2 cannot answer leaves the Tier-1 judgment standing. Best-effort and opt-in; nil disables it.

func (*Service) SetJVMReachability

func (s *Service) SetJVMReachability(a ports.JVMReachabilityAnalyzer)

SetJVMReachability configures the optional coarse JVM class-reachability tagger. nil ⇒ no reachability tagging (components keep an empty/unknown verdict).

func (*Service) SetJVMReachabilityRecorder added in v0.2.0

func (s *Service) SetJVMReachabilityRecorder(r ports.JVMReachabilityRecorder)

SetJVMReachabilityRecorder configures the optional recorder that mints the coarse JVM class-reachability tags as auditable Tier-1.5 judgments (feeding VEX + the SLA scorer). nil ⇒ JVM reachability stays a finding tag only.

func (*Service) SetJarChecksumResolver

func (s *Service) SetJarChecksumResolver(r ports.JarChecksumResolver)

SetJarChecksumResolver configures optional JAR artifact-SHA-1 capture from the prepared workspace, filling in a checksum Syft's CycloneDX output omits (deterministic, offline, read-only). It runs before the SHA-1 coordinate recovery, which needs that checksum as input.

func (*Service) SetJarHashResolver

func (s *Service) SetJarHashResolver(r ports.JarHashResolver)

SetJarHashResolver configures optional SHA-1 coordinate recovery for shaded/metadata-less JARs an egress call to Maven Central, so it's opt-in + best-effort. nil disables it.

func (*Service) SetJavaTaint added in v0.2.0

func (s *Service) SetJavaTaint(t ports.TaintScanner)

SetJavaTaint configures the Java source-only, interprocedural value-flow proposer. Like the JS/Python engines it is propose-only: positive witnesses become gated CapSAST proposals and partial coverage never becomes a clean conclusion. A setter keeps NewService call sites unchanged.

func (*Service) SetJsTaint added in v0.2.0

func (s *Service) SetJsTaint(t ports.TaintScanner)

SetJsTaint configures the JavaScript/TypeScript source-only, interprocedural value-flow proposer. Like the Python hook it is independent and source-only (the synapse-ast sidecar only parses target JS), and it follows the same propose-only lifecycle: positive witnesses become gated CapSAST proposals while missing or partial coverage never becomes a clean conclusion.

func (*Service) SetLicenseFileResolver

func (s *Service) SetLicenseFileResolver(r ports.LicenseFileResolver)

SetLicenseFileResolver configures an optional deterministic, offline fallback that recovers a component's license from the license text embedded in its JAR when the registry left it unknown. Best-effort; nil disables it.

func (*Service) SetLogger added in v0.1.8

func (s *Service) SetLogger(log *slog.Logger)

SetLogger records operational warnings that do not contain source data or paths.

func (*Service) SetMavenCoordResolver

func (s *Service) SetMavenCoordResolver(r ports.MavenCoordResolver)

SetMavenCoordResolver configures optional Maven coordinate recovery (deterministic, offline) that runs before registry license enrichment, so a mis-derived JAR groupId doesn't make the deps.dev lookup 404 → "unknown". Best-effort; nil disables it.

func (*Service) SetMavenResolver

func (s *Service) SetMavenResolver(r ports.MavenResolver)

SetMavenResolver configures the optional Maven transitive-tree resolver. When it also implements ports.MavenGraphResolver the pipeline runs `mvn dependency:tree` and folds in the dependency edges; nil ⇒ Maven projects are scanned from pom.xml only (direct deps, managed versions UNKNOWN, no transitive tree → under-reports, flagged INCOMPLETE). Best-effort + opt-in: a non-Maven target / missing mvn / resolution error leaves the SBOM unchanged and never fails the scan.

func (*Service) SetMisconfigScanner

func (s *Service) SetMisconfigScanner(m ports.MisconfigScanner)

SetMisconfigScanner configures the optional deterministic IaC/config misconfig scanner. nil ⇒ no misconfig scanning. A setter keeps the existing NewService call sites unchanged.

func (*Service) SetNPMResolver

func (s *Service) SetNPMResolver(r ports.NPMResolver)

SetNPMResolver configures the optional npm resolver (`npm install --package-lock-only`), which resolves a package.json that has no committed lockfile into a pinned pkg:npm tree. nil ⇒ disabled.

func (*Service) SetOSPackageCataloger

func (s *Service) SetOSPackageCataloger(c ports.OSPackageCataloger)

SetOSPackageCataloger configures optional owned OS-package cataloging from a materialized image rootfs (Workspace.RootFS). nil ⇒ no owned OS cataloging. It only runs when a rootfs was materialized.

func (*Service) SetObserver added in v0.2.0

func (s *Service) SetObserver(observer ports.SCAObserver)

SetObserver installs an optional terminal SCA execution observer (duration + success/failed/blocked outcome). Nil disables observation.

func (*Service) SetOwnershipSource added in v0.2.0

func (s *Service) SetOwnershipSource(reader ports.OwnershipSourceReader, store ports.OwnershipSourceStore) error

func (*Service) SetProjectAnalysisCompletionTimeout added in v0.1.8

func (s *Service) SetProjectAnalysisCompletionTimeout(timeout time.Duration)

SetProjectAnalysisCompletionTimeout bounds post-scan immutable Project persistence.

func (*Service) SetProjectAnalysisRecorder

func (s *Service) SetProjectAnalysisRecorder(r interface {
	RecordProjectAnalysis(context.Context, shared.ID, string, time.Time, *ScanResult) error
})

SetProjectAnalysisRecorder registers the Project-only success boundary. Nil keeps ordinary Engagement and CLI scans unchanged.

func (*Service) SetProjectComparisonSource added in v0.1.8

func (s *Service) SetProjectComparisonSource(source ports.ProjectComparisonSource)

SetProjectComparisonSource reads persisted Git changes before workspace cleanup.

func (*Service) SetProjectSourceArtifactStore added in v0.1.8

func (s *Service) SetProjectSourceArtifactStore(store ports.ProjectSourceArtifactStore)

SetProjectSourceArtifactStore captures immutable source for Project analyses while the acquired workspace still exists. Nil keeps non-Code deployments unchanged.

func (*Service) SetPyReachability

func (s *Service) SetPyReachability(r ports.ReachabilityRecorder)

SetPyReachability configures the optional deterministic Tier-1 Python import-reachability prover: it mints a not_reachable judgment for a declared PyPI package that first-party code never imports (a dead dependency). nil ⇒ no Python reachability judgments. Same best-effort + opt-in contract as SetReachability (a no-coverage / dynamic-import target leaves the prior tier standing, never a false "not reachable"). Kept distinct from the Go call-graph prover: it is a WEAKER (Tier-1, import-level) proof.

func (*Service) SetPySymbolReachability added in v0.2.0

func (s *Service) SetPySymbolReachability(r ports.ReachabilityRecorder)

SetPySymbolReachability configures the optional Python Tier-2 affected-symbol call-graph proof. It is run after Tier-1 so an incomplete semantic analysis leaves the package-level judgment standing.

func (*Service) SetPythonTaint added in v0.2.0

func (s *Service) SetPythonTaint(t ports.TaintScanner)

SetPythonTaint configures Python's source-only, interprocedural value-flow proposer separately from the legacy Go function-level scanner. Keeping independent hooks lets operators enable Python analysis without enabling target compilation. No-coverage parser/resolution failures remain best-effort and propose nothing.

func (*Service) SetQueue

func (s *Service) SetQueue(q ports.JobQueue)

SetQueue routes SCA scans through the durable job queue: StartScan enqueues and a worker claims + calls RunScanJob. Optional – without it, the in-process goroutine runs.

func (*Service) SetReachability

func (s *Service) SetReachability(r ports.ReachabilityRecorder)

SetReachability configures the optional deterministic Tier-2 reachability prover. nil ⇒ no reachability judgments. Best-effort + opt-in: a no-coverage/un-buildable target leaves the prior reachability tier standing (never a false "not reachable"). A setter keeps NewService call sites unchanged.

func (*Service) SetRunLock

func (s *Service) SetRunLock(l ports.RunLocker)

SetRunLock guards against duplicate concurrent execution of the same scan job under at-least-once queue redelivery.

func (*Service) SetRustSymbolReachability added in v0.2.0

func (s *Service) SetRustSymbolReachability(r ports.ReachabilityRecorder)

SetRustSymbolReachability configures the optional Rust Tier-2 affected-symbol reachability prover (raise-only: it mints a reachable judgment for a proven qualified reference to a vulnerable crate function, never a not-reachable one). nil disables it. Fed the RustSec affected-function symbols per finding.

func (*Service) SetSASTAnalyzer

func (s *Service) SetSASTAnalyzer(a ports.SASTAnalyzer)

SetSASTAnalyzer configures the optional deterministic pattern-SAST analyzer. nil ⇒ no SAST findings. A setter keeps the existing NewService call sites unchanged.

func (*Service) SetSBOMCache

func (s *Service) SetSBOMCache(c ports.SBOMCache)

SetSBOMCache configures the optional generated-SBOM cache. nil ⇒ always regenerate. Best-effort: a cache miss or error never affects correctness, only whether the cataloging step is skipped.

func (*Service) SetSBOMCrossCheck

func (s *Service) SetSBOMCrossCheck(producer ports.SBOMGenerator, r ports.SBOMCrossCheckRecorder)

SetSBOMCrossCheck configures the SBOM-producer cross-check: a SECOND SBOM producer plus the disagreement→judgment recorder. nil either ⇒ no cross-check. Best-effort and enabled by default at the composition root (SYNAPSE_SBOM_CROSSCHECK_ENABLED defaults true): the 2nd producer runs only for the cross-check and a failure is ignored (the scan never fails). A setter keeps NewService call sites unchanged.

func (*Service) SetSBOMEnricher

func (s *Service) SetSBOMEnricher(e ports.SBOMEnricher)

SetSBOMEnricher configures optional manifest-based SBOM enrichment. Best-effort: nil leaves the generator's SBOM untouched. A setter (not a constructor param) keeps the many existing NewService call sites unchanged.

func (*Service) SetSLAAssessor added in v0.1.8

func (s *Service) SetSLAAssessor(assessor ports.FindingSLAAssessor)

SetSLAAssessor enables durable remediation SLA assessment at the finding persistence boundary. When unset, scan behavior and output remain unchanged.

func (*Service) SetScanRunObserver added in v0.2.0

func (s *Service) SetScanRunObserver(observer ScanRunObserver)

func (*Service) SetScanRunProvenance added in v0.2.0

func (s *Service) SetScanRunProvenance(store ports.ScanRunProvenanceStore, tx ports.TenantTransactionRunner)

SetScanRunProvenance enables native manifests without broadening the legacy ScanRunStore port used by integrations and existing scan-history callers.

func (*Service) SetScannedImageRecorder added in v0.1.8

func (s *Service) SetScannedImageRecorder(store ports.ScannedImageStore)

SetScannedImageRecorder wires the scanned-image digest index (#446). When set, a completed image scan records its manifest digest under the engagement's tenant, so the fleet cluster agent can later correlate a running digest with this prior scan. Recording is best-effort — a failure never fails the scan.

func (*Service) SetSecretHistoryEnabled added in v0.2.0

func (s *Service) SetSecretHistoryEnabled(enabled bool)

SetSecretHistoryEnabled turns on git-history secret scanning: when the workspace is a git repository and the secret scanner supports it, every blob in the repository's history is scanned so a committed-then-removed secret is caught, not just the working tree. Off by default (heavier, and it reports secrets no longer in the tree).

func (*Service) SetSecretScanner

func (s *Service) SetSecretScanner(sc ports.SecretScanner)

SetSecretScanner configures the optional deterministic secret scanner. nil ⇒ no secret scanning.

func (*Service) SetSecretVerifier added in v0.2.0

func (s *Service) SetSecretVerifier(v ports.SecretVerifier)

SetSecretVerifier injects the OPT-IN active secret verifier (D6.3). When set AND the secret scanner implements ports.VerifyingSecretScanner, the working-tree secret scan additionally makes one minimal read-only provider call per detected credential to confirm it is live, stamping the finding's verdict. nil (the default) leaves the scan fully deterministic and offline. Verification runs inside the scan the engagement's authorization window already gated (execution.Guard), so it inherits that authorization.

func (*Service) SetSeverityEnricher

func (s *Service) SetSeverityEnricher(e ports.SeverityEnricher)

SetSeverityEnricher configures optional severity backfill (NVD CVSS) for vulnerabilities the detection sources left unknown. Best-effort + bounded; nil skips it. Runs before risk enrichment so risk priority can use the backfilled CVSS.

func (*Service) SetSourceReachability added in v0.1.8

func (s *Service) SetSourceReachability(purlType string, r ports.ReachabilityRecorder)

SetSourceReachability registers a deterministic Tier-1 import-reachability prover for one package-URL ecosystem ("cargo", "composer", "gem"). Best-effort and opt-in; a prover that reports no coverage leaves the prior tier standing.

func (*Service) SetSourceSymbolReachability added in v0.2.0

func (s *Service) SetSourceSymbolReachability(purlType string, r ports.ReachabilityRecorder)

SetSourceSymbolReachability registers a deterministic Tier-2 RAISE-ONLY affected-symbol prover for one package-URL ecosystem (composer/gem/nuget): it asks whether first-party source REFERENCES the specific curated vulnerable function, not merely imports the package. Best-effort and opt-in; because it only mints reachable (never not-reachable), a no-coverage result leaves the prior tier standing.

func (*Service) SetStrictSources added in v0.2.0

func (s *Service) SetStrictSources(strict bool)

SetStrictSources selects fail-closed detection when true: a detection-source error aborts the scan. The default (false) degrades instead — a source that errors is skipped with a SourceWarning and the remaining sources still run, so a transient OSV.dev outage or an advisory-store read blip does not fail an otherwise-good scan (Grype already self-degrades to a no-op when its binary/DB is absent).

func (*Service) SetSuppressionLoader

func (s *Service) SetSuppressionLoader(l ports.SuppressionLoader)

SetSuppressionLoader configures the optional repo-committed .synapseignore accepted-risk policy loader. nil ⇒ no suppression. Suppressed findings are always retained + surfaced, never silently dropped.

func (*Service) SetTaint

func (s *Service) SetTaint(t ports.TaintScanner)

SetTaint configures the optional deterministic taint-analysis CapSAST proposer. nil ⇒ no taint judgments. Best-effort + opt-in: a no-coverage/un-buildable target is ignored (the scan never fails). A setter keeps NewService call sites unchanged.

func (*Service) SetUploadedSourceStore added in v0.2.0

func (s *Service) SetUploadedSourceStore(store ports.EngagementSourceStore)

func (*Service) SetVEXLoader

func (s *Service) SetVEXLoader(l ports.VEXLoader)

SetVEXLoader configures the optional in-repo OpenVEX (.synapse.vex.json) loader. nil ⇒ no in-scan VEX. A not_affected/fixed statement annotates the matched finding accepted-risk on the same retain-and-mark surface as .synapseignore (gate-exempt, but reported + sealed), never removed.

func (*Service) SetVEXReapplier added in v0.2.0

func (s *Service) SetVEXReapplier(r ports.VEXReapplier)

SetVEXReapplier wires the re-apply of persisted imported VEX statements after a rescan (#1064). Optional: without it a rescan leaves findings as materialized, so a previously-imported not_affected/fixed decision is not re-applied.

func (*Service) SetVulnerabilityReconciler added in v0.1.8

func (s *Service) SetVulnerabilityReconciler(reconciler ports.SBOMVulnerabilityReconciler)

func (*Service) StartScan

func (s *Service) StartScan(ctx context.Context, actor string, engagementID shared.ID, req ports.AcquireRequest) (ports.ScanJob, error)

StartScan gates + audits the scan, then runs the pipeline ASYNCHRONOUSLY (single-instance goroutine; a queue lands later) and returns the job immediately. The UI polls the job for progress and can resume after a reload.

func (*Service) StartScanWithOptions

func (s *Service) StartScanWithOptions(ctx context.Context, actor string, engagementID shared.ID, req ports.AcquireRequest, opts ScanOptions) (ports.ScanJob, error)

func (*Service) StartUploadedSourceScanWithOptions added in v0.2.0

func (s *Service) StartUploadedSourceScanWithOptions(ctx context.Context, actor string, tenantID, engagementID shared.ID, opts ScanOptions) (ports.ScanJob, error)

func (*Service) StartUploadedSourceVersionScanWithOptions added in v0.2.0

func (s *Service) StartUploadedSourceVersionScanWithOptions(ctx context.Context, actor string, tenantID, engagementID, versionID shared.ID, opts ScanOptions) (ports.ScanJob, error)

func (*Service) SweepStaleScans

func (s *Service) SweepStaleScans(ctx context.Context, staleFor time.Duration) (int, error)

SweepStaleScans reclaims scan jobs a crashed worker left `running` past staleFor WITHOUT a dead-letter event – parity with recon's SweepStaleRuns, using the run lease as the liveness signal (acquirable lease ⇒ no live owner ⇒ stranded ⇒ finalize failed). Requires the lease; no-ops without it. Returns the number reclaimed.

func (*Service) UploadedSourceMetadata added in v0.2.0

func (s *Service) UploadedSourceMetadata(ctx context.Context, tenantID, engagementID shared.ID) (sourcepackage.Package, error)

func (*Service) VerifyEvidence

func (s *Service) VerifyEvidence(ctx context.Context, engagementID shared.ID) (EvidenceReport, error)

VerifyEvidence loads the engagement's evidence chain and verifies its integrity (tamper detection). Used by the API + before the report is generated.

type SuppressedFinding

type SuppressedFinding struct {
	DedupKey string `json:"dedup_key"` // the accepted finding's key (also its --fail-on gate-exemption key)
	Title    string `json:"title"`
	RuleID   string `json:"rule_id"` // the .synapseignore id that matched (a CVE/GHSA or a dedup key)
	Reason   string `json:"reason,omitempty"`
}

SuppressedFinding marks a finding a .synapseignore rule accepts. CRUCIALLY the finding STAYS in the actionable Findings set – reported, persisted, and sealed into the evidence chain like any other, so a suppression can never hide a finding from a deliverable or the tamper-evident record. This record only ADDS an accepted-risk annotation (which rule matched, and why) that a CI --fail-on gate consults to exempt the finding. Governance over Trivy: acceptance suppresses the GATE, not the finding's visibility.

Directories

Path Synopsis
Package remediation computes the smallest set of direct-dependency upgrades that removes a transitive vulnerability from a resolved dependency graph (EPIC #860 D3.8).
Package remediation computes the smallest set of direct-dependency upgrades that removes a transitive vulnerability from a resolved dependency graph (EPIC #860 D3.8).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL