diff --git a/.github/workflows/cve.yml b/.github/workflows/cve.yml new file mode 100644 index 0000000..850b71d --- /dev/null +++ b/.github/workflows/cve.yml @@ -0,0 +1,43 @@ +# cve — known vulnerabilities in what this repository uses (#83). Runs on main after each merge, on +# each pull request and every Monday, so an advisory published after a merge still turns main red. +# +# - osv: OSV-Scanner reads this repository's lock files (extension/package-lock.json) against +# osv.dev. The checkout has no submodules: forks/picasso and vendor/archify are scanned by their +# own repositories. +# - node: the node of the dev shell (nix/nodejs-bin.nix). `just node-check` fails below the fixed +# versions of the October 2026 security release, because the advisory databases lag the +# Node.js blog; is-my-node-vulnerable checks it against Node.js's own advisories +# (nodejs/security-wg), which catches the next release once its records are published. +name: cve + +on: + push: + branches: [main] + pull_request: + schedule: + - cron: "23 6 * * 1" + workflow_dispatch: + +permissions: + contents: read + +jobs: + osv: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v31 + - name: OSV-Scanner over this repository's lock files + run: nix run nixpkgs#osv-scanner -- scan source --recursive . + + node: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v31 + - name: The dev shell's node has the October 2026 fixes + run: nix develop --no-update-lock-file --command just node-check + - name: is-my-node-vulnerable, on the dev shell's node + run: nix develop --no-update-lock-file --command npx --yes is-my-node-vulnerable@1.6.1 diff --git a/.github/workflows/extension.yml b/.github/workflows/extension.yml index bb5644c..0d61dfd 100644 --- a/.github/workflows/extension.yml +++ b/.github/workflows/extension.yml @@ -37,9 +37,9 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - # ⚠ The dev shell's `nodejs` (nixpkgs at flake.lock) was not checked offline; 22 is the LTS - # the extension was developed on (v22.22.3). - node-version: 22 + # The node of the dev shell (nix/nodejs-bin.nix), the October 2026 security release (#83). + # A bare `22` gave 22.23.3, below the 22.23.4 fix; the CVE workflow fails below 24.22.1. + node-version: 24.22.1 cache: npm cache-dependency-path: extension/package-lock.json - run: npm ci diff --git a/.github/workflows/plugin.yml b/.github/workflows/plugin.yml index 2c0f35e..b2c3c53 100644 --- a/.github/workflows/plugin.yml +++ b/.github/workflows/plugin.yml @@ -46,6 +46,10 @@ jobs: timeout-minutes: 5 steps: - uses: actions/checkout@v4 + # The runner's own node is not pinned and its version is not in the logs (#83): pin it. + - uses: actions/setup-node@v4 + with: + node-version: 24.22.1 - run: npm install -g "@anthropic-ai/claude-code@$CLAUDE_CODE_VERSION" - run: scripts/plugin-smoke.sh @@ -56,6 +60,10 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v4 + # The runner's own node is not pinned and its version is not in the logs (#83): pin it. + - uses: actions/setup-node@v4 + with: + node-version: 24.22.1 - run: npm install -g "@anthropic-ai/claude-code@$CLAUDE_CODE_VERSION" - env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} diff --git a/AGENTS.md b/AGENTS.md index 3373ba9..6c3d016 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,7 +42,7 @@ just opencode-qwen # serve Qwen3.6-27B and run OpenCode - `.mcp.json` + `scripts/firefox-mcp.sh` — the Firefox MCP (Mozilla's `@mozilla/firefox-devtools-mcp`, pinned in the script, throwaway profile; on Ubuntu the snap's real binary, since geckodriver cannot start the `/usr/bin/firefox` wrapper): lets an agent install `extension/dist-firefox` (`install_extension`, type `path`) and drive the page. A dev tool, not part of the plugin. - `.opencode.json` — OpenCode configuration pointing to local `llamacpp/qwen3.6-27b`. - `justfile` — recipes for running OpenCode, serving Qwen, and quality checks. -- `flake.nix` / `flake.lock` — reproducible dev shell. +- `flake.nix` / `flake.lock` — reproducible dev shell. Its node is `nix/nodejs-bin.nix`, the official nodejs.org 24.22.1 (the October 2026 security release, #83), until nixpkgs ships it; then drop the file and use `nodejs` again. `just node-check` (in `just quality`) fails below the fixed versions; `.github/workflows/cve.yml` runs it, OSV-Scanner over the lock files and is-my-node-vulnerable on main, on each PR and every Monday. - `evals/` — regression cases for rules (not yet run by a harness). - `docs/whitepaper/` — the whitepaper's sources: `pt-BR.md` and `en.md` (same sections, same facts) and `template.tex`, a copy of h0ffmann/closed-source's Paper Fabric template at `563c339` (MIT). `just whitepaper` builds `WHITEPAPER.pdf` and `WHITEPAPER.en.pdf` (pandoc and XeLaTeX from the host; the marola and ouroboric logos fetched at pinned commits with their sha256, never committed). Hard cap: 8 pages each (`just whitepaper-check`, in `just quality`). Every fact in it comes from a repo file; `⚠` stays in the PDF. - `README.md` — human-facing documentation (pt-BR); `README.en.md` is its English mirror. Hard cap: 10 minutes of reading time each, by the plugin's own calculator (`just quality` fails above it). Detail goes to the site (rules, origins, roadmap, awesome, ELI5, graphs), to `docs/`, or to *Reference* below, never back into the README. diff --git a/CHANGELOG.md b/CHANGELOG.md index 8410865..e325936 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ cabeçalho abaixo andam juntos. `just release X.Y.Z` abre o PR da versão e, dep ## Unreleased +- Node 24.22.1, a release de segurança de 2026-10-21 (#83), no dev shell e no CI. O nixpkgs ainda está na + 24.21.0, afetada, então o `nix/nodejs-bin.nix` usa o binário oficial do nodejs.org, fixado pelo sha256. + O `just node-check`, no `just quality`, falha abaixo das versões corrigidas. O `cve.yml` roda o + OSV-Scanner nos locks, o `node-check` e o `is-my-node-vulnerable` na `main`, em cada PR e toda segunda. + O shell do site recebe a mesma correção pelo picasso (h0ffmann/picasso#143). - O site embute o whitepaper em pt-BR numa seção própria (`#whitepaper`), como o site do closed-source embute o artigo dele: o PDF num quadro, carregado sob demanda, com links para abrir e baixar onde o quadro não aparece. A pílula do pt-BR sai da capa; a do inglês fica. diff --git a/flake.nix b/flake.nix index cebae0b..04a0406 100644 --- a/flake.nix +++ b/flake.nix @@ -35,7 +35,10 @@ curl lsof vale # the Saramago prose linter (lint/saramago) - nodejs # runs vendor/archify (`just figure`); Chrome comes from the host + # node 24.22.1, the October 2026 security release (#83), from nodejs.org until nixpkgs + # ships it: runs vendor/archify (`just figure`) and the extension's build and tests. + # `just node-check` fails below it. Chrome comes from the host. + (pkgs.callPackage ./nix/nodejs-bin.nix { }) librsvg # rsvg-convert: the whitepaper's logos, SVG to PDF (`just whitepaper`) poppler-utils # pdfinfo: the whitepaper's 5-page cap; pandoc and XeLaTeX come from the host iproute2 diff --git a/justfile b/justfile index 31f095d..2302ed2 100644 --- a/justfile +++ b/justfile @@ -334,7 +334,7 @@ _reading-badge file lang: echo "[![leitura estimada: $min](https://img.shields.io/badge/leitura%20estimada-$enc-1682D4?style=flat-square)](#tempo-de-leitura)" fi -quality: pins saramago-check plugin-check figure-check whitepaper-check ext-test +quality: pins saramago-check plugin-check figure-check whitepaper-check node-check ext-test bash skills/ptbr-routing/bin/run.sh --self-test bash skills/ptbr-routing/bin/run.sh --check just --list >/dev/null @@ -489,3 +489,14 @@ doi: title=$(jq -r .title .zenodo.json) curl -fsS --max-time 60 -G https://zenodo.org/api/records --data-urlencode "q=title:\"$title\"" --data-urlencode size=10 --data-urlencode sort=mostrecent \ | jq -er '.hits.hits | if length == 0 then error("no record yet; Zenodo can take a few minutes after a release") else .[] | [.metadata.version // "?", .doi, .conceptdoi // "?", .metadata.license.id // "?", .metadata.resource_type.title // "?", .links.html] | @tsv end' + +# The node on PATH has the fixes of the October 2026 security release (#83): the minimum of its line, +# from nodejs.org/en/blog/vulnerability/october-2026-security-releases. Any other line fails, 18 and +# 20 (end of life) included. The CVE scanners lag the advisory, so the minimum is written here. +node-check: + #!/usr/bin/env bash + set -euo pipefail + v=$(node --version); v=${v#v} + case "${v%%.*}" in 22) min=22.23.4 ;; 24) min=24.22.1 ;; 26) min=26.12.1 ;; *) min= ;; esac + [ -n "$min" ] && [ "$(printf '%s\n%s\n' "$min" "$v" | sort -V | head -1)" = "$min" ] || { echo "node-check: node $v is affected or unsupported; use 22.23.4+, 24.22.1+ or 26.12.1+ (#83)" >&2; exit 1; } + echo "node-check: node $v (minimum $min)" diff --git a/nix/nodejs-bin.nix b/nix/nodejs-bin.nix new file mode 100644 index 0000000..ff9fac6 --- /dev/null +++ b/nix/nodejs-bin.nix @@ -0,0 +1,57 @@ +# Copied from h0ffmann/picasso labs/gleam-website/nodejs-bin.nix (h0ffmann/picasso#143): a lab references +# nothing outside itself, so this repository keeps its own copy. Same version, same hashes. +# Node.js 24.22.1, the official build from nodejs.org, in place of nixpkgs' nodejs until nixpkgs +# ships it: 24.22.1 is the October 2026 security release (Brotli RCE, TLS hostname bypass, +# nodejs.org/en/blog/vulnerability/october-2026-security-releases), and nixos-unstable is still on +# 24.21.0 (2026-10-22). The hashes are the release's SHASUMS256.txt. Drop this file, and the +# overlay in flake.nix, once `nix flake update` brings nodejs >= 24.22.1. +{ lib, stdenv, fetchurl, patchelf }: + +let + version = "24.22.1"; + builds = { + x86_64-linux = { arch = "linux-x64"; sha256 = "6c172a9ab6718f7b801fb5a7bd486af2ee5e32758086a04b84fcce2aa77095e6"; }; + aarch64-linux = { arch = "linux-arm64"; sha256 = "dbabf7a1cbf947e6059ffad2c27b80041db97dea1e553b62afdee7f13fca336e"; }; + aarch64-darwin = { arch = "darwin-arm64"; sha256 = "654ba79de6155647e22321932b45f2a1ccb705976cc337c9b8e278beb085a628"; }; + x86_64-darwin = { arch = "darwin-x64"; sha256 = "65e450f90a6eaacd5000f611861c4ce65fadc87f813795dc4ed0c0e5f2fca2d4"; }; + }; + build = builds.${stdenv.hostPlatform.system} or (throw "nodejs-bin: no official build for ${stdenv.hostPlatform.system}"); +in +stdenv.mkDerivation { + pname = "nodejs"; + inherit version; + src = fetchurl { + url = "https://nodejs.org/dist/v${version}/node-v${version}-${build.arch}.tar.xz"; + inherit (build) sha256; + }; + nativeBuildInputs = lib.optionals stdenv.hostPlatform.isLinux [ patchelf ]; + dontConfigure = true; + dontBuild = true; + # The fixup phase must not touch the ELF again: strip and shrink-rpath both break node. + dontStrip = true; + dontPatchELF = true; + installPhase = '' + runHook preInstall + mkdir -p $out + cp -r bin include lib share $out/ + '' + lib.optionalString stdenv.hostPlatform.isLinux '' + # The rpath first, then the interpreter, in two calls: patchelf 0.19.2 makes a node that + # segfaults in the loader when it sets both in one call, or the interpreter first. + patchelf --set-rpath ${lib.makeLibraryPath [ stdenv.cc.cc.lib ]} $out/bin/node + patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out/bin/node + '' + '' + runHook postInstall + ''; + # A node that does not start fails the build here, not in a user's shell. + doInstallCheck = true; + installCheckPhase = '' + $out/bin/node --version | grep -qx "v${version}" + ''; + meta = { + description = "Node.js ${version}, the official nodejs.org build"; + homepage = "https://nodejs.org"; + license = lib.licenses.mit; + mainProgram = "node"; + platforms = builtins.attrNames builds; + }; +}