ci: harden CI per Astral's open-source security recommendations #2347
ci: harden CI per Astral's open-source security recommendations #2347
Conversation
Adopts the supply-chain practices described in Astral's "Open source security at Astral" post (https://astral.sh/blog/open-source-security-at-astral) and applies them to the FrankenPHP CI: - Add a zizmor workflow that audits every PR/push touching .github (and weekly on a schedule) as a hard gate. zizmor is installed via pipx so the security workflow itself has minimal supply chain. - Tighten every workflow to start with `permissions: {}` and grant the minimum permissions per job, so newly added jobs inherit nothing. - Track Docker base images with Dependabot so security patches in the underlying images surface as reviewable PRs. - Document the hardened posture (zizmor gate, least-privilege perms, environment-scoped secrets, build provenance, no pull_request_target) in SECURITY.md. - Document hash-pinning as the next ratchet in zizmor.yaml; the policy stays at `ref-pin` for now to avoid breaking existing tag pins, with a clear path to switch to `hash-pin` once Dependabot starts updating by SHA. https://claude.ai/code/session_01YEC8c9bU4Mory8FFoiAS5T
zizmor already runs as GITHUB_ACTIONS_ZIZMOR inside Super Linter, so the dedicated workflow was redundant. Also simplify the SECURITY.md prose to pass the NATURAL_LANGUAGE linter. https://claude.ai/code/session_01YEC8c9bU4Mory8FFoiAS5T
- Revert SECURITY.md to original (no new sections) - Remove docker package-ecosystem from Dependabot (nightly scheduled workflow already updates base images) - Remove added comments and Astral references from zizmor.yaml https://claude.ai/code/session_01YEC8c9bU4Mory8FFoiAS5T
Pin every external action to its commit SHA so mutable tags can no longer alter what runs in CI. The zizmor policy is switched from ref-pin to hash-pin to enforce this going forward. Dependabot already tracks the github-actions ecosystem weekly and will open PRs to bump the SHA pins. A new auto-merge workflow approves and squash-merges minor/patch GitHub Actions updates from Dependabot automatically, keeping pins current without manual churn. https://claude.ai/code/session_01YEC8c9bU4Mory8FFoiAS5T
Signed-off-by: Kévin Dunglas <kevin@dunglas.fr>
There was a problem hiding this comment.
Pull request overview
Hardens the repository’s GitHub Actions CI posture by enforcing least-privilege workflow permissions and pinning third-party actions, aligning with Astral’s supply-chain security recommendations.
Changes:
- Set workflow-level
permissions: {}across workflows and add minimal per-job permissions where needed. - Pin GitHub Actions
uses:references to immutable commit SHAs. - Add a Dependabot auto-merge workflow for non-major GitHub Actions updates and update zizmor policy configuration.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
zizmor.yaml |
Tightens unpinned-uses policy (now configured to enforce stronger pinning). |
.github/workflows/wrap-issue-details.yaml |
Drops default permissions and pins actions/github-script by SHA. |
.github/workflows/windows.yaml |
Drops default permissions and SHA-pins key actions in Windows build workflow. |
.github/workflows/translate.yaml |
Moves permissions to job scope and SHA-pins actions used for translation + PR creation. |
.github/workflows/tests.yaml |
Adds job-scoped contents: read and SHA-pins actions used in test jobs. |
.github/workflows/static.yaml |
Adds job-scoped permissions and SHA-pins Docker/Actions dependencies (incl. provenance attestation action). |
.github/workflows/sanitizers.yaml |
Adds job-scoped contents: read and SHA-pins checkout/go/cache actions. |
.github/workflows/lint.yaml |
Moves permissions to job scope and SHA-pins checkout + super-linter. |
.github/workflows/docker.yaml |
Adds job-scoped permissions and SHA-pins Docker/Actions dependencies. |
.github/workflows/dependabot.yaml |
Introduces a Dependabot PR auto-merge workflow and SHA-pins metadata action. |
.github/actions/watcher/action.yaml |
SHA-pins actions/cache used by the composite action. |
Comments suppressed due to low confidence (1)
zizmor.yaml:6
- The PR description says the zizmor policy will stay at
ref-pinfor now, but this change switches it tohash-pin. Either update the PR description/SECURITY docs to match, or keep the policy atref-pinuntil the repo is ready to enforce hash pinning everywhere.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -0,0 +1,25 @@ | |||
| --- | |||
| name: Dependabot Auto-Merge | |||
There was a problem hiding this comment.
Hear me out. This logic seems kinda circular? Lock down all the things to prevent supply-chain attacks ... but then auto-merge updates, which is the most likely vector for supply-chain attacks?
Don't get me wrong, I completely agree with this workflow (automating updates FTW). Just pointing out the logic.
There was a problem hiding this comment.
I'm against dependabot auto merges. Most of the time it's broken and even in case it does manage to get a working PR, it's likely that it missed other packages, so we need to manually touch it up anyway. Auto merges in general are also a bit tricky in my eyes, many vulnerabilities and projects takeovers have been achieved by auto CI runs or merges.
There was a problem hiding this comment.
I'm also not a fan of SHAs for these same reasons. Dependabot updates the SHA and the comment ... but I still got to go check the SHA is actually what the comment says, which is a branch head. At that point, might as well lock it to the branch instead of the SHA.
There was a problem hiding this comment.
With the cooldown period, this gives some time for the supply chain attacks to be detected (not the case currently), while not increasing maintenance burden for us (currently, new minor versions of our GitHub Actions dependencies are automatically used).
There was a problem hiding this comment.
Pinning to SHA also provides better traceability and reproducibility: we can easily know what exact versions of all our dependencies have been used to build a release.
Adopts the supply-chain practices described in Astral's "Open source
security at Astral" post (https://astral.sh/blog/open-source-security-at-astral)
and applies them to the FrankenPHP CI:
(and weekly on a schedule) as a hard gate. zizmor is installed via
pipx so the security workflow itself has minimal supply chain.
permissions: {}and grant theminimum permissions per job, so newly added jobs inherit nothing.
underlying images surface as reviewable PRs.
environment-scoped secrets, build provenance, no pull_request_target)
in SECURITY.md.
stays at
ref-pinfor now to avoid breaking existing tag pins, witha clear path to switch to
hash-pinonce Dependabot starts updatingby SHA.