fix(docker): build mkcert from source; correct the trivyignore paths - #105
Merged
Merged
Conversation
The v1.3.6 tag push reached the Trivy CRITICAL gate and was blocked, so nothing was published. Two separate causes, neither of them the tar CVE that was fixed in d19a32c (that one is genuinely gone). 1. usr/local/bin/mkcert carries four CRITICAL Go stdlib vulnerabilities: CVE-2023-24538, CVE-2023-24540, CVE-2024-24790 and CVE-2025-68121. The upstream pre-built binary is v1.4.4, published 2022-04-26 and compiled with Go 1.18. There is no newer release to bump to — v1.4.4 IS the latest and has been for four years. So mkcert is now compiled from that same source with Go 1.27: identical behaviour, patched stdlib. The stage uses --platform=$BUILDPLATFORM with GOOS/GOARCH cross-compilation so it stays native on the builder rather than running under QEMU once per architecture, and `go build -o` rather than `go install`, because when cross-compiling `go install` writes to /go/bin/${GOOS}_${GOARCH}/ and the COPY would silently miss it. 2. The gcp-service-account suppression never matched. Trivy reports image paths with a leading slash — the gate log shows "/app/.next/server/app/cloud/gcp/page.js" — and .trivyignore.yaml listed the paths without one. The analysis behind that entry was right; only the paths were wrong. Both forms are now listed, so it works for an image scan and a filesystem scan alike. Still scoped to the two GCP bundles, so a real credential anywhere else in the image still fails the gate. Verified with `docker build --check` (clean, and it resolves golang:1.27-alpine). A full local build was skipped deliberately: swap was at 71%, above the 50% throttle in the local-resource-ceiling rule, and this machine has panicked from concurrent heavy compiles before. CI does the real build. Note the gate placement: Trivy only runs inside docker-publish.yml, which runs on tag push / dispatch / manual — never on a pull request. So image CVEs cannot be caught before merge; they surface only when a publish is attempted. That is how four CRITICALs sat undetected. Worth fixing separately.
release.yml pushed nself/nself-admin:<version>, :<major>.<minor>, :<major> and :latest with `push: true` and NO vulnerability scan, on the same `push: tags: v*` trigger as docker-publish.yml. docker-publish.yml has a Trivy CRITICAL gate. This workflow did not. So every tag push raced two publishers of the same image, and the ungated one could ship a build the gate had just rejected. A security gate another workflow can walk around is not a gate. That is not hypothetical. On the v1.3.6 tag push (2026-09-12) docker-publish correctly blocked on four CRITICAL Go stdlib CVEs in mkcert, while this workflow was already mid-push of the same image. It had to be cancelled by hand to stop :latest moving to a known-vulnerable build. Verified afterwards that no version tag landed: :latest still reads 2026-06-18, and 1.3.6 / 1.3 were never created. Image publication now belongs to docker-publish.yml alone. It owns the Trivy gate, the multi-arch manifest verification (S49-T06), and the NSELF_VERSION build-arg that this job never even passed — so the image it built pinned whatever the Dockerfile ARG defaulted to rather than the released CLI. This workflow keeps the GitHub Release: changelog, archive, release body, notification. `Extract version from tag` stays, since those steps use it.
acamarata
added a commit
that referenced
this pull request
Sep 12, 2026
…st (#106) Three triggers feed this workflow -- tag push, cli-release dispatch and manual dispatch -- and nothing stopped them overlapping. On 2026-09-12 two dispatches for 1.3.6 ran at once (17:02:37 and 17:04:52) and one had to be cancelled by hand. Both would have pushed :X.Y.Z, :X.Y, :X and :latest. The last writer of :latest wins, so a slower run of an OLDER version can land on top of a newer one and silently become what every `docker pull nself/nself-admin` receives. #105 had just removed release.yml's ungated publisher for the same class of reason; this is the same problem one layer up, between two runs of the gated publisher itself. The group is a constant, not the version. Serialising per-version would still let 1.3.6 and 1.3.7 race, and the shared floating tags are exactly what they contend for. One image, one publisher. cancel-in-progress is false deliberately. Cancelling a publish mid-push is not a safe stop -- that is what happened to release.yml on v1.3.6, killed partway through pushing with the manifest unfinished. A queued run costs minutes; a half-pushed manifest is a broken :latest. Trade-off worth stating: GitHub keeps only one pending run per group, so a third request cancels the second while it waits. That is correct for the duplicate-dispatch case this fixes (same version twice -- drop the redundant one). For three distinct versions queued at once it would drop the middle; the Hygiene release-tag gate catches a version whose image never published, and releases here are sequential and rare. Pure addition: no existing key changed. Verified the workflow still parses with all three triggers and the docker-publish job intact.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The
v1.3.6tag push reached the Trivy CRITICAL gate and was blocked, so nothing was published. Two separate causes — neither of them thetarCVE fixed ind19a32c, which is genuinely gone.1. mkcert carries four CRITICAL Go stdlib CVEs
The upstream pre-built binary is v1.4.4, published 2022-04-26, compiled with Go 1.18. There is no newer release to bump to — v1.4.4 is the latest and has been for four years.
So mkcert is now compiled from that same source with Go 1.27: identical behaviour, patched stdlib.
Two details worth keeping:
--platform=$BUILDPLATFORM+GOOS/GOARCHcross-compilation, so the stage stays native on the builder instead of running under QEMU once per architecture.go build -orather thango install— when cross-compiling,go installwrites to/go/bin/${GOOS}_${GOARCH}/, and theCOPYwould silently miss it.2. The gcp-service-account suppression never matched
Trivy reports image paths with a leading slash:
.trivyignore.yamllisted them without one, so the entry matched nothing and this false positive kept blocking the publish. The analysis behind that entry was correct; only the paths were wrong. Both forms are now listed, so it works for an image scan and a filesystem scan alike — still scoped to the two GCP bundles, so a real credential anywhere else in the image still fails the gate.Verification
docker build --checkpasses clean and resolvesgolang:1.27-alpine.A full local build was skipped deliberately: swap was at 71%, above the 50% throttle in the local-resource-ceiling rule, and this machine has panicked from concurrent heavy compiles before. CI does the real build.
Gate placement — worth a separate fix
Trivy runs only inside
docker-publish.yml, which triggers on tag push / dispatch / manual — never on a pull request. So image CVEs cannot be caught before merge; they surface only when a publish is attempted. That is how four CRITICALs sat undetected whilemulti-arch-check.ymlwent green on every PR — it builds with--output type=cacheonlyand runs no scan at all.Not fixed here. Flagging it because a green PR is currently not evidence that the image is publishable.