diff --git a/.changeset/drop-node-20-brotli.md b/.changeset/drop-node-20-brotli.md new file mode 100644 index 0000000..c98ac18 --- /dev/null +++ b/.changeset/drop-node-20-brotli.md @@ -0,0 +1,5 @@ +--- +"@codacy/codacy-cloud-cli": minor +--- + +Require a Node.js runtime patched for CVE-2026-111497 (Brotli decoder out-of-bounds write): `^22.23.4 || ^24.22.1 || >=26.12.1`. Node.js 20 is end-of-life, never got the fix, and is no longer supported. The CLI decompresses Brotli-encoded HTTP responses through Node's bundled decoder, so upgrade Node.js if you are on an older release. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d4e5165..4da66df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - node-version: [20, 22] + node-version: [22, 24] steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 diff --git a/README.md b/README.md index 7bd7653..7365a9f 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ npm run update-api # Update the auto-generated API client ### CI/CD -- **CI**: Runs on every push to `main` and on PRs. Builds, smoke-tests the built CLI, and runs the test suite across Node.js 20 and 22. +- **CI**: Runs on every push to `main` and on PRs. Builds, smoke-tests the built CLI, and runs the test suite across Node.js 22 and 24. - **Release**: Uses [changesets](https://github.com/changesets/changesets) for automated versioning and npm publishing. #### Publishing a new version diff --git a/SPECS/README.md b/SPECS/README.md index 41a1f75..34951f1 100644 --- a/SPECS/README.md +++ b/SPECS/README.md @@ -48,6 +48,7 @@ This is the single source of truth for all project tasks and specs. | Date | What was done | |---|---| +| 2026-11-03 | **Node.js engines raised for CVE-2026-111497** (Brotli decoder OOB write, bundled in Node). `engines` `>=20` → `^22.23.4 \|\| ^24.22.1 \|\| >=26.12.1`, the first patched release of each line; Node 20 is EOL and unpatched, so it is dropped. CI matrix `[20, 22]` → `[22, 24]`. No dependency change: the repo ships no Brotli package, but `fetch` (undici) decompresses `Content-Encoding: br` responses with Node's bundled decoder, so the runtime is the exposure. `engines` only warns on install; no runtime version check was added | | 2026-09-30 | (OD-590, OD-784) `fixedVersion` surfaced on `issue`/`issues`/`pull-request --issue`, now that `CommitIssue` carries it (first in API `57.7.9`; counterpart of `codacy-spa` #3145). **API bump: pinned `57.6.4` → `57.7.10`** — a diff of both bundled specs shows only `CommitIssue.fixedVersion` added, the organization webhook operations retagged `organization` → `webhooks` (the CLI uses none of them) and a `hasWebhooksEnabled` field on an organization schema; no operation signatures shifted, so `SPECS/repository-tokens.md`'s whitelist needed no changes. `57.7.9` and `57.7.10` bundle identical specs. `printIssueCard` (list) and `printIssueCodeContext` (detail, shared with `pull-request --issue` and `finding`'s linked-issue block) now pass `issue.fixedVersion` to the existing `formatDependencyChainsLine`/`formatDependencyChainsBlock`, so a direct dependency reads `Direct - Update to ` and a transitive one ends `(Fixed in )`, as on `finding`/`findings`. The param `finding` passes (`SrmItem.fixedVersion`) still wins when non-empty. An empty array (no fix available) renders as before — no version text — rather than adding a "no fix" phrase the other commands don't use. `fixedVersion` added to all three JSON projections (issue.test.ts 24→28, issues.test.ts 76→78, pull-request.test.ts +2) | | 2026-09-23 | (OD-748) `images` shows a **Tags** column (per-image `tagCount`) and an `Image tags: X of Y used` line under the header, read from `listOrganizationImages`' new `usage` object (OD-724, API 57.6.4 — `fetch-api` bumped from 57.4.17). Still one request per page. The line turns red at the cap, where new tags are rejected. Exact figures, not `formatCount`. `--output json` stays an array and gains `tagCount` only; `usage` is not in the JSON, since adding it would change the top-level shape The `image --delete --keep-latest` budget warning now reads that same `usage.limit` from the image-count request it already made, in place of the hardcoded `DEFAULT_ORG_TAG_CAP` (1,000), and drops its "this CLI cannot read the value in force" disclaimer Both commands tolerate a response without `usage`/`tagCount` (an API behind the client), and the exact-figure formatter is now shared as `formatExactCount` (5 new tests, 784 total) | | 2026-09-22 | (OD-710) **Fix: path parameters are now escaped per segment.** Every `image` subcommand 404'd against a namespaced image name — `codacy/codacy-website`, the shape of all seven images in `gh/codacy` — because the generated client falls back to `encodeURI` when `OpenAPI.ENCODE_PATH` is unset, and `encodeURI` leaves `/` intact by design: it encodes whole URLs, not the segments they are built from. The value expanded into two segments and hit a route that does not exist; verified against the API, where the raw slash returns 404 and `%2F` returns 200. `src/utils/api-path.ts` exports `encodePathSegment` (`encodeURIComponent`) and `src/index.ts` installs it beside `OpenAPI.BASE` — the generated client is untouched, so `npm run update-api` cannot undo it. The encoder is global, which is correct rather than incidental: `{branchName}` and `{filePath}` carry slashes for the same reason, though no shipped command sends either as a path parameter today, so nothing else changes shape. Confirmed end to end against `gh/codacy` after the fix: `images` lists 7, `image codacy/codacy-website` lists 84 tags, `--delete --keep-latest 10 --dry-run` reports 74 of 84 (5 new tests, 767 total) | diff --git a/SPECS/deployment.md b/SPECS/deployment.md index 3527044..18dd45a 100644 --- a/SPECS/deployment.md +++ b/SPECS/deployment.md @@ -7,7 +7,7 @@ - **Binary name:** `codacy` (registered in `package.json` under `bin`) - **Included files:** `dist/` and `README.md` (via `files` field) - **Pre-publish:** `prepublishOnly` runs `npm run update-api && npm run build` as a safety net for local publishes -- **Engines:** requires Node.js >= 20 +- **Engines:** requires Node.js `^22.23.4 || ^24.22.1 || >=26.12.1` — the first releases of each line with the bundled-Brotli fix for CVE-2026-111497 (Node 20 is EOL and was never patched) - **Install globally:** `npm install -g "@codacy/codacy-cloud-cli"` ## GitHub Actions @@ -16,7 +16,7 @@ Triggers on: push and pull requests to `main`. -Matrix: Node.js 20, 22. +Matrix: Node.js 22, 24. Jobs: - **build-and-test**: checkout → setup node → install → generate API client → type check → build → smoke test the built CLI → test diff --git a/package-lock.json b/package-lock.json index 3ed3250..b1ed13d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@codacy/codacy-cloud-cli", - "version": "1.9.0", + "version": "1.14.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@codacy/codacy-cloud-cli", - "version": "1.9.0", + "version": "1.14.0", "license": "ISC", "dependencies": { "@codacy/tooling": "0.23.0", @@ -38,7 +38,7 @@ "vitest": "4.0.18" }, "engines": { - "node": ">=20" + "node": "^22.23.4 || ^24.22.1 || >=26.12.1" } }, "node_modules/@apidevtools/json-schema-ref-parser": { diff --git a/package.json b/package.json index 3dd72a1..c826653 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "author": "Codacy (https://www.codacy.com)", "license": "ISC", "engines": { - "node": ">=20" + "node": "^22.23.4 || ^24.22.1 || >=26.12.1" }, "dependencies": { "@codacy/tooling": "0.23.0",