Proposal: harden the release workflow
Los mantenedores suelen responder en 1 día
@GregoireF ya está trabajando en esto.
Desde el 25/10/2026.
Evaluación
Este issue todavía no se ha evaluado.
Descripción
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.
- Lenguaje dominante
- JavaScript
- Estrellas
- 0
- Forks
- 0
- Merge medio
- 55 min
- PR fusionados (30 d)
- 12
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de modulane/dev-workspace-cli
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
modulane/dev-workspace-cli#15 ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
modulane/dev-workspace-cli#14 ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 3/5 1-2 días Aptitud para principiantes 72/100
modulane/dev-workspace-cli#8 ·
Los mantenedores suelen responder en 1 día
Todos los issues de modulane/dev-workspace-cli
Issues similares
-
[bug] extension mappingAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 64/100
-
bug code-annotation
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
quarto-dev/quarto-cli#15215 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 70/100
521xueweihan/HelloGitHub#4133 ·
-
Dificultad 1/5 1-3 horas Aptitud para principiantes 88/100
-
enhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
Hugo-SA/receita-random#20 ·
Los mantenedores suelen responder en 1 día