Skip to content

#6 Node.js 24 LTS from NodeSource apt, versioned in deploy/ - #7

Merged
gregoryfoster merged 13 commits into
mainfrom
6-nodesource
Sep 30, 2026
Merged

gregoryfoster merged 13 commits into
mainfrom
6-nodesource

Conversation

@gregoryfoster

@gregoryfoster gregoryfoster commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

Closes #6.

What

Node 24 LTS from NodeSource's apt repo on co-processor, for agent tooling only (using-mayfly-chat, SocratiCode's npx). The service never runs it. It is versioned here so the host can be checked against the repo and rebuilt from it.

  • deploy/apt/nodesource.sources (deb822): node_24.x, with Signed-By: naming a dedicated keyring.
  • deploy/apt/nodesource.pref: nodejs pinned to deb.nodesource.com at 600, which beats universe's nodejs 18 without allowing a downgrade.
  • deploy/nodesource.sh:
    • install (root) fetches the key and refuses it unless the fingerprint is 6F71…E0B4 (watcher#296). It then installs the keyring and both files, and runs apt-get install nodejs with NEEDRESTART_MODE=l.
    • check (no root) compares the host against deploy/apt/, the keyring's fingerprint, the source of the nodejs candidate, and the major line. It exits 3 and names each drift.
  • tests/test_nodesource.py: the files and the script agree, the fingerprint matches DEPLOYMENT.md's, and bash -n passes. EXPECTED_MAJOR makes a major bump a deliberate, test-failing edit, like the co-core pin.
  • DEPLOYMENT.md gets a Node.js section: install, check, patching, moving the major line, removal. AGENTS.md gets an Infrastructure row.

Verified on co-processor, 2026-09-30

  • Before the install, check exited 3 and named all six gaps.

  • A copy of the script with a wrong expected fingerprint refused (exit 1) and installed nothing.

  • install gave node v24.21.0 with npm and npx 11.19.0 bundled, no Ubuntu npm package, and needrestart restarted nothing. check exits 0, with the normal PATH and with a minimal systemd-style one.

  • mayfly.sh --help exits 0 (it was exit 4).

  • Maintenance lane: I stepped nodejs back to 24.20.0 and ran unattended-upgrade --dry-run three ways:

    • With the stock (security-lane) config, nodejs was not selected.
    • With site=deb.nodesource.com, it was.
    • With origin=. nodistro, it was too.

    Then I restored 24.21.0 with a targeted install. There were no apt holds and dpkg --audit was clean. Only dry-runs used unattended-upgrade; applying would also have taken the 5 pending security updates outside the owner's window.

  • Gate: ruff, ruff format, and 157 tests passed with 30 integration tests deselected.

Rough edges found

  1. NodeSource's Release file says Origin: . nodistro. That's aptly's default, generic and containing a space. Pin and select by host instead (Pin: origin deb.nodesource.com, and site=deb.nodesource.com in the lane's Origins-Pattern). The patching-hosts knob's origin <origin> follow is split on whitespace and can't hold that value, so this repo commits no knob line yet. This is going upstream as a patching-hosts issue once this PR has been reviewed.
  2. command -v node finds /bin/node, not /usr/bin/node. This user's PATH lists /bin before /usr/bin. On merged-/usr Ubuntu that's the same file, so check compares resolved paths.
  3. apt-cache policy shows the pin's 600 on the version and 500 on the source line. That's the expected display; the pin works, as the candidate shows.

Code review, round 1 (CR --fix)

There were four findings, all fixed, with one commit each (23e24d5..5a5ca50). Nothing was held back.

# Finding Commit
1 install broke its own exit-code contract. A download that isn't a key exited 2 with no message, and a 404 exited 22. Now a non-key is REFUSED ("got ", exit 1), and fetch or apt failures print a message and exit 2. I re-ran both probes against a copy of the script 23e24d5
2 The pin covered only nodejs, while the lane's site=deb.nodesource.com selects everything the site serves (nodejs and nsolid today). Everything else from that host is now pinned at 100: apt-cache policy shows nodejs 600 and nsolid 100. With nodejs stepped back again, the site= dry-run still selects nodejs and not nsolid 4c2e9f4, 5a5ca50
3 The apt calls now run under choom -n 0 --, as patching-hosts' run.md applies updates. This was latent: this session is at adj 0 70f9f51
4 DEPLOYMENT.md now says processor declares no patching posture yet. With no knob, the skill would read it as automatic, report-only b222b6e

After the last fix, the gate passed with 157 tests and 30 integration tests deselected. uv lock --locked is clean, the re-install was idempotent, and check exits 0 on the host.

Code review, round 2 (CR --fix)

There were three findings, numbered on from round 1, all fixed with one commit each (a859fcc..c3dc9e6).

# Finding Commit
5 The documented out-of-cycle fix, a bare apt-get install nodejs, did nothing on this host. apt-daily.timer is masked and APT::Periodic::Enable is 0, so the package lists are only as fresh as the last manual apt-get update. The out-of-cycle fix is now sudo bash deploy/nodesource.sh install, which refreshes the lists first a859fcc
6 Both docs restate the major line and the installed paths, but only the fingerprint was tested. A new test now requires DEPLOYMENT.md and AGENTS.md to match EXPECTED_MAJOR and the script's three paths, and the bump procedure names every file to edit. A bump done by the old procedure now fails the test (mutation-checked) f69d233
7 check said ok when an older nodejs was installed, so a pending release was invisible under the scheduled posture. It now prints pending: nodejs <installed> -> <candidate>, which is a note, not drift. I verified it with nodejs stepped back to 24.20.0, then restored c3dc9e6

After the last fix, the gate passed with 158 tests and 30 integration tests deselected. uv lock --locked is clean, check exits 0 on the host, and the branch merges cleanly with #4 (git merge-tree).

Code review, round 3 (CR --fix)

There were two minor findings, both fixed with one commit each (c5e79e0, c4c4d67). There were no bugs and nothing I'd call must-fix. NodeSource's signing key never expires (created 2016-05-23), so an expired key can't silently freeze updates.

# Finding Commit
8 check resolved node to /usr/bin/node but didn't check which package owns the file, so a stray binary there would have passed. It now reports drift unless dpkg -S names nodejs. A copy of the script expecting a different owner exits 3 c5e79e0
9 usage() printed header lines 5–7 by number, so any edit to the header would shift the help text. It now finds the Usage block by pattern, and a test checks that a bare invocation exits 2 and names both subcommands. Adding a header line broke the old version and passes the new one c4c4d67

After the last fix, the gate passed with 159 tests and 30 integration tests deselected. uv lock --locked is clean, check exits 0 on the host, and the branch merges cleanly with #4.

Not in this PR

🤖 Generated with Claude Code

gregoryfoster and others added 3 commits September 30, 2026 21:06
…ngerprint

Red until deploy/ and DEPLOYMENT.md land (5 of 5 failing at this commit).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
install refuses a key whose fingerprint isn't NodeSource's (exercised);
check compares the host against deploy/apt/, the keyring, the nodejs
candidate's source and the major line, and resolves node through
merged-/usr rather than comparing paths as text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e by site=, major bumps, removal

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gregoryfoster and others added 10 commits September 30, 2026 21:38
…1), fetch and apt failures say so (2)

Previously a non-key download exited 2 with no message (set -e on the
command substitution, gpg's stderr discarded) and a 404 exited 22.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…so the lane takes only Node

site=deb.nodesource.com selects the whole site (nodejs and nsolid today).
Verified: apt-cache policy gives nodejs 600, nsolid 100; with nodejs
stepped back to 24.20.0 the site= dry-run still selects nodejs, not nsolid.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…' run.md applies

Latent here (this session is at 0), but a -1000 session would otherwise
make dpkg unkillable beside the production service.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ure yet, not that it is scheduled

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ists; a bare apt-get install is a no-op here

apt-daily.timer is masked and APT::Periodic::Enable is 0 on this image, so
package lists are only as fresh as the last manual apt-get update.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…paths; the bump procedure names them

A bump that follows the old procedure (sources + EXPECTED_MAJOR only) now
fails test_docs_follow_the_major_line_and_the_installed_paths until
DEPLOYMENT.md and AGENTS.md follow (mutation-checked).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Verified: with nodejs stepped back to 24.20.0, check exits 0 and prints
'pending: nodejs 24.20.0-1nodesource1 -> 24.21.0-1nodesource1'; restored,
the line is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ackage

Verified: the host passes; a copy expecting another owner reports drift (3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…est holds the bare invocation

Mutation-checked: an added header line broke the old line-number usage()
and failed the new test; the pattern version prints the same help either way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Node.js 24 LTS on co-processor from NodeSource apt, versioned in deploy/ (agent tooling: mayfly, SocratiCode)

1 participant