README
¶
scanner-worker
Purpose
scanner-worker runs claim-driven scanner work for security analyzers that are
too CPU-heavy or memory-heavy for reducer lanes. The installed binary is
eshu-scanner-worker.
Flow
flowchart LR
workflow["workflow work item"] --> claim["scanner-worker claim"]
claim --> input["scannerworker.ClaimInput"]
input --> analyzer["bounded analyzer"]
analyzer --> facts["scanner source facts\nscanner_worker.* / sbom.* / vulnerability.os_package"]
facts --> postgres["Postgres fact store"]
postgres --> reducers["reducers admit findings"]
Runtime Contract
- Selects one enabled, claim-capable
scanner_workercollector instance fromESHU_COLLECTOR_INSTANCES_JSON. - Uses
ESHU_SCANNER_WORKER_ANALYZERor the instanceconfiguration.analyzerto choose a scanner-worker analyzer profile. - Applies analyzer defaults, optional instance
resource_limits, thenESHU_SCANNER_WORKER_*resource overrides. - Emits source facts only and rejects silent clean output before committing.
- Runs the concrete
image_unpackinganalyzer when configured withimage_targets; this source reads configured local image rootfs metadata or ordered OCI layer tar streams, extracts Alpine apk or Debian dpkg installed package databases, and emitsscanner_worker.analysiscoverage,vulnerability.os_package,vulnerability.warning, orscanner_worker.warningunsupported evidence. - Runs the concrete
sbom_generationanalyzer when configured withsbom_targets; this source walks a configured repository root, reads boundedpackage-lock.json,npm-shrinkwrap.json,go.mod,Cargo.lock,composer.lock,packages.lock.json,Pipfile.lock,poetry.lock,Gemfile.lock, andgradle.lockfilelockfile evidence, and emitssbom.document,sbom.component, andsbom.warningfacts. - Runs the concrete
os_package_extractionanalyzer when configured withos_package_targets; this parser consumes already-extracted Alpine or Debian rootfs metadata and emitsvulnerability.os_package/vulnerability.warningfacts. - Records retry and dead-letter payloads with locator hashes and bounded failure classes.
- Exposes
/healthz,/readyz,/metrics,/admin/status, and optional private pprof throughESHU_PPROF_ADDR.
The fallback analyzer emits an explicit scanner_worker.warning source fact
(reason=analyzer_not_configured). sbom_generation falls back to
reason=sbom_generator_source_not_configured when no sbom_targets are
configured. Concrete secret, license, source, and misconfiguration analyzers
must plug into this boundary instead of running in reducer lanes.
image_unpacking targets are configured inside the selected scanner_worker
collector instance:
{
"analyzer": "image_unpacking",
"image_targets": [
{
"scope_id": "image://registry.example/team/app@sha256:...",
"rootfs_path": "/var/lib/eshu/scanner/rootfs/...",
"layer_paths": ["/var/lib/eshu/scanner/layers/layer.tar.gz"],
"source_uri": "oci://registry.example/team/app@sha256:...",
"source_record_id": "sha256:...",
"image_reference": "registry.example/team/app:1.2.3",
"image_digest": "sha256:..."
}
]
}
rootfs_path and layer_paths are runtime-local configuration. They must not
appear in retry, dead-letter, metric, log, or public documentation payloads.
Layer paths are ordered from base to top layer. Unsupported image shapes emit
scanner_worker.warning facts with analysis_status=not_scanned,
coverage_status=unsupported, and an extraction_reason instead of clean
results. Missing image digests are unsupported coverage evidence; tag-only
image configuration does not emit package facts.
sbom_generation repository targets are configured inside the selected
scanner_worker collector instance:
{
"analyzer": "sbom_generation",
"sbom_targets": [
{
"scope_id": "scanner-worker://repository/team-api",
"root_path": "/var/lib/eshu/scanner/repositories/team-api",
"subject_digest": "sha256:..."
}
]
}
The repository path is runtime-local configuration. It must not appear in
retry, dead-letter, metric, log, or public documentation payloads. If no usable
components are found, the analyzer emits a document fact plus an
sbom.warning fact instead of returning silent clean output. Component facts
preserve bounded evidence fields: ecosystem, repository-relative
lockfile_path, evidence_source, package name, installed version, PURL,
dependency scope/type when the lockfile reports it, and
extraction_reason="lockfile_exact_version". Malformed supported lockfiles
emit sbom.warning with reason="lockfile_malformed" and the relative
lockfile path; they do not leak the runtime-local repository root.
NPM package-lock.json package entries may encode dependency edges as version
range strings. Those ranges are accepted so the lockfile remains usable, but
they are not emitted as installed-version components unless a sibling lockfile
entry supplies the exact installed version.
The repository walk counts only supported manifest and lockfile inputs toward
FileCount and ESHU_SCANNER_WORKER_MAX_FILES; ignored directories and
unsupported regular files do not consume the SBOM input-file budget.
os_package_extraction targets are configured inside the selected
scanner_worker collector instance:
{
"analyzer": "os_package_extraction",
"os_package_targets": [
{
"scope_id": "image://registry.example/team/app@sha256:...",
"rootfs_path": "/var/lib/eshu/scanner/rootfs/...",
"source_uri": "oci://registry.example/team/app@sha256:...",
"source_record_id": "sha256:..."
}
]
}
The rootfs path is runtime-local configuration. It must not appear in retry, dead-letter, metric, log, or public documentation payloads.
Environment
| Variable | Purpose |
|---|---|
ESHU_SCANNER_WORKER_INSTANCE_ID |
Select one configured scanner-worker instance when more than one exists. |
ESHU_SCANNER_WORKER_ANALYZER |
Analyzer override such as source_analysis or image_unpacking. |
ESHU_SCANNER_WORKER_POLL_INTERVAL |
Claim poll interval. |
ESHU_SCANNER_WORKER_CLAIM_LEASE_TTL |
Workflow claim lease TTL. |
ESHU_SCANNER_WORKER_HEARTBEAT_INTERVAL |
Claim heartbeat interval; must be less than lease TTL. |
ESHU_SCANNER_WORKER_CPU_MILLIS |
Analyzer CPU budget in millicores. |
ESHU_SCANNER_WORKER_MEMORY_BYTES |
Analyzer memory budget in bytes. |
ESHU_SCANNER_WORKER_TIMEOUT |
Analyzer timeout. |
ESHU_SCANNER_WORKER_MAX_INPUT_BYTES |
Maximum analyzer input bytes. |
ESHU_SCANNER_WORKER_MAX_FILES |
Maximum analyzer input files per claim. |
ESHU_SCANNER_WORKER_MAX_FACTS |
Maximum source facts emitted per claim. |
Evidence
No-Regression Evidence: scanner-worker runtime behavior is covered by
go test ./internal/collector/scannerworker ./internal/collector/scannerworker/imageanalyzer ./internal/collector/scannerworker/sbomgenerator ./internal/collector/ospackagevulnerability/osruntime ./cmd/scanner-worker -count=1.
No-Regression Evidence: go test ./cmd/scanner-worker -run 'TestRepositorySBOMSource(ParsesNPMPackageDependencyRanges|ParsesCargoAndComposerLockfiles|ParsesPythonRubyAndGradleLockfiles|EmitsMalformedLockfileWarning)|TestNPMLockDependencyUnmarshalStringResetsPriorObject' -count=1
proved repository SBOM generation accepts npm package dependency range maps,
extracts Cargo, Composer, PyPI, RubyGems, Gradle/Maven, and NuGet exact
lockfile components with ecosystem, relative path, dependency scope/type, PURL,
and extraction reason, while malformed Composer lockfiles produce bounded
sbom.warning evidence instead of terminal analyzer failure or silent clean
output.
Observability Evidence: the runtime records scanner-worker claim, retry,
dead-letter, facts-emitted, queue-wait, scan-duration, target-count,
result-count, CPU, and memory metrics, plus scanner_worker.* spans and
bounded structured failure logs. Post-analysis persistence failures retry as
failure_class=commit_failed and include a bounded commit_failure_class
stage in logs, while analyzer source-read failures remain
source_unavailable. Configured image_unpacking and sbom_generation
sources return measured metadata or manifest input bytes as peak memory usage
and CPU seconds from the Go runtime counters, so operators can distinguish
queue wait, extraction or manifest read cost, source fact volume, retries,
commit-stage failures, and terminal resource-limit failures.
Documentation
¶
Overview ¶
Command scanner-worker runs isolated scanner-worker claims for CPU-heavy or memory-heavy security analyzers.
The binary consumes workflow work items with collector_kind=scanner_worker, builds scannerworker.ClaimInput values with resource limits, commits source facts under the claim fence, and records bounded retry or dead-letter payloads. It can run concrete image_unpacking, sbom_generation repository-manifest, and os_package_extraction rootfs analyzers. Image unpacking emits coverage or unsupported evidence, but the binary does not emit reducer-owned findings.