Documentation
¶
Overview ¶
Package scanpipeline runs the scan pipeline that assembles a neutral sbom.Inventory. Run is the full flow over a source path: collect files → fingerprint → scan → source declared dependencies from the same files → gather + enrich the requested layers via the SDK's decoration pipeline (scanoss.DecorationPipeline). Enricher is the gathering half on its own, for callers that already have an inventory (a scan result, or a parsed SBOM). Rendering is left to sbom.Generate — this package does not render. Layers to gather are driven by the caller's request, never by any output format.
Index ¶
Constants ¶
const ( LayerCollect = "collect" // local: walking the tree and applying the filters LayerFingerprint = "fingerprint" // local: hashing the collected files LayerManifests = "manifests" // local: parsing dependency manifests LayerUpload = "upload" // remote: uploading the WFP LayerScan = "scan" // remote: the server-side scan )
Layers the pipeline runs itself or delegates. Enrichment layers are not listed: they report under their API service name, which the SDK already supplies.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Enricher ¶ added in v0.8.0
type Enricher struct {
Client *scanoss.Client
Services []scanoss.Service
Reporter scanoss.DecorationReporter
}
Enricher is what the requested layers are gathered with: a client to ask, the layers to ask for, and who to report progress to. Run builds one from its Options; a caller that already has an inventory — from a scan result, or parsed from an existing SBOM — builds one directly.
The zero Services asks for nothing, which is not an error: a bare scan does no decoration work.
func (Enricher) Enrich ¶ added in v0.8.0
Enrich attaches the requested purl-layers to the inventory's components in place — licenses/cryptography/geoprovenance inline on each component, vulnerabilities as the flat top-level list. It is format-blind, keyed purely by PURL (+ version).
Enrichment is non-fatal, so the inventory is usable whatever this returns: a layer that failed is simply absent. The error names what did not arrive, which is the only way to tell an inventory with no licences because the project declares none from one with no licences because every request failed. With no layer requested, or no component to decorate, it makes no API call and returns nil.
type Options ¶
type Options struct {
Client *scanoss.Client // required
// Services are the decoration services to gather over the components. The caller resolves
// these — from a flag, a config file, or nothing at all — and hands over the result: this
// package knows services, not whatever vocabulary produced them.
Services []scanoss.Service
// SourceDeclared asks for declared dependencies to be sourced from the dependency manifests in
// the same tree, and merged into the inventory alongside the scan's detected components. It is
// not a decoration service: nothing is fetched, the manifests already carry resolved PURLs.
SourceDeclared bool
SourcePath string // file or directory to scan (required)
Threads int // fingerprint workers (<1 => 1)
// ScanFilters collects the files to fingerprint; DependencyFilters collects the
// manifests, when SourceDeclared asks for them.
//
// Both are the caller's to build, because only the caller knows which of the values
// in them came from a user flag and which from a profile. This package used to
// derive the second from the first by copying selected fields, which meant a field
// the dependency profile had deliberately set was overwritten by the scan's.
ScanFilters filter.Options
DependencyFilters filter.Options
ScanOptions []scanoss.ScanOption // per-scan tuning (chunk size, poll interval, BOM, ...)
// WFPWriter, when set, receives the WFP as it is generated, block by block. It is how a
// caller keeps the WFP: pass a file to save it, a bytes.Buffer to hold it in memory. Nil
// discards it after upload, which costs nothing. Block order is completion order.
WFPWriter io.Writer
// OnProgress receives every layer's progress. Optional; nil reports nothing. The pipeline runs
// layers concurrently, so it must be safe for concurrent use.
OnProgress func(Progress)
}
Options configures Run, the full scan pipeline over a source path. Every layer reports through OnProgress — the steps the pipeline runs itself and the ones it delegates to the SDK alike, so a caller listens on one channel rather than reconciling two.
type Progress ¶ added in v0.5.0
type Progress struct {
Layer string // which layer is reporting; see the Layer* constants
Status Status // where that layer is
Done int // units done, only ever growing
Total int // units in total; 0 when the layer cannot say
}
Progress is one update from one pipeline layer, whether the pipeline ran that layer itself or delegated it to the SDK. Every field means the same thing for every layer, so a consumer can render any update without knowing which layer produced it, or how that layer works.
Done and Total only ever grow within a layer. Where the underlying work says otherwise — the server-side scan runs in passes that each restart their own counter — it is normalised here, so that no consumer has to know.
type Reporter ¶ added in v0.5.0
type Reporter struct {
// contains filtered or unexported fields
}
Reporter turns the SDK's stages into this package's layer updates. Run wires one up itself; it is exported for the callers that drive the SDK directly — `results` resumes a scan and enriches it, collecting and fingerprinting nothing — so that every entry point reports layers the same way and the translation exists in one place.
Hand it to a call with WithScanReporter and WithDecorationReporter — the reporter belongs to the operation, not to the client, so the same client can serve several with different listeners.
func NewReporter ¶ added in v0.5.0
NewReporter returns a Reporter delivering to on. A nil on makes every update a no-op.
func (*Reporter) Decorating ¶ added in v0.5.0
Decorating names the layer after the service that reported it, which is what a consumer sees.
func (*Reporter) Fingerprinting ¶ added in v0.5.0
func (*Reporter) Scanning ¶ added in v0.5.0
func (r *Reporter) Scanning(e scanossapi.ScanEnvelope)
Scanning normalises the poll: the server restarts its counter on every pass, so each pass owns a share of the layer's range and the result only ever grows.
type Result ¶
type Result struct {
Inventory sbom.Inventory
// ProcessErrors are the files that could not be fingerprinted, as pkg/wfp reported them.
// A scan of 3000 files that skipped 3 unreadable ones still produced a usable WFP, so these
// are not fatal — but which file failed and why is the caller's to judge, and a count alone
// cannot answer it. Empty when every file was fingerprinted.
ProcessErrors []error
// EnrichError reports that the requested layers did not all come back. The pipeline stays
// non-fatal — a service that fails does not discard a scan — so this is how a caller tells an
// inventory with no licences because the project declares none from one with no licences
// because every request failed. Nil when everything asked for arrived.
EnrichError error
}
Result is the outcome of Run: the gathered inventory, the files that could not be fingerprinted, and whether enrichment came back whole. The WFP is not here — it streams through a temporary file, and a caller that wants it passes Options.WFPWriter.
What the filters excluded is not here: it is reported as the collect layer completing, while the scan is still ahead, rather than handed back once everything is over.
func Run ¶
Run executes the full pipeline over Options.SourcePath: collect the files (applying the filters for a directory), fingerprint them, scan, source declared dependencies from the same file set (when the deps layer is requested), and gather + enrich into an Inventory. It owns everything from file collection onward; the caller supplies only flag-derived configuration.