Build, harden, and scan the final artifact
The main build creates the artifact that later controls will identify. Scanning a Dockerfile or dependency manifest alone would leave a gap: the final container also inherits distribution packages, runtime libraries, and build choices. The workflow therefore scans the pushed final image by the digest returned by the build.
Inputs and output identity
Section titled “Inputs and output identity”Build and Push is reusable and is reached by the trusted caller. It checks out the run’s source, authenticates to GCP, builds Dockerfile, injects GIT_SHA, and publishes a Git-SHA tag. The action’s steps.build.outputs.digest becomes a job output and then a caller output. Trivy, signing, and verification receive that digest directly.
The final image scan constructs registry/project/repository/supply-chain-demo@digest. It uses HIGH/CRITICAL, an exit code of 1, and .trivyignore. SARIF upload runs even after a failure. Publication precedes scanning, so a failed scan can leave an image stored in GAR. The dependent signing/verification jobs do not then proceed through the normal chain.
Hardening changes the runtime surface
Section titled “Hardening changes the runtime surface”The Dockerfile builds Python dependencies in a separate stage, removes pip and setuptools from the copied virtual environment, and discards the build-stage compiler. The final stage applies available distribution updates and uses numeric UID/GID 10001. It copies application code and the virtual environment and runs Uvicorn on port 8000.
The Helm deployment adds a read-only root filesystem, disabled privilege escalation, all capabilities dropped, and RuntimeDefault seccomp. These settings constrain the workload. They do not make a vulnerable application invulnerable, establish that the container has no shell, or stop every suspicious process.
Scanner result versus release judgment
Section titled “Scanner result versus release judgment”The ignore file lists explicit CVE exceptions with source comments asserting reasons such as unreachable code paths, architecture mismatch, or pending upstream fixes. Those comments are accepted-exception claims in the historical source, not fresh vulnerability analysis by this website. Some entries refer to an unresolved issue #X; an ignore list needs ownership and reassessment rather than being interpreted as proof of safety.
The dependency stage installs declared requirements through pip, upgrades build tooling, and resolves distribution packages at build time. Both base stages use the mutable tag python:3.12-slim-trixie. Therefore a source commit does not by itself imply a reproducible, hermetic, or bit-identical build. The runtime digest pins the produced artifact; it does not pin every input that produced it.
Evidence and handoff
Section titled “Evidence and handoff”Historical records include the main pipeline and the GAR digest, while a later strict CI run produced a different verified digest that was not selected in Helm. Use scope and revision boundaries when associating a recorded artifact with a particular source run. A “build passed” conclusion is limited to that invocation and its configured scanner policy.
Continue with cloud identity to understand how this workflow obtains registry authority, then keyless signing to see which identity makes the artifact claim.