Skip to content

ci: enable npm trusted publishing (OIDC)#154

Merged
filiphric merged 1 commit into
mainfrom
ci/npm-trusted-publishing
Jun 28, 2026
Merged

ci: enable npm trusted publishing (OIDC)#154
filiphric merged 1 commit into
mainfrom
ci/npm-trusted-publishing

Conversation

@filiphric

Copy link
Copy Markdown
Owner

What

Configures .github/workflows/tests.yml to publish to npm via trusted publishing (OIDC) instead of a long-lived NPM_TOKEN.

Changes

  • Add id-token: write permission — required so GitHub mints the OIDC token npm exchanges for short-lived credentials. Also added contents: write for semantic-release's tags/GitHub release.
  • Upgrade npm to npm@latest — trusted publishing requires npm ≥ 11.5.1; Node 22.14.0 ships 11.2.0.
  • Remove NPM_TOKEN — with a token present npm prefers it and skips OIDC. GITHUB_TOKEN is kept for the GitHub release/changelog.
  • Bump actions/checkout to v4 and run it before setup-node.

@semantic-release/npm@^13.1.1 and semantic-release@^25.0.2 already support OIDC, so no dependency changes are needed.

Follow-ups (outside this PR)

  • After the first successful OIDC release, delete the NPM_TOKEN repo secret.
  • Confirm the npm trusted publisher points at repo filiphric/cypress-plugin-api and workflow file tests.yml — a mismatch causes the OIDC exchange to be rejected.

Side benefit: npm provenance is now generated automatically.

- Add id-token: write permission so GitHub mints an OIDC token
- Upgrade npm to >= 11.5.1 (required for trusted publishing)
- Remove NPM_TOKEN so the OIDC exchange is used instead of legacy token
- Bump actions/checkout to v4 and run it before setup-node
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 28, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Shallow checkout breaks releases ✓ Resolved 🧑 Team insight ☼ Reliability
Description
**Inspired by shay-qodo's coding and review patterns** — actions/checkout is used without
fetch-depth: 0, which often prevents semantic-release from seeing tags/history and can cause
skipped or incorrect versioning. This can lead to flaky or wrong releases even if the rest of the
OIDC setup is correct.
Code

.github/workflows/tests.yml[R10-15]

+      - name: Checkout
+        uses: actions/checkout@v4
     - name: Setup Node.js
       uses: actions/setup-node@v4
       with:
         node-version: '22.14.0'
-      - name: Checkout
-        uses: actions/checkout@v2
Evidence
The workflow runs semantic-release but does not configure checkout depth, meaning the release step
may not have the required tag/commit context. Per shay-qodo’s focus on production safety and
avoiding fragile integrations, this is the kind of latent reliability footgun they typically ask to
harden.

.github/workflows/tests.yml[10-34]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
semantic-release typically requires full git history and tags; a shallow checkout (default) can cause it to mis-detect previous releases or fail.
### Issue Context
`actions/checkout@v4` defaults to `fetch-depth: 1`.
### Fix Focus Areas
- .github/workflows/tests.yml[10-15]
### Suggested fix
Update checkout step:

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Unpinned npm@latest install 🐞 Bug ☼ Reliability
Description
The workflow installs npm@latest, which is non-deterministic and can change CI/release behavior
over time without any repository change, potentially breaking publishing unexpectedly. Because this
happens immediately before semantic-release publishes, it increases reliability and supply-chain
risk in the release path and should be pinned (or at least constrained) to a known-good version that
satisfies OIDC/trusted publishing requirements.
Code

.github/workflows/tests.yml[R16-17]

+      - name: Upgrade npm for trusted publishing
+        run: npm install -g npm@latest   # needs >= 11.5.1
Evidence
The workflow contains a step that runs npm install -g npm@latest, which means the npm version used
during the release is whatever is current at execution time rather than a repository-controlled
version. This implicit drift can introduce behavioral changes (including major/minor updates) that
destabilize the publishing pipeline; an operator-minded approach favors making the version explicit,
safe, and reversible by pinning or constraining the npm version.

.github/workflows/tests.yml[12-18]
.github/workflows/tests.yml[16-17]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`npm install -g npm@latest` makes CI/release behavior non-deterministic because the npm version can change over time without any repository changes, which can unexpectedly break releases (especially immediately before semantic-release publishes).
## Issue Context
Trusted publishing requires a minimum npm version; Node 22.14.0 ships npm 11.2.0, while trusted publishing requires npm >= 11.5.1. You can satisfy this minimum while still keeping the pipeline deterministic by pinning npm to a known-good version (or a constrained range) and optionally logging the installed version; consider documenting the rationale and adopting a deliberate upgrade cadence (e.g., quarterly) so changes are explicit and auditable.
## Fix Focus Areas
- .github/workflows/tests.yml[16-17]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Overbroad job token scopes 🐞 Bug ⛨ Security
Description
The workflow grants contents: write and id-token: write at the job level for a job that runs on
every push, so all steps (including third-party actions and project scripts) can request an OIDC
token and use a write-scoped GITHUB_TOKEN. This unnecessarily broadens the blast radius of any
compromised/buggy dependency and provides publish-capable permissions even when a release is not
intended, so release permissions should be isolated and/or gated to main only.
Code

.github/workflows/tests.yml[R6-8]

+    permissions:
+      contents: write       # semantic-release pushes tags / GitHub release
+      id-token: write       # required for npm trusted publishing (OIDC)
Evidence
The cited workflow is triggered on every push and defines a job-level permissions: block that
includes contents: write and id-token: write, which applies to every step in that job (not just
release logic). Because the job executes complex/untrusted steps such as third-party actions (e.g.,
Cypress) and project scripts, and also performs publishing via semantic-release (which is the only
part that actually needs contents: write for tags/releases and id-token: write for npm trusted
publishing), the citations show that elevated write/OIDC capabilities are available far beyond what
is required for running tests, increasing operational risk and blast radius.

.github/workflows/tests.yml[2-34]
package.json[36-49]
.github/workflows/tests.yml[4-34]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The workflow assigns `permissions: contents: write` and `id-token: write` to the entire `cypress-run`/Cypress test job while the workflow triggers on every `push`, which means every step (including third-party actions and project scripts) can mint OIDC tokens and use a write-capable `GITHUB_TOKEN`. We want to reduce blast radius by ensuring publish/release-grade permissions are only available to the minimal scope needed (ideally a separate, gated release path on `main`).
## Issue Context
Only the publishing/release portion needs elevated permissions: npm trusted publishing requires `id-token: write` only during publish, and semantic-release requires `contents: write` only when creating releases/tags/pushing release metadata. Tests (checkout/setup/cypress) generally only need minimal permissions (often `contents: read`) and should not run with publish-capable credentials.
## Fix Focus Areas
- .github/workflows/tests.yml[4-34]
- .github/workflows/tests.yml[6-34]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@qodo-for-filiphric

qodo-for-filiphric Bot commented Jun 28, 2026

Copy link
Copy Markdown

PR Summary by Qodo

ci: enable npm trusted publishing via OIDC
⚙️ Configuration changes ✨ Enhancement 🕐 10-20 Minutes

Grey Divider

Description

• Enable GitHub OIDC permissions for npm trusted publishing.
• Upgrade checkout action and ensure checkout runs before Node setup.
• Install newer npm and drop NPM_TOKEN to force OIDC-based publishing.
Diagram

graph TD
  A["Push event"] --> B["GitHub Actions: tests.yml"] --> C["Checkout (actions/checkout@v4)"] --> D["Setup Node 22.14.0"] --> E["Upgrade npm (>=11.5.1)"] --> F["semantic-release"] --> G{{"npm Registry (OIDC)"}}
  F --> H{{"GitHub tags/releases"}}
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Pin npm to a known-good version (e.g., npm@11.5.1 or ^11.5)
  • ➕ More reproducible CI behavior; avoids unexpected breaking changes from npm@latest
  • ➕ Easier to debug release failures (version is stable)
  • ➖ Requires occasional manual bumps to stay current
  • ➖ May miss newer npm fixes until upgraded
2. Bump Node.js to a version that bundles npm >= 11.5.1
  • ➕ Avoids global npm install step (simpler and faster pipeline)
  • ➕ Keeps Node/npm pairing aligned with upstream distribution
  • ➖ May not be possible if the project is intentionally pinned to Node 22.14.0
  • ➖ Upgrading Node can introduce unrelated runtime/tooling differences

Recommendation: The OIDC/trusted publishing approach is the right direction and aligns with npm’s recommended auth model. Consider pinning npm (instead of npm@latest) to keep releases deterministic, unless you explicitly want to track npm’s latest behavior in CI.

Files changed (1) +8 / -3

Other (1) +8 / -3
tests.ymlSwitch npm publishing to OIDC trusted publishing in CI workflow +8/-3

Switch npm publishing to OIDC trusted publishing in CI workflow

• Adds job permissions for contents write (semantic-release) and id-token write (OIDC). Updates checkout to v4 and moves it before setup-node, installs a newer npm required for trusted publishing, and removes NPM_TOKEN to ensure OIDC is used for npm auth.

.github/workflows/tests.yml

@cypress

cypress Bot commented Jun 28, 2026

Copy link
Copy Markdown

cypress-plugin-api    Run #207

Run Properties:  status check passed Passed #207  •  git commit 288d108c03: ci: enable npm trusted publishing (OIDC)
Project cypress-plugin-api
Branch Review ci/npm-trusted-publishing
Run status status check passed Passed #207
Run duration 01m 12s
Commit git commit 288d108c03: ci: enable npm trusted publishing (OIDC)
Committer Filip Hric
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 91
View all changes introduced in this branch ↗︎

@qodo-for-filiphric

qodo-for-filiphric Bot commented Jun 28, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2)   📘 Rule violations (0)   🧑 Team insights (0)   📜 Skill insights (0)
🐞 ☼ Reliability (1) ⛨ Security (1)
Context used
✅ Compliance rules (platform): 3 rules
✅ Team profiles: shay-qodo, avi-gl
Review effort: 🔍 Standard

Grey Divider


Action required

1. Shallow checkout breaks releases ✓ Resolved 🧑 ☼ Reliability
Description
**Inspired by shay-qodo's coding and review patterns** — actions/checkout is used without
fetch-depth: 0, which often prevents semantic-release from seeing tags/history and can cause
skipped or incorrect versioning. This can lead to flaky or wrong releases even if the rest of the
OIDC setup is correct.
Code

.github/workflows/tests.yml[R10-15]

+      - name: Checkout
+        uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '22.14.0'
-      - name: Checkout
-        uses: actions/checkout@v2
Evidence
The workflow runs semantic-release but does not configure checkout depth, meaning the release step
may not have the required tag/commit context. Per shay-qodo’s focus on production safety and
avoiding fragile integrations, this is the kind of latent reliability footgun they typically ask to
harden.

.github/workflows/tests.yml[10-34]

Teammate info & reasoning
Review Focus Areas > 1) Reliability of external calls (retries + bounded latency)
Reason for choosing shay-qodo: Strong CI/CD and infrastructure focus (codium-infrastructure experience); well-suited to review GitHub Actions permission changes, release automation, and secure OIDC-based npm publishing.
Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
semantic-release typically requires full git history and tags; a shallow checkout (default) can cause it to mis-detect previous releases or fail.

### Issue Context
`actions/checkout@v4` defaults to `fetch-depth: 1`.

### Fix Focus Areas
- .github/workflows/tests.yml[10-15]

### Suggested fix
Update checkout step:
```yaml
- name: Checkout
 uses: actions/checkout@v4
 with:
   fetch-depth: 0
```
(If you also need tags explicitly in some setups, `fetch-tags: true` can be added, but `fetch-depth: 0` is usually sufficient.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Unpinned npm@latest install 🐞 ☼ Reliability
Description
The workflow installs npm@latest, which is non-deterministic and can change CI/release behavior
over time without any repository change, potentially breaking publishing unexpectedly. Because this
happens immediately before semantic-release publishes, it increases reliability and supply-chain
risk in the release path and should be pinned (or at least constrained) to a known-good version that
satisfies OIDC/trusted publishing requirements.
Code

.github/workflows/tests.yml[R16-17]

+      - name: Upgrade npm for trusted publishing
+        run: npm install -g npm@latest   # needs >= 11.5.1
Evidence
The workflow contains a step that runs npm install -g npm@latest, which means the npm version used
during the release is whatever is current at execution time rather than a repository-controlled
version. This implicit drift can introduce behavioral changes (including major/minor updates) that
destabilize the publishing pipeline; an operator-minded approach favors making the version explicit,
safe, and reversible by pinning or constraining the npm version.

.github/workflows/tests.yml[12-18]
.github/workflows/tests.yml[16-17]

Teammate info & reasoning
Review Focus Areas > 2) Resource lifecycle correctness (init order, cleanup on failure, avoid double-teardown)
Reason for choosing avi-gl: Extensive infra/DevOps review background; can validate workflow ordering (checkout/setup-node), npm upgrade implications, and security posture of id-token/contents permissions for trusted publishing.
Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`npm install -g npm@latest` makes CI/release behavior non-deterministic because the npm version can change over time without any repository changes, which can unexpectedly break releases (especially immediately before semantic-release publishes).

## Issue Context
Trusted publishing requires a minimum npm version; Node 22.14.0 ships npm 11.2.0, while trusted publishing requires npm >= 11.5.1. You can satisfy this minimum while still keeping the pipeline deterministic by pinning npm to a known-good version (or a constrained range) and optionally logging the installed version; consider documenting the rationale and adopting a deliberate upgrade cadence (e.g., quarterly) so changes are explicit and auditable.

## Fix Focus Areas
- .github/workflows/tests.yml[16-17]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Overbroad job token scopes 🐞 ⛨ Security
Description
The workflow grants contents: write and id-token: write at the job level for a job that runs on
every push, so all steps (including third-party actions and project scripts) can request an OIDC
token and use a write-scoped GITHUB_TOKEN. This unnecessarily broadens the blast radius of any
compromised/buggy dependency and provides publish-capable permissions even when a release is not
intended, so release permissions should be isolated and/or gated to main only.
Code

.github/workflows/tests.yml[R6-8]

+    permissions:
+      contents: write       # semantic-release pushes tags / GitHub release
+      id-token: write       # required for npm trusted publishing (OIDC)
Evidence
The cited workflow is triggered on every push and defines a job-level permissions: block that
includes contents: write and id-token: write, which applies to every step in that job (not just
release logic). Because the job executes complex/untrusted steps such as third-party actions (e.g.,
Cypress) and project scripts, and also performs publishing via semantic-release (which is the only
part that actually needs contents: write for tags/releases and id-token: write for npm trusted
publishing), the citations show that elevated write/OIDC capabilities are available far beyond what
is required for running tests, increasing operational risk and blast radius.

.github/workflows/tests.yml[2-34]
package.json[36-49]
.github/workflows/tests.yml[4-34]

Teammate info & reasoning
Review Focus Areas > 5) Rollout/migration safety (default-off, fail-safe to legacy, no-event-loss)
Reason for choosing avi-gl: Extensive infra/DevOps review background; can validate workflow ordering (checkout/setup-node), npm upgrade implications, and security posture of id-token/contents permissions for trusted publishing.
Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The workflow assigns `permissions: contents: write` and `id-token: write` to the entire `cypress-run`/Cypress test job while the workflow triggers on every `push`, which means every step (including third-party actions and project scripts) can mint OIDC tokens and use a write-capable `GITHUB_TOKEN`. We want to reduce blast radius by ensuring publish/release-grade permissions are only available to the minimal scope needed (ideally a separate, gated release path on `main`).

## Issue Context
Only the publishing/release portion needs elevated permissions: npm trusted publishing requires `id-token: write` only during publish, and semantic-release requires `contents: write` only when creating releases/tags/pushing release metadata. Tests (checkout/setup/cypress) generally only need minimal permissions (often `contents: read`) and should not run with publish-capable credentials.

## Fix Focus Areas
- .github/workflows/tests.yml[4-34]
- .github/workflows/tests.yml[6-34]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread .github/workflows/tests.yml
@qodo-for-filiphric

Copy link
Copy Markdown

Qodo Fixer

✅ Committed (1) · ☑ Fixed (1)

Grey Divider

Commits pushed directly to this PR — no separate fix PR opened.

Process — 1 fixed
  • ☑ Fixed: Shallow checkout breaks releases

@filiphric filiphric merged commit fbb3a67 into main Jun 28, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant