Skip to content
About

Validate a proposal without release authority

A pull request is a proposal from source that has not crossed the trusted main boundary. It needs useful validation without the authority to publish an official artifact or sign it as the release workflow. Otherwise an attacker could turn validation of their proposal into distribution of their chosen image.

PR validation versus release authority
PR validation versus release authorityPR jobs build with push:false and run static, image and policy tests. Passing checks are inputs to review; remote branch enforcement is separately unconfirmed. Release jobs require refs/heads/main and an allowed event/confirmation. That guarded path obtains cloud access and creates signed artifacts.PR changeLocal checksMain conditionPublish & sign
The PR branch has local validation; the guarded main path publishes and signs.
  1. PR jobs build with push:false and run static, image and policy tests.
  2. Passing checks are inputs to review; remote branch enforcement is separately unconfirmed.
  3. Release jobs require refs/heads/main and an allowed event/confirmation.
  4. That guarded path obtains cloud access and creates signed artifacts.

Solid arrows indicate the stated handoff, not a claim of independent trust. Optional relationships are described in the text equivalent. Historical components are labeled in the caption.

PR Check triggers for pull requests targeting main without a trigger-level path filter. Its path-detection job decides whether source/security-relevant changes need Semgrep, filesystem Trivy, and policy regression checks. The selected paths include the application, Dockerfile, workflows/actions, policies, Terraform/infrastructure, Helm chart, and CODEOWNERS. Irrelevant changes skip the relevant jobs instead of preventing the workflow from appearing at all.

The reusable security scan temporarily lets the Semgrep command fail so reports can be uploaded, then has an explicit enforcement step when fail-on-findings is true. This caller supplies true. The filesystem Trivy scan uses HIGH/CRITICAL and a nonzero exit code for the blocking caller. A report upload is evidence of findings being published, not proof that the release gate passed.

Separately, Deploy’s PR image job builds the Dockerfile locally with push: false and load: true. Trivy evaluates that local image with HIGH/CRITICAL, exit-code: 1, and the checked-in image ignore file. This catches issues in the assembled runtime image that a source-only view may miss.

PR Check has contents: read, security-events: write, and pull-requests: read; the last permission supports reading the diff. It does not request id-token: write. Deploy’s workflow-level permissions include OIDC for the trusted path, but its PR image job overrides permissions to contents: read and security-events: write. That job has no cloud-authentication step.

The publish job requires github.ref == 'refs/heads/main' and either a push or a manual dispatch with the typed confirmation deploy. Its dependent sign and verify jobs therefore do not run for the pull request ref. The no-publication claim comes from job conditions, permissions, and invoked steps together, rather than from the reassuring name of a check.

The policy tests check identity-string consistency and evaluate the actual provenance JMESPath expressions against a fixture. They do not invoke the Kubernetes API or simulate all admission behavior. A PR’s local image is also distinct from the later main build: changing the ref context, dependencies, or base image can change the final digest.

CODEOWNERS names an owner, and a Terraform ruleset definition defines required checks. Neither proves the remote ruleset is applied. The historical decision record says activation was deferred; the definition deliberately omits an approving-review requirement for the single-maintainer repository.

Read the build stage next. Crossing into main grants artifact authority through the workflow; it does not eliminate defects that the proposal checks failed to detect.