mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-03 07:18:03 +01:00
v1.91.213.0 fix(ci): Node.js 22.23.4 in the CI image and Ubicloud free-suite VMs, SHA-256 verified (port #3355, fixes #3354) (#3400)
* fix(ci): bump Node.js to 22.23.4 for CVE-2026-111497 * fix(ci): pin Node.js 22.23.4 in the Ubicloud free-suite bootstrap too, and verify both archives by SHA-256 #3355 bumped Dockerfile.ci only; scripts/ubicloud/setup-free-suite.sh still installed 22.20.0. Both now pin the same version and the linux-x64 SHA-256 from the release's signed SHASUMS256.txt, check the archive before unpacking, and test/ci-image-cli-pin.test.ts keeps the two pins equal (#3354). Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> Co-authored-by: Michael Sumner <75835774+michael-sumner@users.noreply.github.com> Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs(changelog): Node.js 22.23.4 CI pin (#3354) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test(ci-image): name Dockerfile.ci in a form pregate resolves; assert the image hash in the parity case Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: Michael Sumner <75835774+michael-sumner@users.noreply.github.com> Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
7 files changed
+75
-9
No files matched your search
@@ -90,8 +90,13 @@ RUN curl --retry 5 --retry-delay 5 --retry-connrefused -fsSL https://cli.github.
|
||||
# and "gnupg" was renamed to "gpg" on Ubuntu 24.04 anyway, so NodeSource's script
|
||||
# fails before it can add its own repo. Direct tarball download is network-simpler
|
||||
# (one host: nodejs.org) and doesn't touch apt at all.
|
||||
ENV NODE_VERSION=22.20.0
|
||||
# The hash comes from the release's signed SHASUMS256.txt, and the archive is
|
||||
# checked before it is unpacked. scripts/ubicloud/setup-free-suite.sh pins the
|
||||
# same version and hash (test/ci-image-cli-pin.test.ts keeps them equal).
|
||||
ENV NODE_VERSION=22.23.4
|
||||
ARG NODE_SHA256=1805bcd35e6815559bd2eb97db438d3fdb0eb3a5e6a977b7c1badca76337e9ce
|
||||
RUN curl --retry 5 --retry-delay 5 --retry-connrefused -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz" -o /tmp/node.tar.xz \
|
||||
&& echo "${NODE_SHA256} /tmp/node.tar.xz" | sha256sum -c - \
|
||||
&& tar -xJ -C /usr/local --strip-components=1 --no-same-owner -f /tmp/node.tar.xz \
|
||||
&& rm -f /tmp/node.tar.xz \
|
||||
&& node --version \
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# Changelog
|
||||
|
||||
## [1.91.213.0] - 2026-10-25
|
||||
|
||||
**The CI image and the Ubicloud free-suite VMs move off Node.js 22.20.0 to 22.23.4, and both now check the Node archive's SHA-256 before unpacking it (#3354, port of #3355 by @michael-sumner).** 22.20.0 is affected by the October 21, 2026 Node.js security releases, including the Brotli decoder out-of-bounds write (CVE-2026-111497, high) and the TLS hostname bypass for leading-zero IPv4 hosts (CVE-2026-106069, high). 22.23.4 is the patched 22.x release. #3355 bumped `.github/docker/Dockerfile.ci`, but `scripts/ubicloud/setup-free-suite.sh` pins Node separately and would have kept installing 22.20.0 on every remote free-suite run.
|
||||
|
||||
### Fixed
|
||||
- **`.github/docker/Dockerfile.ci`**: `NODE_VERSION` is 22.23.4 (Michael Sumner's commit). The archive is checked against `NODE_SHA256`, the linux-x64 hash from the release's SHASUMS256.txt, whose signature verifies against the Node.js release keyring, before it is unpacked.
|
||||
- **`scripts/ubicloud/setup-free-suite.sh`**: pins the same 22.23.4 and hash, and downloads the archive to a temporary file and verifies it instead of piping `curl` straight into `sudo tar`.
|
||||
|
||||
### Tests
|
||||
- `test/ci-image-cli-pin.test.ts` gains four cases: Dockerfile.ci pins an exact Node version and a SHA-256, both files verify before they unpack, and `setup-free-suite.sh` pins the same version and hash as the image. On #3355's head alone, all four fail; on main, three fail.
|
||||
- The Bun ordering check in `setup-free-suite.sh` now looks for `sha256sum -c` after the Bun download instead of anywhere in the file, because the Node check now comes first.
|
||||
- The test names `Dockerfile.ci` as `join(__dirname, '..', '.github', …)`, the form pregate's literal scan resolves, so a change to the image now selects it (before, pregate refused a Dockerfile.ci-only change with `PREGATE_NO_LANE`).
|
||||
|
||||
### Gate integrity
|
||||
- One accepted-input change to review: the Bun ordering check searches for its `sha256sum -c` from the Bun download onward. It now accepts one input it used to reject: a file with some other `sha256sum -c` before the Bun download and the Bun check after it, which is this file. The property it guards, Bun verified after download and before unpack, is unchanged. A file whose only `sha256sum -c` sits before the download still fails, and so does removing the Bun hash or moving it after `unzip` (negative controls run). No threshold, budget, timeout, trial count or case kind changed.
|
||||
|
||||
## [1.91.212.0] - 2026-10-25
|
||||
|
||||
**/careful no longer asks about words inside a commit message (#1060; ported from #3221 by @Bhumika-1432006).** The careful hook matched its MEDIUM patterns against the whole command, so `git commit -m "fix: prevent drop table in migration"` asked for approval as an SQL DROP. The hook now masks git commit's own literal message before those checks, including the `-m "$(cat <<'EOF' … EOF
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# gstack digest v1.91.212.0 — regenerate/re-copy after upgrading gstack
|
||||
# gstack digest v1.91.213.0 — regenerate/re-copy after upgrading gstack
|
||||
|
||||
Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed
|
||||
for agent hosts without a full skill install. The full skills add workflows,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gstack",
|
||||
"version": "1.91.212",
|
||||
"version": "1.91.213",
|
||||
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
set -euo pipefail
|
||||
|
||||
BUN_VERSION=1.4.2
|
||||
NODE_VERSION=22.20.0
|
||||
NODE_VERSION=22.23.4
|
||||
NODE_SHA256=1805bcd35e6815559bd2eb97db438d3fdb0eb3a5e6a977b7c1badca76337e9ce
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
sudo -E apt-get update -qq
|
||||
@@ -17,9 +18,13 @@ sudo -E apt-get install -y -qq --no-install-recommends \
|
||||
# needs; GitHub-hosted runners ship with this relaxed.
|
||||
sudo sysctl -qw kernel.apparmor_restrict_unprivileged_userns=0
|
||||
|
||||
# The same verified release archive as .github/docker/Dockerfile.ci.
|
||||
if ! command -v node >/dev/null; then
|
||||
curl -fsSL "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
|
||||
| sudo tar -xJ -C /usr/local --strip-components=1
|
||||
node_tmp=$(mktemp -d)
|
||||
curl -fsSL "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" -o "$node_tmp/node.tar.xz"
|
||||
echo "$NODE_SHA256 $node_tmp/node.tar.xz" | sha256sum -c - >/dev/null
|
||||
sudo tar -xJ -C /usr/local --strip-components=1 -f "$node_tmp/node.tar.xz"
|
||||
rm -rf "$node_tmp"
|
||||
fi
|
||||
|
||||
# The exact release archive, verified by SHA-256 before it is unpacked, as in
|
||||
|
||||
@@ -24,7 +24,7 @@ import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
|
||||
const ROOT = path.resolve(__dirname, '..');
|
||||
const DOCKERFILE = path.join(ROOT, '.github', 'docker', 'Dockerfile.ci');
|
||||
const DOCKERFILE = path.join(__dirname, '..', '.github', 'docker', 'Dockerfile.ci');
|
||||
|
||||
/** Package specs from every `npm i -g` / `npm install -g` in the Dockerfile. */
|
||||
export function globalNpmInstallSpecs(source: string): string[] {
|
||||
@@ -193,7 +193,7 @@ describe('other CI Bun installs match the image (#1713, #1706)', () => {
|
||||
test(`${rel} downloads the verified linux-x64 archive instead of piping an installer into a shell`, () => {
|
||||
expect(curlPipedToShell(source)).toEqual([]);
|
||||
const download = source.indexOf('/releases/download/bun-v$BUN_VERSION/bun-linux-x64.zip');
|
||||
const verify = source.indexOf('sha256sum -c');
|
||||
const verify = source.indexOf('sha256sum -c', download);
|
||||
const unpack = source.indexOf('unzip -q');
|
||||
expect(download).toBeGreaterThan(-1);
|
||||
expect(verify).toBeGreaterThan(download);
|
||||
@@ -216,3 +216,43 @@ describe('other CI Bun installs match the image (#1713, #1706)', () => {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('CI Node.js installs match the image and are verified (#3354)', () => {
|
||||
const docker = fs.readFileSync(DOCKERFILE, 'utf-8');
|
||||
const imageVersion = docker.match(/^ENV NODE_VERSION=(\S+)$/m)?.[1];
|
||||
const imageSha = docker.match(/^ARG NODE_SHA256=(\S+)$/m)?.[1];
|
||||
const nodeRun = logicalLines(docker).find((line) => line.includes('nodejs.org/dist/v${NODE_VERSION}/')) ?? '';
|
||||
|
||||
test('Dockerfile.ci pins an exact Node.js version and the SHA-256 of its linux-x64 archive', () => {
|
||||
expect(imageVersion).toMatch(/^\d+\.\d+\.\d+$/);
|
||||
expect(imageSha).toMatch(/^[0-9a-f]{64}$/);
|
||||
});
|
||||
|
||||
test('Dockerfile.ci checks the Node.js archive before it is unpacked', () => {
|
||||
expect(nodeRun, 'Node.js must come from the nodejs.org release archive').not.toBe('');
|
||||
const download = nodeRun.indexOf('-o /tmp/node.tar.xz');
|
||||
const verify = nodeRun.indexOf('echo "${NODE_SHA256} /tmp/node.tar.xz" | sha256sum -c -');
|
||||
const unpack = nodeRun.indexOf('tar -xJ');
|
||||
expect(download).toBeGreaterThan(-1);
|
||||
expect(verify).toBeGreaterThan(download);
|
||||
expect(unpack).toBeGreaterThan(verify);
|
||||
});
|
||||
|
||||
const rel = 'scripts/ubicloud/setup-free-suite.sh';
|
||||
const source = fs.readFileSync(path.join(ROOT, rel), 'utf-8');
|
||||
|
||||
test(`${rel} pins the same Node.js version and SHA-256 as Dockerfile.ci`, () => {
|
||||
expect(imageSha).toMatch(/^[0-9a-f]{64}$/);
|
||||
expect(source.match(/^NODE_VERSION=(\S+)$/m)?.[1]).toBe(imageVersion!);
|
||||
expect(source.match(/^NODE_SHA256=(\S+)$/m)?.[1]).toBe(imageSha!);
|
||||
});
|
||||
|
||||
test(`${rel} checks the Node.js archive before it is unpacked`, () => {
|
||||
const download = source.indexOf('/node-v$NODE_VERSION-linux-x64.tar.xz" -o "$node_tmp/node.tar.xz"');
|
||||
const verify = source.indexOf('echo "$NODE_SHA256 $node_tmp/node.tar.xz" | sha256sum -c -');
|
||||
const unpack = source.indexOf('tar -xJ');
|
||||
expect(download).toBeGreaterThan(-1);
|
||||
expect(verify).toBeGreaterThan(download);
|
||||
expect(unpack).toBeGreaterThan(verify);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user