sca

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Jul 22, 2026 License: Apache-2.0 Imports: 30 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 (
	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 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

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

func (s *Service) CompareRuns(ctx context.Context, 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) 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) 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) 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; 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

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) 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) 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

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) 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 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

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) 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) 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) 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.

Jump to

Keyboard shortcuts

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