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.
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.