Documentation
¶
Overview ¶
Package scanner provides pluggable pre-cache artifact scanning.
A Scanner inspects an artifact staged in the proxy's own storage before it becomes visible to clients, and returns a verdict on whether it may be cached. The proxy never uploads artifact bytes to a scanner directly: it hands the scanner a short-lived signed URL and the scanner pulls the bytes itself. See HTTPScanner for the built-in adapter that implements this over a small HTTP/JSON contract, letting trivy, ClamAV, Wiz, or any custom service integrate without the proxy needing built-in knowledge of any specific tool.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Group ¶
type Group struct {
// contains filtered or unexported fields
}
Group runs a set of configured Scanners concurrently and turns their individual verdicts into a single decision.
func NewGroup ¶
NewGroup builds a Group from cfg. If cfg.Enabled is false, the returned Group has no entries and Enabled() reports false, so callers can skip the scan path entirely.
func (*Group) Scan ¶
Scan runs every scanner applicable to req.Ecosystem concurrently, never sequentially, and returns a single decision.
The moment any "block" mode scanner reports Allowed: false (or errors, unless FailOpen is set), Scan cancels a context shared by every goroutine: in-flight calls to the other scanners are aborted rather than waited out, since a single block already decides the outcome. Scan still waits for all goroutines to observe that cancellation and return before it itself returns, so no scan call outlives this method call.
If nothing blocks, Scan waits for every "block" mode scanner to finish before reporting Allowed: true — an allow decision can't be finalized until all of them have answered. "monitor" mode scanners never gate the wait or trigger cancellation: a monitor verdict of Allowed: false is logged and folded into Result.Findings, but never blocks.
type HTTPScanner ¶
type HTTPScanner struct {
// contains filtered or unexported fields
}
HTTPScanner adapts an external HTTP scanning service to the Scanner interface. It POSTs a small JSON notification describing the staged artifact, including a signed fetch URL; the external service is responsible for GETting that URL itself, running the real scan against those bytes, and replying with a verdict before the request's deadline.
Request body:
{
"ecosystem": "npm", "name": "left-pad", "version": "1.0.0",
"filename": "left-pad-1.0.0.tgz", "purl": "pkg:npm/left-pad@1.0.0",
"content_type": "application/octet-stream", "size": 1234,
"fetch_url": "https://proxy.internal/_internal/scan-fetch?..."
}
Response body:
{
"allowed": true, "reason": "",
"findings": [{"severity": "high", "title": "...", "description": "..."}]
}
Any compliant adapter — a trivy wrapper, a clamav-rest bridge, a Wiz connector, or an in-house service — need only implement this contract.
func NewHTTPScanner ¶
NewHTTPScanner creates an HTTPScanner named name that notifies url of staged artifacts, attaching headers to every request (e.g. for auth). If client is nil, http.DefaultClient is used.
func (*HTTPScanner) Name ¶
func (s *HTTPScanner) Name() string
Name returns the scanner's configured name.
type Request ¶
type Request struct {
Ecosystem string `json:"ecosystem"`
Name string `json:"name"`
Version string `json:"version"`
Filename string `json:"filename"`
PURL string `json:"purl"`
ContentType string `json:"content_type"`
Size int64 `json:"size"`
// FetchURL is a short-lived signed URL the scanner must GET itself to
// retrieve the exact bytes staged in the proxy's storage.
FetchURL string `json:"fetch_url"`
}
Request describes a staged artifact awaiting a scan verdict.
type Result ¶
type Result struct {
Allowed bool
Reason string
Findings []Finding
// ScannerName identifies which scanner produced this result. Set by
// Group, not by individual Scanner implementations.
ScannerName string
// InfraError reports whether Allowed: false was forced by a scanner
// call failing (network error, timeout, bad response) rather than an
// actual verdict from the scanner. Set by Group. Callers that surface
// Reason to untrusted clients must not do so when this is true: it may
// contain raw connection errors (internal hostnames, ports) instead of
// a verdict meant to be shown outside the proxy.
InfraError bool
}
Result is a scanner's verdict for a Request.
type Scanner ¶
type Scanner interface {
// Name identifies this scanner in logs and metrics.
Name() string
// Scan requests a verdict for req. Implementations must respect ctx
// cancellation: Group cancels in-flight scans once a blocking verdict
// has already been decided by another scanner.
Scan(ctx context.Context, req Request) (Result, error)
}
Scanner is the extension point for pluggable pre-cache scanning.