feat: support digest-addressed Helm images and enforce release supply chain#516
feat: support digest-addressed Helm images and enforce release supply chain#516nash87 wants to merge 14 commits into
Conversation
…-clean # Conflicts: # .github/workflows/ci.yml # .github/workflows/dependency-review.yml
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: df7928439b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (( diff_touch_workflows || diff_touch_image )) || [[ "$profile" == "cd" || "${FOP_LOCAL_CI_RUN_LINTERS:-}" == "1" ]]; then | ||
| run_direct "release supply-chain policy" "bash scripts/check-release-supply-chain-policy.sh" | ||
| else |
There was a problem hiding this comment.
Guard local gate against missing PyYAML dependency
This new mandatory run_direct invocation makes the release policy check part of the default local PR gate, but scripts/check-release-supply-chain-policy.sh hard-fails on ModuleNotFoundError when yaml is not installed. On clean contributor machines (where PyYAML is not preinstalled), make ci/make ci-post now fails before any project bootstrap, so unrelated changes cannot clear the required local gate.
Useful? React with 👍 / 👎.
| # Soft-fail: diffs surface as downloadable artifacts but don't block merge | ||
| # or make the scheduled health board look cancelled. | ||
| continue-on-error: true | ||
| continue-on-error: false |
There was a problem hiding this comment.
Keep visual regression workflow in non-blocking mode
This job is documented as a soft-fail signal for noisy renderer diffs, but changing continue-on-error to false makes expected anti-aliasing/font-hinting drift fail the workflow outright. That contradicts the workflow’s stated purpose (artifact-only triage) and will generate avoidable red runs whenever baseline noise appears.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds support for digest-addressed Helm image references while tightening release supply-chain enforcement across CI and local gates.
Changes:
- Helm chart: render
repository@sha256:...whenimage.digestis set. - Add a repo-wide release supply-chain policy check and run it in CI and local fop profiles.
- Make multiple CI/security workflows blocking (and pin
wolfi-basefrom:latestto an immutable digest).
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/check-release-supply-chain-policy.sh | New policy gate to detect mutable refs / non-blocking gates and require provenance/SBOM/signing workflow snippets |
| helm/parkhub/values.yaml | Adds image.digest value |
| helm/parkhub/templates/deployment.yaml | Switches image field to render via new helper |
| helm/parkhub/templates/_helpers.tpl | Adds parkhub.imageRef helper (tag vs digest) |
| .zizmor.yaml | Updates documented GHA zizmor mode to blocking |
| .github/workflows/visual-regression.yml | Flips visual regression job to blocking |
| .github/workflows/security.yml | Flips multiple advisory security steps/jobs to blocking |
| .github/workflows/scorecard.yml | Flips scorecard to blocking |
| .github/workflows/schemathesis.yml | Flips schemathesis to blocking |
| .github/workflows/infection.yml | Flips mutation testing to blocking |
| .github/workflows/helm.yml | Adds helm template assertion for digest image rendering |
| .github/workflows/docker-publish.yml | Pins Wolfi base to digest and makes Trivy scan blocking |
| .github/workflows/dependabot-local-ci-bridge.yml | Makes dependency/vuln/typos checks blocking |
| .github/workflows/ci.yml | Runs new supply-chain policy check; pins Wolfi base; makes cosign verify blocking/required |
| .github/scripts/fop-local-ci.sh | Runs new policy gate conditionally; updates local gating commentary |
| .github/actions/dependency-review/action.yml | Makes dependency review blocking and updates comments accordingly |
| .gitea/workflows/visual-regression.yaml | Flips visual regression job to blocking |
| .gitea/workflows/unlighthouse.yaml | Flips unlighthouse to blocking (comment still claims soft-fail) |
| .gitea/workflows/security.yaml | Flips multiple advisory security jobs/steps to blocking |
| .gitea/workflows/scorecard.yaml | Flips scorecard to blocking |
| .gitea/workflows/schemathesis.yaml | Flips schemathesis to blocking |
| .gitea/workflows/lost-pixel.yaml | Flips lost-pixel to blocking (comment still claims never block) |
| .gitea/workflows/infection.yaml | Flips mutation testing to blocking |
| .gitea/workflows/docker-publish.yaml | Makes Trivy scan blocking |
| .gitea/workflows/dependabot-local-ci-bridge.yaml | Makes dependency/vuln/typos checks blocking |
| .gitea/workflows/ci.yaml | Makes cosign verify blocking |
| .gitea/workflows/accessibility-insights.yaml | Flips accessibility insights to blocking (comment still claims soft-fail) |
| # Audit-mode: surface findings as informational; do NOT fail the gate yet. | ||
| # Promote findings to errors once the workflow inventory has been triaged. | ||
| continue-on-error: true | ||
| continue-on-error: false |
| # Soft job — mutation score is informational during the baseline | ||
| # phase. Do NOT gate merges on this; watch the nightly trend instead. | ||
| continue-on-error: true | ||
| continue-on-error: false |
| options: --add-host=gitea.test:192.168.178.233 | ||
| timeout-minutes: 45 | ||
| continue-on-error: true # Soft-fail — long-tail budgets still tuning. | ||
| continue-on-error: false # Soft-fail — long-tail budgets still tuning. |
| for path in sorted(p for p in repo.rglob("*") if p.is_file() and is_policy_surface(p)): | ||
| text = read_text(path) |
| forbidden = { | ||
| "wolfi-base" + ":latest": "mutable Wolfi base image tag", | ||
| "continue-on-error" + ": true": "non-blocking release or security gate", | ||
| "advisory until " + "first signed": "advisory attestation verification", | ||
| } |
| for pattern, description in forbidden.items(): | ||
| if pattern in text: | ||
| errors.append(f"{path}: contains {description}: {pattern}") |
| print("PyYAML is required for release supply-chain policy checks", file=sys.stderr) | ||
| raise |
| {{- define "parkhub.imageRef" -}} | ||
| {{- $repository := required "image.repository is required" .Values.image.repository -}} | ||
| {{- $digest := default "" .Values.image.digest -}} | ||
| {{- if $digest -}} | ||
| {{- printf "%s@%s" $repository $digest -}} | ||
| {{- else -}} | ||
| {{- printf "%s:%s" $repository (include "parkhub.imageTag" .) -}} | ||
| {{- end -}} |
Summary
Verification
Legal / compliance boundary
Follow-up noted