Skip to content

fix(gha): Fix pnpm upgrade workflow - #335

Merged
jsteinich merged 6 commits into
open-constructs:mainfrom
jsteinich:fix_pnpm_upgrade_ncu
Jul 18, 2026
Merged

fix(gha): Fix pnpm upgrade workflow#335
jsteinich merged 6 commits into
open-constructs:mainfrom
jsteinich:fix_pnpm_upgrade_ncu

Conversation

@jsteinich

Copy link
Copy Markdown
Contributor

Description

Attempting to fix failures seen in pnpm upgrade job: https://github.com/open-constructs/cdk-terrain/actions/runs/29232337176/job/86759126716

Checklist

  • I have updated the PR title to match CDKTN's style guide
  • I have run the linter on my code locally
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation if applicable
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works if applicable
  • New and existing unit tests pass locally with my changes

@jsteinich
jsteinich requested a review from a team as a code owner July 17, 2026 02:18
@sakul-learning

Copy link
Copy Markdown
Contributor

The direction is right, but the current diff cannot work with the ncu version installed by this workflow, and there is a second package-matrix failure that --packageManager pnpm alone does not address.

1. Pin a pnpm-capable ncu release

.github/workflows/pnpm-upgrade.yml still installs this in all three upgrade jobs (currently lines 43, 168, and 235):

npm -g install npm-check-updates@^9.0.0

The latest v9 release, 9.2.4, accepts only npm and yarn for --packageManager; it exits with Error: Invalid package manager: pnpm. Please pin the current reviewed release instead in all three places:

npm -g install npm-check-updates@22.2.9

I validated 22.2.9 against this PR's toolchain and workspace:

  • Node 22.22.3
  • npm 10.9.8
  • ncu 22.2.9
  • a non-mutating root invocation with the proposed flags returned {} successfully
  • a non-mutating invocation using repeated --workspace cdktn --workspace @cdktn/cli-core --no-root resolved the two expected workspace manifests successfully

Those Node/npm versions satisfy ncu 22.2.9's documented engines (^20.19 || ^22.12 || >=24, npm >=10). Current ncu can auto-detect pnpm from pnpm-lock.yaml, so the explicit flag is not strictly required; retaining it is still reasonable in CI because it makes the intended package manager deterministic.

2. Make the v9 → v22 default changes explicit

Current ncu includes the root packageManager field in its default dependency sections and includes deprecated releases by default. Without an explicit --dep, the broad root update can also rewrite the integrity-pinned:

"packageManager": "pnpm@11.5.2+sha512..."

That would couple pnpm toolchain upgrades to the ordinary dependency-upgrade job. To preserve the older policy and keep the package-manager pin separately controlled, add these options to every ncu invocation:

--packageManager pnpm
--dep prod,dev,optional,peer
--no-deprecated

In particular, --dep prod,dev,optional,peer deliberately omits packageManager.

3. Use ncu's workspace support instead of dispatching manifest edits through repeated pnpm exec nx exec

The failed package-matrix jobs show this sequence:

  1. the first ncu pass edits workspace manifests;
  2. the next outer pnpm exec nx exec starts under CI=true;
  3. pnpm checks the now-dirty workspace against pnpm-lock.yaml and exits with ERR_PNPM_OUTDATED_LOCKFILE before the final non-frozen install can run.

Adding --packageManager pnpm does not fix that sequencing issue. ncu 22.2.9 will not fix repeated outer pnpm exec calls automatically either. However, current ncu supports pnpm workspaces directly, so this PR can remove pnpm/Nx from the manifest-edit dispatch path and perform one final lockfile reconciliation afterward. This is consistent with the repository's broader move away from Yarn Classic/Lerna toward pnpm/Nx, while using each tool for the job it owns.

All required changes are in .github/workflows/pnpm-upgrade.yml:

upgradeRoot

Keep the three direct root ncu calls, but use ncu 22.2.9 and append the explicit compatibility options above. No workspace option is needed here.

upgradePackage

Replace the three commands shaped like:

pnpm exec nx exec -p '${{ join(matrix.pr.packages, ',') }}' -- ncu ...

with direct ncu workspace calls. ncu requires one --workspace option per workspace. A safe way to derive that from the existing static matrix without interpolating expressions directly into shell code is:

- name: Run "ncu -u"
  shell: bash
  env:
    NCU_WORKSPACES: ${{ join(matrix.pr.packages, ' ') }}
  run: |-
    read -ra workspaces <<< "$NCU_WORKSPACES"
    workspace_args=()
    for workspace in "${workspaces[@]}"; do
      workspace_args+=(--workspace "$workspace")
    done

    ncu --upgrade "${workspace_args[@]}" --no-root \
      --filter=@types/fs-extra --target=minor \
      --packageManager pnpm --dep prod,dev,optional,peer --no-deprecated

    ncu --upgrade "${workspace_args[@]}" --no-root \
      --filter=typescript --target=patch \
      --packageManager pnpm --dep prod,dev,optional,peer --no-deprecated

    ncu --upgrade "${workspace_args[@]}" --no-root \
      --reject='@types/node,@types/fs-extra,constructs,typescript,graphology-types,jsii,jsii-pacmak,jsii-rosetta,jsii-docgen,codemaker,${{ steps.list-packages.outputs.list }}' \
      --target=minor \
      --packageManager pnpm --dep prod,dev,optional,peer --no-deprecated

--no-root is important here because ncu v17+ includes the root manifest by default in workspace mode; each matrix entry should touch only its selected workspace packages.

Keep the existing final reconciliation:

pnpm install --prefer-offline --no-frozen-lockfile

Then validate the result with a clean frozen install. Direct ncu workspace runs only edit manifests; they do not regenerate pnpm-lock.yaml, so the final pnpm step remains required.

upgradeJSII

Replace:

pnpm exec nx exec -- ncu --upgrade --filter='jsii,jsii-pacmak,jsii-rosetta,jsii-docgen,codemaker,constructs' --target=minor ...

with ncu's all-workspaces mode, explicitly preserving the current root-inclusive behavior:

ncu --upgrade --workspaces --root \
  --filter='jsii,jsii-pacmak,jsii-rosetta,jsii-docgen,codemaker,constructs' \
  --target=minor \
  --packageManager pnpm --dep prod,dev,optional,peer --no-deprecated

Keep its final pnpm install --prefer-offline --no-frozen-lockfile as well.

The focused validation for this change should reproduce the upgradePackage sequence with CI=true, confirm all selected manifests are processed without ERR_PNPM_OUTDATED_LOCKFILE, run the final non-frozen install, and then confirm a clean pnpm install --frozen-lockfile succeeds.

Separate follow-up: reviewer-assignment authentication

The linked JSII job actually completed ncu, refreshed the pnpm lockfile, pushed the branch, and created PR #327; it was marked failed afterward because team-reviewers: cdktn-maintainers could not be requested with the existing token. That authentication issue is separate from this PR.

A follow-up should reuse the existing CDKTN maintainers GitHub App flow from .github/workflows/release-please.yml:

uses: actions/create-github-app-token@...
with:
  app-id: ${{ secrets.CDKTN_MAINTAINERS_APP_ID }}
  private-key: ${{ secrets.CDKTN_MAINTAINERS_APP_PRIVATE_KEY }}

That App token is already used so bot-created PRs trigger normal CI. Once the requested organization/team read permissions are available, it should also be evaluated for the dependency PR jobs instead of retaining a separate legacy PAT. This should remain a separate auth-focused change rather than being mixed into the ncu/workspace repair.

References:

@so0k so0k left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on analysis from GPT5.6 Sol - I'm going to agree we may need to bump npm-check-updates version to achieve this?

Comment thread .github/workflows/pnpm-upgrade.yml Outdated
@jsteinich jsteinich changed the title fix(gha): Force ncu to use pnpm fix(gha): Fix pnpm upgrade workflow Jul 18, 2026
@so0k so0k added ci/skip-examples Skip Examples Testing in PR ci/skip-integration Skips Integration Testing on PR ci/skip-provider-integration Skips Provider Integration Tests on PR ci/skip-unit Skips Unit Testing on PR labels Jul 18, 2026
@sakul-learning

Copy link
Copy Markdown
Contributor

Follow-up review — bf3a0be

The ncu/workspace repair now addresses the original functional blockers:

  • ncu is upgraded to the pnpm-capable v22 line;
  • every invocation explicitly uses --dep prod,dev,optional,peer --no-deprecated, so the root packageManager declaration is not upgraded with ordinary dependencies;
  • upgradePackage uses repeated native ncu workspace arguments instead of launching another pnpm exec after manifests become dirty;
  • the final pnpm install --no-frozen-lockfile remains after all manifest edits.

I still see the following blockers before merge.

1. New App tokens inherit every installation permission

The new actions/create-github-app-token calls at .github/workflows/pnpm-upgrade.yml:98, :225, and :303 specify no permission-* inputs. By default, each minted token inherits all permissions granted to the App installation. Zizmor reports all three as new high-severity / high-confidence github-app findings.

Please either keep the reviewer-auth migration in the previously suggested separate PR, or explicitly narrow every token to what these dependency PR jobs need:

with:
  app-id: ${{ secrets.CDKTN_MAINTAINERS_APP_ID }}
  private-key: ${{ secrets.CDKTN_MAINTAINERS_APP_PRIVATE_KEY }}
  permission-contents: write
  permission-pull-requests: write
  permission-members: read
  • contents: write is needed to create/update the automation branch.
  • pull-requests: write covers creating/updating the PR, labels, and review requests.
  • members: read limits organization access to the team lookup already being requested for cdktn-maintainers.

The App installation must grant those permissions; these inputs narrow the resulting token and cannot elevate it. prRoot should also declare an explicit job-level permissions: { contents: read }, matching the other jobs, so its ambient GITHUB_TOKEN is not left at repository defaults.

2. ncu is still range-pinned rather than fully pinned

All three install steps currently use:

npm -g install npm-check-updates@^22.2.9

The prior recommendation was an exact reviewed tool pin:

npm -g install npm-check-updates@22.2.9

The caret allows a future 22.x release to change scheduled CI behavior without a repository change or review. This workflow already pins actions/container content and the repository integrity-pins pnpm, so ncu should be deterministic as well.

Scope / artifact-value

The App-token migration is separable from the ncu/workspace fix and expands this PR into credential/identity behavior. split: the smallest reviewable path is to merge the ncu repair independently and move the three App-token/committer changes to an auth-focused PR. If retained here, the least-privilege fixes above are required.

No new tests were added. The configured cdktn tests are green, but they do not exercise this scheduled workflow; a safe workflow_dispatch run remains the meaningful end-to-end validation for ncu workspace selection, lockfile reconciliation, App permissions, and team-reviewer assignment.

Zizmor baseline comparison

  • Changed workflow: .github/workflows/pnpm-upgrade.yml
  • Baseline findings: 121
  • Head findings in the changed workflow: 12
  • New/touched findings: 3
  • Result: ❌ ATTENTION REQUIRED — the three new unrestricted GitHub App-token findings above are PR-specific blockers.

Verdict: REQUEST_CHANGES

@so0k

so0k commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

oops not sure why The bot posted that 2nd comment - I didn't approve it to comment 😬

@sakul-learning

Copy link
Copy Markdown
Contributor

Follow-up review — 4dff66d

The previous blockers are resolved:

  • all three jobs now pin the reviewed tool exactly as npm-check-updates@22.2.9;
  • all three GitHub App tokens are narrowed to contents: write, pull-requests: write, and members: read;
  • prRoot now limits its ambient GITHUB_TOKEN to contents: read;
  • the ncu native-workspace selection, explicit dependency/deprecation policy, and final non-frozen lockfile refresh remain intact.

The configured checks pass:

  • pnpm exec jest packages/cdktn/test/validations.test.ts --runInBand: 31/31 tests and 9/9 snapshots
  • pnpm exec nx build cdktn: success, 0 errors / 0 warnings (+30 silenced)
  • pnpm exec nx test cdktn --runInBand: 457/457 tests and 288/288 snapshots

These code-level checks do not execute the scheduled workflow; a safe workflow_dispatch run remains the best end-to-end confirmation of the App installation permissions and team-reviewer assignment, but I do not see a merge blocker in the current diff.

Zizmor baseline comparison

  • Changed workflow: .github/workflows/pnpm-upgrade.yml
  • Baseline findings: 121
  • Head findings in the changed workflow: 7
  • New/touched findings: 0
  • Result: ✅ PASS — the three prior unrestricted GitHub App-token findings are gone, with no new or touched workflow-security findings.

Ponytail artifact-value pass: the changed workflow logic is now cohesive and each added permission/configuration line serves the active dependency-update path. No new tests, generated files, dependencies, docs, or delivered SpecLedger artifacts were added.

Verdict: APPROVE

@jsteinich
jsteinich merged commit e1a69fc into open-constructs:main Jul 18, 2026
12 checks passed
@jsteinich
jsteinich deleted the fix_pnpm_upgrade_ncu branch July 18, 2026 22:22
so0k pushed a commit that referenced this pull request Aug 7, 2026
🤖 Release PR — merge to cut a new release. Kept open and rebased
as commits land on `main`.
---


<details><summary>0.24.0</summary>

##
[0.24.0](v0.23.4...v0.24.0)
(2026-08-06)


### ⚠ BREAKING CHANGES

* **lib:** validate Terraform function versions by default
([#362](#362))
* **deps:** Require Node 22 minimum
([#345](#345))
* **lib:** preserve symlinks in TerraformAsset walkers
([#321](#321))
* **cli:** replace node-fetch with undici
([#306](#306))

### Features

* **lib:** canonical asset hashes behind the canonicalAssetHashes
feature flag
([#323](#323))
([76dd4ff](76dd4ff))
* **lib:** validate Terraform function versions by default
([#362](#362))
([4ac0736](4ac0736))
* support newer provider plugin-protocol features via targetVersions
(RFC-04)
([#296](#296))
([90322f9](90322f9))


### Bug Fixes

* **cli:** don't downgrade prebuilt providers on a transient registry
failure
([#298](#298))
([a960c5c](a960c5c))
* **cli:** include dev dependencies in npm version lookup
([#280](#280))
([955204a](955204a))
* **docs:** fix stale constructs pin breaking with()/IMixin docs
([#305](#305))
([605cf63](605cf63))
* **gha:** Allow pnpm to update the lockfile after package updates
([#318](#318))
([a899b7c](a899b7c))
* **gha:** Fix pnpm upgrade workflow
([#335](#335))
([e1a69fc](e1a69fc))
* **gha:** flip merged release PR label to autorelease: tagged
([#302](#302))
([8d64f6c](8d64f6c))
* **gha:** mint the Go-publish token from the CDKTN Maintainers app
([#369](#369))
([71921ce](71921ce))
* **gha:** mint the Go-publish token from the open-constructs-cdktn App
([#368](#368))
([179f10c](179f10c))
* **gha:** pass the Go-publish App token as x-access-token userinfo
([#370](#370))
([4e3ff19](4e3ff19))
* **lib:** Disallow constructs 10.8 until support can be added
([#363](#363))
([8bdae0d](8bdae0d))
* **lib:** preserve symlinks in TerraformAsset walkers
([#321](#321))
([6360e20](6360e20))
* typo in `moveFromId` JSDoc
([#355](#355))
([e1cf8ce](e1cf8ce))


### Miscellaneous Chores

* **cli:** replace Ink + React with smaller-tree CLI libraries
([#264](#264))
([a6aff7e](a6aff7e))
* **cli:** replace node-fetch with undici
([#306](#306))
([1317141](1317141))
* **deps:** bump glob to 13.0.6
([#307](#307))
([47ee2bb](47ee2bb))
* **deps:** bump the github-actions-backward-compatible group with 2
updates
([#295](#295))
([eab2a01](eab2a01))
* **deps:** replace lerna with nx
([#315](#315))
([94999fc](94999fc))
* **deps:** Require Node 22 minimum
([#345](#345))
([2bf315d](2bf315d))
* **deps:** update ci-info to 4.4.0 across all packages
([#329](#329))
([557a163](557a163))
* **deps:** update fs-extra to 11.3.6 across all packages
([#328](#328))
([95753a9](95753a9))
* **deps:** update minimatch to 10.2.5
([#330](#330))
([d1c1c53](d1c1c53))
* **deps:** Update sscaff to v2.0.388
([#331](#331))
([38ea0ba](38ea0ba))
* **deps:** Update zod to v4.4.3
([#332](#332))
([c10ee35](c10ee35))
* **deps:** Upgrade dependencies
([#347](#347))
([45d3a66](45d3a66))
* remove cdktf from tests
([#277](#277))
([dc9a8e9](dc9a8e9))
* ship Terraform 1.15.8 in the jsii-terraform image
([#367](#367))
([deaa9b0](deaa9b0))
* Upgrade dependencies for lib
([#348](#348))
([d616f17](d616f17))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: open-constructs-cdktn[bot] <291052431+open-constructs-cdktn[bot]@users.noreply.github.com>
X-Guardian pushed a commit to X-Guardian/cdk-terrain that referenced this pull request Aug 10, 2026
### Description

Attempting to fix failures seen in pnpm upgrade job:
https://github.com/open-constructs/cdk-terrain/actions/runs/29232337176/job/86759126716

### Checklist

- [ ] I have updated the PR title to match [CDKTN's style
guide](https://github.com/open-constructs/cdk-terrain/blob/main/CONTRIBUTING.md#pull-requests-1)
- [ ] I have run the linter on my code locally
- [ ] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the
[documentation](https://github.com/open-constructs/cdk-terrain-docs/tree/main/content)
if applicable
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works if applicable
- [ ] New and existing unit tests pass locally with my changes

<!-- If this is still a work in progress, feel free to open a draft PR
until you're able to check off all the items on the list above -->
X-Guardian pushed a commit to X-Guardian/cdk-terrain that referenced this pull request Aug 10, 2026
🤖 Release PR — merge to cut a new release. Kept open and rebased
as commits land on `main`.
---


<details><summary>0.24.0</summary>

##
[0.24.0](open-constructs/cdk-terrain@v0.23.4...v0.24.0)
(2026-08-06)


### ⚠ BREAKING CHANGES

* **lib:** validate Terraform function versions by default
([open-constructs#362](open-constructs#362))
* **deps:** Require Node 22 minimum
([open-constructs#345](open-constructs#345))
* **lib:** preserve symlinks in TerraformAsset walkers
([open-constructs#321](open-constructs#321))
* **cli:** replace node-fetch with undici
([open-constructs#306](open-constructs#306))

### Features

* **lib:** canonical asset hashes behind the canonicalAssetHashes
feature flag
([open-constructs#323](open-constructs#323))
([76dd4ff](open-constructs@76dd4ff))
* **lib:** validate Terraform function versions by default
([open-constructs#362](open-constructs#362))
([4ac0736](open-constructs@4ac0736))
* support newer provider plugin-protocol features via targetVersions
(RFC-04)
([open-constructs#296](open-constructs#296))
([90322f9](open-constructs@90322f9))


### Bug Fixes

* **cli:** don't downgrade prebuilt providers on a transient registry
failure
([open-constructs#298](open-constructs#298))
([a960c5c](open-constructs@a960c5c))
* **cli:** include dev dependencies in npm version lookup
([open-constructs#280](open-constructs#280))
([955204a](open-constructs@955204a))
* **docs:** fix stale constructs pin breaking with()/IMixin docs
([open-constructs#305](open-constructs#305))
([605cf63](open-constructs@605cf63))
* **gha:** Allow pnpm to update the lockfile after package updates
([open-constructs#318](open-constructs#318))
([a899b7c](open-constructs@a899b7c))
* **gha:** Fix pnpm upgrade workflow
([open-constructs#335](open-constructs#335))
([e1a69fc](open-constructs@e1a69fc))
* **gha:** flip merged release PR label to autorelease: tagged
([open-constructs#302](open-constructs#302))
([8d64f6c](open-constructs@8d64f6c))
* **gha:** mint the Go-publish token from the CDKTN Maintainers app
([open-constructs#369](open-constructs#369))
([71921ce](open-constructs@71921ce))
* **gha:** mint the Go-publish token from the open-constructs-cdktn App
([open-constructs#368](open-constructs#368))
([179f10c](open-constructs@179f10c))
* **gha:** pass the Go-publish App token as x-access-token userinfo
([open-constructs#370](open-constructs#370))
([4e3ff19](open-constructs@4e3ff19))
* **lib:** Disallow constructs 10.8 until support can be added
([open-constructs#363](open-constructs#363))
([8bdae0d](open-constructs@8bdae0d))
* **lib:** preserve symlinks in TerraformAsset walkers
([open-constructs#321](open-constructs#321))
([6360e20](open-constructs@6360e20))
* typo in `moveFromId` JSDoc
([open-constructs#355](open-constructs#355))
([e1cf8ce](open-constructs@e1cf8ce))


### Miscellaneous Chores

* **cli:** replace Ink + React with smaller-tree CLI libraries
([open-constructs#264](open-constructs#264))
([a6aff7e](open-constructs@a6aff7e))
* **cli:** replace node-fetch with undici
([open-constructs#306](open-constructs#306))
([1317141](open-constructs@1317141))
* **deps:** bump glob to 13.0.6
([open-constructs#307](open-constructs#307))
([47ee2bb](open-constructs@47ee2bb))
* **deps:** bump the github-actions-backward-compatible group with 2
updates
([open-constructs#295](open-constructs#295))
([eab2a01](open-constructs@eab2a01))
* **deps:** replace lerna with nx
([open-constructs#315](open-constructs#315))
([94999fc](open-constructs@94999fc))
* **deps:** Require Node 22 minimum
([open-constructs#345](open-constructs#345))
([2bf315d](open-constructs@2bf315d))
* **deps:** update ci-info to 4.4.0 across all packages
([open-constructs#329](open-constructs#329))
([557a163](open-constructs@557a163))
* **deps:** update fs-extra to 11.3.6 across all packages
([open-constructs#328](open-constructs#328))
([95753a9](open-constructs@95753a9))
* **deps:** update minimatch to 10.2.5
([open-constructs#330](open-constructs#330))
([d1c1c53](open-constructs@d1c1c53))
* **deps:** Update sscaff to v2.0.388
([open-constructs#331](open-constructs#331))
([38ea0ba](open-constructs@38ea0ba))
* **deps:** Update zod to v4.4.3
([open-constructs#332](open-constructs#332))
([c10ee35](open-constructs@c10ee35))
* **deps:** Upgrade dependencies
([open-constructs#347](open-constructs#347))
([45d3a66](open-constructs@45d3a66))
* remove cdktf from tests
([open-constructs#277](open-constructs#277))
([dc9a8e9](open-constructs@dc9a8e9))
* ship Terraform 1.15.8 in the jsii-terraform image
([open-constructs#367](open-constructs#367))
([deaa9b0](open-constructs@deaa9b0))
* Upgrade dependencies for lib
([open-constructs#348](open-constructs#348))
([d616f17](open-constructs@d616f17))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: open-constructs-cdktn[bot] <291052431+open-constructs-cdktn[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/skip-examples Skip Examples Testing in PR ci/skip-integration Skips Integration Testing on PR ci/skip-provider-integration Skips Provider Integration Tests on PR ci/skip-unit Skips Unit Testing on PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants