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
- func ReproDigest(res *ScanResult) string
- type ComponentLicenseAudit
- type EvidenceReport
- type FindingQuality
- type LicenseCoverageBreakdown
- type NeedsVerifyFinding
- type ScanDrift
- type ScanOptions
- type ScanResult
- type Service
- func (s *Service) AddManifestResolver(r ports.ManifestResolver)
- func (s *Service) CompareRuns(ctx context.Context, runA, runB string) (ScanDrift, error)
- func (s *Service) CycloneDX(ctx context.Context, engagementID shared.ID) ([]byte, error)
- func (s *Service) FailStrandedScanJob(ctx context.Context, payload []byte, cause error) error
- func (s *Service) ImportSBOM(ctx context.Context, actor string, tenantID, engagementID shared.ID, ...) (*ScanResult, error)
- func (s *Service) ImportSBOMFile(ctx context.Context, actor string, tenantID, engagementID shared.ID, ...) (*ScanResult, error)
- func (s *Service) ImportedSBOMMetadata(ctx context.Context, tenantID, engagementID shared.ID) (importedsbom.Metadata, error)
- func (s *Service) LatestJob(ctx context.Context, engagementID shared.ID) (ports.ScanJob, error)
- func (s *Service) LatestJobs(ctx context.Context, engagementIDs []shared.ID) (map[shared.ID]ports.ScanJob, error)
- func (s *Service) LatestResult(ctx context.Context, engagementID shared.ID) ([]byte, error)
- func (s *Service) ReportInsight(ctx context.Context, engagementID shared.ID) (ports.ReportInsight, error)
- func (s *Service) RunScanJob(ctx context.Context, payload []byte) error
- func (s *Service) SPDX(ctx context.Context, engagementID shared.ID) ([]byte, error)
- func (s *Service) SPDX3(ctx context.Context, engagementID shared.ID) ([]byte, error)
- func (s *Service) Scan(ctx context.Context, actor string, engagementID shared.ID, ...) (*ScanResult, error)
- func (s *Service) ScanRuns(ctx context.Context, engagementID shared.ID) ([]ports.ScanRun, error)
- func (s *Service) ScanWithOptions(ctx context.Context, actor string, engagementID shared.ID, ...) (*ScanResult, error)
- func (s *Service) SetCodeQuality(q interface{ ... })
- func (s *Service) SetComplianceEnabled(on bool)
- func (s *Service) SetCorrelation(r ports.CorrelationRecorder)
- func (s *Service) SetDBMaxAgeDays(days int)
- func (s *Service) SetDetectionPriority(p string)
- func (s *Service) SetFPTriage(t ports.FPTriager)
- func (s *Service) SetGateDecoder(decoder ports.GateDecoder)
- func (s *Service) SetGradleResolver(r ports.GradleResolver)
- func (s *Service) SetGraphResolver(r ports.DependencyGraphResolver)
- func (s *Service) SetIgnoreUnfixed(v bool)
- func (s *Service) SetImportedSBOMStore(store ports.ImportedSBOMStore)
- func (s *Service) SetIncludeTestSecrets(v bool)
- func (s *Service) SetInstalledPackageCataloger(c ports.InstalledPackageCataloger)
- func (s *Service) SetJVMReachability(a ports.JVMReachabilityAnalyzer)
- func (s *Service) SetJarChecksumResolver(r ports.JarChecksumResolver)
- func (s *Service) SetJarHashResolver(r ports.JarHashResolver)
- func (s *Service) SetLicenseFileResolver(r ports.LicenseFileResolver)
- func (s *Service) SetMavenCoordResolver(r ports.MavenCoordResolver)
- func (s *Service) SetMavenResolver(r ports.MavenResolver)
- func (s *Service) SetMisconfigScanner(m ports.MisconfigScanner)
- func (s *Service) SetNPMResolver(r ports.NPMResolver)
- func (s *Service) SetOSPackageCataloger(c ports.OSPackageCataloger)
- func (s *Service) SetProjectAnalysisRecorder(r interface{ ... })
- func (s *Service) SetPyReachability(r ports.ReachabilityRecorder)
- func (s *Service) SetQueue(q ports.JobQueue)
- func (s *Service) SetReachability(r ports.ReachabilityRecorder)
- func (s *Service) SetRunLock(l ports.RunLocker)
- func (s *Service) SetSASTAnalyzer(a ports.SASTAnalyzer)
- func (s *Service) SetSBOMCache(c ports.SBOMCache)
- func (s *Service) SetSBOMCrossCheck(producer ports.SBOMGenerator, r ports.SBOMCrossCheckRecorder)
- func (s *Service) SetSBOMEnricher(e ports.SBOMEnricher)
- func (s *Service) SetSecretScanner(sc ports.SecretScanner)
- func (s *Service) SetSeverityEnricher(e ports.SeverityEnricher)
- func (s *Service) SetSuppressionLoader(l ports.SuppressionLoader)
- func (s *Service) SetTaint(t ports.TaintScanner)
- func (s *Service) SetVEXLoader(l ports.VEXLoader)
- func (s *Service) StartScan(ctx context.Context, actor string, engagementID shared.ID, ...) (ports.ScanJob, error)
- func (s *Service) StartScanWithOptions(ctx context.Context, actor string, engagementID shared.ID, ...) (ports.ScanJob, error)
- func (s *Service) SweepStaleScans(ctx context.Context, staleFor time.Duration) (int, error)
- func (s *Service) VerifyEvidence(ctx context.Context, engagementID shared.ID) (EvidenceReport, error)
- type SuppressedFinding
Constants ¶
const ( ScanModeFull = "full" ScanModeVulnerabilities = "vulnerabilities" ScanModeLicenses = "licenses" )
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" )
const ScanJobKind = "sca"
ScanJobKind is the durable-queue Kind for an SCA scan.
Variables ¶
This section is empty.
Functions ¶
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 ComponentLicenseAudit ¶
type ComponentLicenseAudit struct {
Component string `json:"component"`
Version string `json:"version"`
PURL string `json:"purl"`
Scope string `json:"scope"`
Location string `json:"location"`
License string `json:"license"`
Category sbom.LicenseCategory `json:"category"`
Verdict ports.LicenseVerdict `json:"verdict"`
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"`
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"`
// 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"`
// 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 an optional LLM false-positive critique of first-party source findings (opt-in,
// best-effort). Each entry is the model's PROPOSED verdict; a suspected-FP entry is retain-and-mark
// (the finding stays reported here and sealed, it is only held back from the CI gate), never a
// deletion. Populated by the injected ports.FPTriager for BOTH the CLI and the durable API scan job;
// empty unless the FP-triage gate ran.
AITriage []ports.AICritique `json:"ai_triage,omitempty"`
}
ScanResult is the aggregate output of an SCA scan.
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 the set of finding DedupKeys the AI triage marked as suspected false positives (retain-and-mark). A --fail-on gate exempts these (still reported + sealed), the same way it exempts accepted-risk and needs-verify findings.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service orchestrates the SCA pipeline over swappable ports.
func NewService ¶
func NewService( engagements ports.EngagementRepository, findings ports.FindingRepository, scans ports.ScanRepository, results ports.ScanResultStore, jobs ports.ScanJobStore, runs ports.ScanRunStore, ev *evidenceuc.Service, ids ports.IDGenerator, prov ports.Provenance, clock ports.Clock, audit ports.AuditLogger, minSeverity shared.Severity, timeout time.Duration, a ports.Acquirer, d ports.LanguageDetector, s ports.SBOMGenerator, sources []ports.DetectionSource, r ports.RiskEnricher, l ports.LicenseScanner, le ports.LicenseEnricher, ) *Service
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) 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) CompareRuns ¶
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 ¶
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 ¶
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) 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 ¶
LatestJob returns the engagement's most recent scan job (for the status poll).
func (*Service) LatestJobs ¶
func (*Service) LatestResult ¶
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 ¶
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 ¶
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 ¶
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) ScanRuns ¶
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) SetCodeQuality ¶
func (*Service) SetComplianceEnabled ¶
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 ¶
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 ¶
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 ¶
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; a suspected-FP is retain-and-mark (gate-exempt via SuspectedFPKeys, still reported + sealed). Best-effort; nil = no triage.
func (*Service) SetGateDecoder ¶
func (s *Service) SetGateDecoder(decoder ports.GateDecoder)
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 ¶
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) SetImportedSBOMStore ¶
func (s *Service) SetImportedSBOMStore(store ports.ImportedSBOMStore)
SetImportedSBOMStore configures the engagement-scoped client SBOM artifact store.
func (*Service) SetIncludeTestSecrets ¶
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) 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) 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) 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) 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 (`mvn dependency:list`). 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 (dpkg/apk) from a materialized image rootfs (Workspace.RootFS). nil ⇒ no owned OS cataloging. It only runs when a rootfs was materialized.
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) 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) SetQueue ¶
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 ¶
SetRunLock guards against duplicate concurrent execution of the same scan job under at-least-once queue redelivery.
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 ¶
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 optional SBOM-producer cross-check: a SECOND SBOM producer plus the disagreement→judgment recorder. nil either ⇒ no cross-check. Best-effort + opt-in: 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) SetSecretScanner ¶
func (s *Service) SetSecretScanner(sc ports.SecretScanner)
SetSecretScanner configures the optional deterministic secret scanner. nil ⇒ no secret scanning.
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) 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) SetVEXLoader ¶
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) 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 (*Service) SweepStaleScans ¶
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) 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.