Scan, attest and sign the published Docker images

Aperta
#207 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 2 giorni

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
42/100
Tipo di issue
Funzionalità
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
docker, github-actions, python

Direzione di ricerca

Read CONTRIBUTING.md first, then inspect Dockerfile, .github/workflows/docker.yaml, and deploy-prod.yaml after #203. Check the existing release build and image publication flow before reviewing the requested Trivy, attestation, digest-pinning, signing, and README verification steps. Done means PR and release images meet every acceptance criterion and the workflow is validated on a fork.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

enhancement tests and ci/cd

🔄 Updated for v5.0.0 (2026-10-08). Rewritten for the current CI. Since this was written, the image is built once per commit by the shared build_push_image.yml workflow in pesu-dev/actions (#203, #223, #224), which sets provenance: false. Images are multi-arch and published to GHCR, then copied to Docker Hub on release. The base images changed too, and the uv image is pulled as latest. The four protections are still missing; where each one now goes is updated below.

Summary

Nothing checks the published Docker images for known vulnerabilities, nothing records what's inside them, and nothing proves that they were built by this repository's CI. Add the standard supply-chain protections for container images:

  1. Vulnerability scanning with Trivy.
  2. An SBOM and build provenance.
  3. Base images pinned by digest.
  4. Keyless signing with cosign.

Background

  • The Dockerfile uses python:3.14-slim-bookworm (builder and runtime) and copies uv from ghcr.io/astral-sh/uv:latest, all by tag. A tag can be moved to point at a different image at any time, and latest moves on every uv release.
  • Where images are built:
    • every PR: the Build image on PR job (pr_image_build in ci_checks.yml, shared build_push_image.yml, no push), plus a local docker build in the Container security & smoke test job (container_checks), which runs the image and checks it runs as UID 10001;
    • every merge to dev: deploy_staging.yml builds and pushes ghcr.io/pesu-dev/pesu-auth:<sha> for linux/amd64 and linux/arm64, then tags it staging;
    • every release: deploy_prod.yml builds the approved commit the same way, and its release job tags it vX.Y.Z, latest and prod on GHCR and copies it to Docker Hub (pesudev/pesu-auth) with docker buildx imagetools create.
  • The shared workflow passes provenance: false to docker/build-push-action, so no attestations are pushed today.
  • Render does not run these images. It builds the Dockerfile itself from the deployed commit. Signing and SBOMs protect the published images that people pull, not what runs on pesuauth.onrender.com. Pinning base images by digest protects both.
  • The repo's security settings (Dependabot security updates, secret scanning) are maintainer settings, tracked in #209.

Proposed change

  1. Scan on every PR: in container_checks, after docker build, run aquasecurity/trivy-action on pesu-auth-test with severity: CRITICAL,HIGH and ignore-unfixed: true, failing the job on findings. Add a .trivyignore (empty to start), with a comment saying each entry needs a reason and an expiry date.
  2. Scan on release too, and upload the SARIF report to the Security tab (github/codeql-action/upload-sarif). That needs security-events: write on that job only.
  3. SBOM and provenance: add inputs to build_push_image.yml in pesu-dev/actions to turn on sbom: true and provenance: mode=max (keeping today's behaviour as the default), and pass them from the two deploy workflows here. They're pushed with the image as attestations. Check that the release job's docker buildx imagetools create --prefer-index=false keeps them on the vX.Y.Z, latest and prod tags, and on Docker Hub.
  4. Pin base images by digest: FROM python:3.14-slim-bookworm@sha256:<digest>, and the same for the uv image, replacing latest with an exact version (ghcr.io/astral-sh/uv:<version>@sha256:<digest>). Keep the tag in the line for readability. #209 adds Dependabot's docker ecosystem, which keeps digests current. Without it, pinned digests go stale and miss security fixes, so these two issues should land together or in that order.
  5. Sign: install sigstore/cosign-installer, then cosign sign --yes <image>@<digest> for both registries after the release tags are created, using GitHub's OIDC token (keyless). The job needs id-token: write. Document how users verify a signature in the README (cosign verify ... --certificate-identity-regexp ... --certificate-oidc-issuer https://token.actions.githubusercontent.com).

On permissions: the workflows already declare permissions: at the workflow and job level. Grant security-events: write and id-token: write only to the jobs that need them, and say so in the PR description.

House rules for workflow changes:

  • Keep workflow comments to short one-liners, matching the existing files, and put the reasoning in the PR description.
  • Every PR check runs from .github/workflows/ci_checks.yml. The only required status check on dev is Greenlight - CI checks, which fails if any job it needs failed. Add a new job to its needs list and to CHECK_RESULTS, or the job won't block a merge, and don't rename the Greenlight job, or the required check never reports.
  • Image builds and Render deploys run through shared workflows in pesu-dev/actions (build_push_image.yml and deploy_render.yml, used at @v1). A change to them is a PR to that repository, followed by moving its v1 tag.
  • astral-sh/setup-uv publishes no floating major tag, so pin an exact version (CI uses @v9.0.0) or a commit SHA.
  • ci_checks.yml runs on pull requests, so test a workflow change by opening a pull request inside your fork (from your branch to your fork's dev), and link the green run in your PR.

Acceptance criteria

  • PR builds fail on fixable CRITICAL/HIGH vulnerabilities
  • Release images carry an SBOM and provenance, and are signed; the README shows how to verify
  • Base images are pinned by digest (no latest), and kept current by Dependabot (#209)
  • Validated on a fork with your own registry; run linked in the PR

How to contribute

  • Wait until you're assigned. Comment to ask for this issue, then wait for a maintainer to assign it to you before writing any code. PRs for unassigned issues are closed without review.
  • Read CONTRIBUTING.md first. It covers forking, setting up with uv, and running the tests.
  • Branch from dev in your fork, and open the PR against dev with a Conventional Commit title and Closes #207 in the description. The pesu-dev/actions change is a separate PR to that repository; link the two.
  • Bump the minor version in pyproject.toml and run uv lock (CI checks this). uv run pre-commit run --all-files must pass, and coverage must stay at 100%.
  • Update the README, app/docs/ and comments in the same PR as the behaviour they describe.
  • Never log, print, store or echo a password or token, including in tests, PR descriptions and screenshots.
Lingua principale
Python
Stelle
23
Fork
30
Merge medio
1g 18h
PR unite (30g)
18

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di pesu-dev/auth

Tutte le issue di pesu-dev/auth

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.