Nothing scans the image, so the scan that found these was done by hand #156
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Depends on
Reference
Postulo/postulo#156
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Observation
Everything in the two issues beside this one was found by running a scanner by hand, on a
Raspberry Pi that happened to have
aquasec/trivyandanchore/grypepulled for somethingelse. Neither finding was new. Both had been in the image since it was built.
What exists
Nothing scans the image, and nothing can.
.forgejo/workflows/ci.ymlruns the tests, thelint,
pip-auditover the exported lock,zizmorover the workflows andcheck --deploy—a genuinely careful pipeline — and it never builds a container, because building one needs a
runner advertising the
dockerlabel and none is registered (#81).image.ymlhas never run.pip-auditis the closest thing, and it covers the lock: Postulo's own Pythondependencies, before they are put in an image. It says nothing about the base image, the
apt packages, what
uv syncactually installed, or anything left in a layer.This is the same gap that let #121 ship an image that could not be built at all.
What this asks for
A scan the project runs rather than one somebody remembers to run.
Worth being careful about
It depends on #81 and there is no way around that. Scanning an image requires an image.
Until a runner can build one, the honest options are a scan on whatever machine builds by
hand, or a documented step in the release checklist — both of which are what just happened,
and neither of which is a pipeline.
Both tools, not one. They disagreed usefully here: Grype found the only actionable
Debian update, which Trivy did not mark fixable; Trivy found the Python packages and the
leftover cache, which Grype's
deb-and-binaryscan did not see at all. Running one andbelieving it would have missed half of this.
A threshold that fails the build has to be survivable. Six CRITICAL findings with no fix
available are the normal state of a Debian base image; a pipeline that fails on
--severity CRITICALfails every day for reasons nobody can act on, and is switched offwithin a fortnight. The useful gate is fixable findings — Trivy's
--ignore-unfixed—which on this image today would be one line, and that is a gate worth having.
The tools' own database is a network dependency. Trivy downloads a vulnerability DB; a
build that cannot reach the internet cannot scan. That is fine for CI and worth remembering
before anything depends on it at release time.
An SBOM is the cheap half. Both tools produce one, and a signed SBOM per release is more
useful to somebody self-hosting Postulo than a scan result from the day it was built: it lets
them scan it later, against a database that did not exist yet. That is a small addition to
image.ymland worth considering alongside this.Record what was found rather than only what was fixed. The scan that produced these
issues also produced a clean result — no secrets, no misconfigurations — and that half is
what nobody writes down.
The blocker is gone. The issue said "It depends on #81 and there is no way around
that" — and #81 is closed: a runner advertising the
dockerlabel exists, soimage.ymlcan do more than sit there. This is the pipeline rather than the release-checklist
consolation.
It gates the push. Native-architecture build → scan → multi-architecture push. A scan
after the push would be a report about something already published.
One script, two callers.
scripts/scan-image.shis what a person runs and what theworkflow runs. Two descriptions of one intent drift apart, and the one nobody executes is
always the one that is wrong.
The five warnings
Both tools. They disagreed usefully — Grype found the only actionable Debian update that
Trivy did not mark fixable; Trivy found the Python packages and the leftover uv cache that
Grype's deb-and-binary scan did not see at all. Both, pinned by tag, because a scanner that
changes under you changes what the gate means.
A threshold that fails the build has to be survivable. The gate is
--ignore-unfixedand
--only-fixedat HIGH and above. Six unfixable CRITICALs is the ordinary state of aDebian base image; a build that fails daily for reasons nobody can act on is switched off
within a fortnight. What stops a push is always something somebody can do something about.
The database is a network dependency. Said in the script's header and beside the step,
with the caches mounted as volumes so a second run does not fetch both again.
An SBOM is the cheap half. Taken. CycloneDX, kept as an artefact per run — worth more to
somebody self-hosting Postulo than this run's verdict, because it lets them scan the release
later against a database that does not exist yet. From Trivy rather than a third tool.
Record what was found rather than only what was fixed. The full report — every finding
either scanner saw, fixable or not, plus the secret and misconfiguration scans — goes into
the job summary, and the step runs
if: always()so a failing gate still publishes what itsaw. That clean half is what nobody writes down, and it is the half that says the image is in
the state you think it is.
Checked, since nothing here can run it yet from this machine
Six tests in
tests/test_image_build.py, in the same read-the-file style as the rest of thatfile: the scan step precedes the push step, the workflow calls the script rather than
restating it, both scanners are present and pinned, the gate is on fixable findings, and the
bill of materials leaves the runner.
zizmorpasses on the changed workflow.The first real run belongs to whoever builds the next release image — and with #157 landing
just before this, the before-and-after is worth recording when they do.
Shipped in
55549beon0.3.0, withmainkept level.