From f078ae4415e4e15d12313b18aad5687d3b232c2e Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 26 Jun 2026 11:01:45 +0000 Subject: [PATCH 1/2] ci: pin Node to exact patched versions via central env vars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to d7175e2 (which pinned only the skill-eval E2E job). Every other actions/setup-node step still floated a bare major ("22"/"24") and would silently reuse the runner's pre-cached buggy patch (24.17.0 / 22.23.0). Those carry CVE-2026-48931's http.Agent fix, which added a `data` listener on idle sockets that makes keep-alive fetch reuse throw false ERR_STREAM_PREMATURE_CLOSE — fixed in 24.18.0 / 22.23.1 (nodejs/node#64004). Centralize the versions as per-workflow env vars (NODE_VERSION_22 / NODE_VERSION_24) so each file has a single source of truth, and pin the exact patched releases: - ci.yml: all 22/24 setup-node steps + the build-npm matrix (mapped from bare-major labels so the `matrix.node == '22'` artifact guard still works) - release.yml, sentry-release.yml: 22.23.1 (publish/upload over HTTPS) - docs-preview.yml: 24.18.0 Validated with actionlint (no new findings vs main). --- .github/workflows/ci.yml | 37 ++++++++++++++++++---------- .github/workflows/docs-preview.yml | 14 ++++++++--- .github/workflows/release.yml | 9 ++++++- .github/workflows/sentry-release.yml | 15 ++++++++--- 4 files changed, 55 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd845a6d7..e4d16879a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,17 @@ env: # don't fully support it, causing SIGABRT in Node.js processes. # See: https://github.com/actions/runner-images/issues/13602 UV_USE_IO_URING: "0" + # CI Node.js versions, pinned to exact patches and used as the single source + # of truth for every actions/setup-node step (referenced as + # ${{ env.NODE_VERSION_xx }}). Node 24.17.0 / 22.23.0 (CVE-2026-48931's + # http.Agent fix) added a `data` listener on idle agent sockets that makes + # keep-alive fetch reuse throw false ERR_STREAM_PREMATURE_CLOSE + # ("Premature close" — hit by the skill-eval planner talking to external + # APIs). Fixed in 24.18.0 / 22.23.1 (nodejs/node#64004). A floating major + # ("24"/"22") silently reuses the runner's pre-cached buggy patch, so pin the + # exact patched versions here and bump them in one place. + NODE_VERSION_22: "22.23.1" + NODE_VERSION_24: "24.18.0" jobs: changes: @@ -128,7 +139,7 @@ jobs: - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v6 with: - node-version: "22" + node-version: ${{ env.NODE_VERSION_22 }} - uses: actions/cache@v5 id: cache with: @@ -183,7 +194,7 @@ jobs: - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v6 with: - node-version: "22" + node-version: ${{ env.NODE_VERSION_22 }} - uses: actions/cache@v5 id: cache with: @@ -214,7 +225,7 @@ jobs: - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v6 with: - node-version: "24" + node-version: ${{ env.NODE_VERSION_24 }} - uses: actions/cache@v5 id: cache with: @@ -249,7 +260,7 @@ jobs: - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v6 with: - node-version: "22" + node-version: ${{ env.NODE_VERSION_22 }} - uses: actions/cache@v5 id: cache with: @@ -710,13 +721,10 @@ jobs: - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v6 with: - # Pin exact patch: Node 24.17.0 (and 22.23.0) shipped CVE-2026-48931's - # http.Agent fix, which added a `data` listener on idle sockets that - # makes keep-alive fetch reuse throw false ERR_STREAM_PREMATURE_CLOSE. - # This surfaces as "Premature close" in the skill-eval planner's HTTP - # calls. Fixed in 24.18.0 (nodejs/node#64004). A floating "24" silently - # reuses the runner's pre-cached buggy 24.17.0, so pin the exact patch. - node-version: "24.18.0" + # Pinned to a patched 24 — the skill-eval planner makes keep-alive + # HTTPS calls and would hit the ERR_STREAM_PREMATURE_CLOSE regression + # on a floating "24". See NODE_VERSION_24 in the top-level env block. + node-version: ${{ env.NODE_VERSION_24 }} - uses: actions/cache@v5 id: cache with: @@ -755,7 +763,10 @@ jobs: - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v6 with: - node-version: ${{ matrix.node }} + # Matrix entries stay bare majors ("22"/"24") for the job name and the + # `matrix.node == '22'` artifact guard below; map each to its exact + # patched version from the central env block here. + node-version: ${{ matrix.node == '24' && env.NODE_VERSION_24 || env.NODE_VERSION_22 }} - uses: actions/cache@v5 id: cache with: @@ -818,7 +829,7 @@ jobs: # build doesn't rely on whatever ships on the runner image. - uses: actions/setup-node@v6 with: - node-version: "24" + node-version: ${{ env.NODE_VERSION_24 }} - uses: actions/cache@v5 id: cache with: diff --git a/.github/workflows/docs-preview.yml b/.github/workflows/docs-preview.yml index 2c056af98..ac5fb00ba 100644 --- a/.github/workflows/docs-preview.yml +++ b/.github/workflows/docs-preview.yml @@ -27,6 +27,13 @@ concurrency: group: docs-preview-${{ github.ref }} cancel-in-progress: true +env: + # Pin Node to an exact patched version (single source of truth). A floating + # "24" can reuse the runner's pre-cached 24.17.0, which carries the + # ERR_STREAM_PREMATURE_CLOSE regression on keep-alive fetch reuse + # (nodejs/node#64004, fixed in 24.18.0). + NODE_VERSION_24: "24.18.0" + jobs: preview: runs-on: ubuntu-latest @@ -35,11 +42,12 @@ jobs: - uses: pnpm/action-setup@v4 - # Astro 6 requires Node >= 22.12. Pin an explicit version so the docs - # build doesn't rely on whatever ships on the runner image. + # Astro 6 requires Node >= 22.12. Pin an exact patched version (see + # NODE_VERSION_24) so the docs build doesn't rely on the runner image's + # default. - uses: actions/setup-node@v6 with: - node-version: "24" + node-version: ${{ env.NODE_VERSION_24 }} - uses: actions/cache@v5 id: cache diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3e2930c70..3e712f083 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,6 +15,13 @@ permissions: contents: write pull-requests: write +env: + # Pin Node to an exact patched version (single source of truth). A floating + # "22" can reuse the runner's pre-cached 22.23.0, which carries the + # ERR_STREAM_PREMATURE_CLOSE regression on keep-alive fetch reuse + # (nodejs/node#64004, fixed in 22.23.1). + NODE_VERSION_22: "22.23.1" + jobs: release: runs-on: ubuntu-latest @@ -33,7 +40,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: 22 + node-version: ${{ env.NODE_VERSION_22 }} - name: Prepare release uses: getsentry/craft@v2 env: diff --git a/.github/workflows/sentry-release.yml b/.github/workflows/sentry-release.yml index 6a9fc42ce..e2c335fce 100644 --- a/.github/workflows/sentry-release.yml +++ b/.github/workflows/sentry-release.yml @@ -13,6 +13,14 @@ permissions: contents: read issues: write +env: + # Pin Node to an exact patched version (single source of truth). A floating + # "22" can reuse the runner's pre-cached 22.23.0, which carries the + # ERR_STREAM_PREMATURE_CLOSE regression on keep-alive fetch reuse + # (nodejs/node#64004, fixed in 22.23.1). This job installs from and uploads + # over HTTPS. + NODE_VERSION_22: "22.23.1" + jobs: finalize: name: Finalize Sentry Release @@ -34,12 +42,13 @@ jobs: with: fetch-depth: 0 - # The sentry npm package requires Node.js >= 22.12 — pin an explicit - # version so this job doesn't depend on the runner image's default. + # The sentry npm package requires Node.js >= 22.12 — pin an exact patched + # version (see NODE_VERSION_22) so this job doesn't depend on the runner + # image's default. - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: 22 + node-version: ${{ env.NODE_VERSION_22 }} - name: Install CLI run: npm install -g "sentry@${VERSION}" From 3b8b2f1a28dec32a35651c03c44ece8a102065a5 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 26 Jun 2026 14:09:57 +0000 Subject: [PATCH 2/2] ci: pin Node in fork skill-eval workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The eval-skill-fork.yml `eval` job set up pnpm but never ran actions/setup-node, so pnpm install, generate:docs, and eval:skill all ran on the runner's floating Node — the exact unpinned path this PR exists to eliminate, and the one most likely to hit the false ERR_STREAM_PREMATURE_CLOSE (the skill-eval planner talks to external APIs over keep-alive fetch). Add a workflow-level NODE_VERSION_24 env var and an actions/setup-node step pinned to it, mirroring the non-fork skill-eval job in ci.yml. Validated with actionlint (no findings). --- .github/workflows/eval-skill-fork.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/eval-skill-fork.yml b/.github/workflows/eval-skill-fork.yml index 649d5f0b0..7edffa694 100644 --- a/.github/workflows/eval-skill-fork.yml +++ b/.github/workflows/eval-skill-fork.yml @@ -9,6 +9,15 @@ permissions: statuses: write pull-requests: write +env: + # Pin Node to the exact patched release rather than floating on the runner's + # pre-cached major. Node 24.17.0 (CVE-2026-48931's http.Agent fix) added a + # `data` listener on idle agent sockets that makes keep-alive fetch reuse + # throw a false ERR_STREAM_PREMATURE_CLOSE — exactly the failure the + # skill-eval planner hits talking to external APIs. Fixed in 24.18.0 + # (nodejs/node#64004). Keep in sync with NODE_VERSION_24 in ci.yml. + NODE_VERSION_24: "24.18.0" + jobs: remove-labels-on-sync: name: Reset eval labels @@ -38,6 +47,10 @@ jobs: - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v6 + with: + node-version: ${{ env.NODE_VERSION_24 }} + - uses: actions/cache@v5 id: cache with: