Proposal: harden the release workflow
メンテナーはふだん 1 日以内に返信
@GregoireF がすでに取り組んでいます。
2026年10月25日 から。
評価
この issue はまだ評価されていません。
説明
Hi! I've been reading through the repository and really like how the release process is set up: trusted publishing with provenance, a guarded workflow_run, Conventional Commit titles enforced on PRs, and a bounded npm range instead of npm@latest. The CONTRIBUTING and ROADMAP docs make the intent very clear.
While going through .github/workflows/ with zizmor 1.31.1, I noticed a few things that could be tightened in the job that publishes to npm. None of them looks exploited or urgent. They are low-cost changes that reduce what a compromised third-party action or dependency could do with the job's OIDC token. I'd be happy to open a PR if you're interested.
What I found
All links point to the current main (dfccb6b).
1. Actions referenced by mutable tags (zizmor unpinned-uses)
https://github.com/modulane/dev-workspace-cli/blob/dfccb6bcd8ccfb32540ed69fa6f13000ec6c231d/.github/workflows/release.yml#L39
https://github.com/modulane/dev-workspace-cli/blob/dfccb6bcd8ccfb32540ed69fa6f13000ec6c231d/.github/workflows/release.yml#L46
These steps run in a job with id-token: write and contents: write. If a tag is moved to a malicious commit, that code runs with the ability to publish to npm. The tj-actions/changed-files incident (March 2025) worked this way. The same applies to ci.yml (including oven-sh/setup-bun@v2) and pr-title.yml. CI gates the release, so its integrity matters too.
2. Package code can run while the OIDC token is available (zizmor adhoc-packages)
npm install --global "npm@^11.5.1"resolves a version from the registry at release time.npm ciruns dependency lifecycle scripts.- In a job with
id-token: write, any step, including those scripts, can request an OIDC token.
The good news is that no package in package-lock.json currently has an install script, so npm ci --ignore-scripts would cost nothing today. The npm bundled with current Node 24 releases should already satisfy ≥ 11.5.1, so the global install could become a version check.
3. The git credential stays on disk (zizmor artipacked)
actions/checkout keeps the contents: write token in .git/config for the whole job, including during npm ci. semantic-release authenticates with GITHUB_TOKEN itself, so persist-credentials: false should be enough.
4. workflow_run trigger (zizmor dangerous-triggers)
To be fair, the event == 'push' and conclusion == 'success' guards make this usage reasonably safe. An alternative would remove both the warning and the head_sha || sha workaround:
release.ymlruns onpush: mainand callsci.ymlas a reusable workflow (uses: $/.github/workflows/ci.yml, the self-repository syntax GitHub added in July 2026);- the release job uses
needs: ci; - tests and publishing then share one run and one commit.
The file would stay release.yml. The provenance on 0.5.0 shows the trusted publisher is bound to that path, so it would keep working.
5. Tests run twice in the release job
https://github.com/modulane/dev-workspace-cli/blob/dfccb6bcd8ccfb32540ed69fa6f13000ec6c231d/.github/workflows/release.yml#L59
https://github.com/modulane/dev-workspace-cli/blob/dfccb6bcd8ccfb32540ed69fa6f13000ec6c231d/package.json#L19
The explicit npm run check step and prepublishOnly both run during a release, after the full CI matrix has already passed on that commit. Dropping the explicit step would keep prepublishOnly as the safety net.
Suggested changes
release.yml
- Permissions:
permissions: {}at workflow level, with each job permission explained in a comment. - Job setup:
- a fork guard and a
main-only condition; timeout-minutes;- job-level
concurrencywithcancel-in-progress: false.
- a fork guard and a
- Install and publish steps:
- checkout with
persist-credentials: false; npm ci --ignore-scriptsfollowed bynpm audit signatures;npx --no-install semantic-release.
- checkout with
- Manual runs:
workflow_dispatchgains an optionaldry-runinput, passed throughenv:rather than interpolated into the script. - Optional:
- an
npmdeployment environment restricted tomain; step-security/harden-runnerin audit mode.
- an
Across all workflows
- Pin every action to a full commit SHA, with a
# vX.Y.Zcomment. - Add
.github/dependabot.ymlfor thegithub-actionsecosystem:- a 7-day cooldown before an update is proposed;
- a
ci:commit prefix, so updates never trigger a release.
- Optionally, add a small zizmor workflow on pull requests to catch regressions.
Docs
Update to match the new flow:
- the "Releases" section of CONTRIBUTING.md;
- the "Release safety" items in ROADMAP.md.
Open questions for you
- Trigger: keep
workflow_run(only pinning and token hygiene), or switch to the reusable-workflow approach? The switch has two side effects:ci.ymlwould no longer run on its own onmain, so the README CI badge would need to point atrelease.yml;- the coverage badge deploy would run inside the release run.
- Environment: would you like an
npmdeployment environment? It is optional, but it lets you scope the trusted publisher on npmjs.com and add protection rules. - Scope: one PR for everything, or one for
release.ymland a separate one for pinningci.ymlandpr-title.ymlplus Dependabot?
Repository settings worth checking
These are only visible to maintainers, so they may already be in place:
- default
GITHUB_TOKENpermissions set to read-only; - full-SHA pinning required for actions;
- a tag ruleset on
v*; - immutable releases;
- after a successful OIDC publish, "Require 2FA and disallow tokens" on the npm package.
Possibly related, not part of this proposal
- Node.js 20 reached end-of-life in April 2026. The CI matrix and
enginesstill include it, andsemantic-release25 (dev dependency) requires Node ≥ 22.14. npm install --global pnpm yarnandsetup-buninstall unpinned tool versions in CI.- A
refs/notes/semantic-release-v1.0.0ref exists on the remote with no matching tag, probably left over from the early releases. It is harmless, but you may want to delete it.
Happy to adjust any of this to how you prefer to work. Just let me know whether a PR would be welcome and which direction you'd like for the trigger.
- 主要言語
- JavaScript
- スター
- 0
- フォーク
- 0
- 平均マージ
- 46分
- マージ済み PR(30日)
- 15
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
似ている issue
-
enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
glossyio/traffic-monitor#264 ·
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 72/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
micromatch/picomatch#243 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信
-
getComputedStyle().display is "" for span, a, b, label and other inline elements instead of "inline"オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
capricorn86/happy-dom#2556 ·
メンテナーはふだん 1 日以内に返信