installer: provision Node instead of refusing to run without it #1228
Open
Ghost
wants to merge 3 commits from
fix/installer-provisions-node into next
pull from: fix/installer-provisions-node
merge into: :next
:next
:ci/push-ci-comment-model
:merge/main-into-next
:fix/1323-gitea-legacy-recipe
:fix/ci-queue-wait-no-status
:fred/code-review-pinned-tool-rules
:docs/ri-050-release-evidence
:fred/guides-seat-identity-fleet-comms
:fred/credential-fail-closed-seat-slots
:feat/ri-050-qr-evaluator
:docs/ri-050-forge-docs-fastfollow
:fix/ri-050-registry-secrets
:test/ri-050-publish-gate-negative
:fix/ri-050-verify-pglite-path
:docs/ri-050-qr-probe-inventory
:feat/ri-050-web-stale-safety
:docs/ri-050-mission-bootstrap
:fix/ri-050-forge-fail-closed
:feat/ri-050-publish-gate
:fix/1292-lease-broker-activation
:fleet/continuation-record-2026-08-17
:feat/ri-050-prd-authority
:fix/ri-050-macp-fail-closed
:fix/1280-identity-first-resolution
:feat/w-f4-store
:fix/1264-fleet-unattended-first-start
:fix/1269-ci-chain-unblock
:fix/1256-fleet-runtime-preflight
:fix/1256-fleet-pane-path-node
:fix/1257-e7-draft-transition
:fix/1017-enumeration-guard-population
:fix/1240-fleet-transport-check
:fix/1017-wire-start-agent-session
:e2e-compose
:fix/1241-launch-failure-visible
:fix/1237-fleet-v2-dispatch
:fix/1236-installer-dir-modes
:fix/installer-path-and-node
:docs/1216-trunk-parameterization
:docs/ia-merge-current
:fix/869-lease-probe-timeout
:main
:feat/workspace-hygiene-tool-enforcement
:feat/1080-pr-edit
:fix/1182-fail-closed-launch
:fix/1179-required-security-di
:feat/p3-slice0-task5-chat-runtime-router-shaggy
:feat/p3-slice0-task5-chat-runtime-router
:feat/wf1-composition
:feat/p3-slice0-task4-web-catalog-selection
:feat/lease-promotion-and-harness-isolation
:ci/provision-pi-runtime
:feat/p3-slice0-task3-catalog-selection
:feat/p3-slice0-task2-harness-registry
:adopt/965-mos-ste-writing-standard
:fix/991-comment-url-scheme-normalise
:feat/wf2-bundle-migration
:feat/wf4-plugin-acquisition
:feat/wf5-refresh-safety
:fix/1145-coord-di-compiled-boot
:feat/p3-slice0-task1-harness-contracts
:docs/webui-phase-p-structure
:feat/1150-pi-goal-extension
:feat/webui-p3-chat
:fix/1146-ci-queue-purpose
:fix/1138-conditional-federation
:feat/webui-p2-data-auth
:fix/gateway-runner-image
:feat/webui-p1-vite-skeleton
:fix/break-c-hooks-and-web-image
:docs/webui-fleet-claude-bridge-plan
:fix/wizard-gateway-failure
:fix/next-node-gate
:fix/mosaic-init-rce
:greenfield/fomo-lin
:fix/1099-pipefail-wake
:fix/1099-pipefail-tests
:fix/1099-pipefail-sweep
:fix/framework-shell-portability
:fix/1043-pane-git-identity
:fix/1081-issue-close-silent-comment-failure
:fix/1090-enrollment-wallclock-tolerance
:feat/1082-tea-stale-token-diagnostic
:fix/detect-platform-silent-128-outside-repo
:feat/1050-install-state-machine-red-fixture
:fix/pr-merge-message-field
:feat/1051-mosaic-brain-installer
:feat/1045-mosaic-cred
:remediation/state
:fix/1056-upgrade-rollback-control-race
:fix/1019-ci-queue-timeout-harness
:feat/rm-02-gate-registry
:fix/rm-01-reproducible-checkout
:remediation/mission-setup
:fix/hygiene-inert-format-gate
:fix/1019-queue-guard-stdin
:feat/mos-ste-writing-standard
:fix/1007-suite-hermeticity
:feat/push-guard-null-case-verification
:mos-comms-live
:docs/heartbeat-framework-layering-ms-lead
:feat/869-c4-version-coupling
:feat/869-c2-install-ordering-guard
:feat/869-c5-doctor-activation-check
:feat/per-agent-gitea-identity
:fix/875-belongs-case-insensitive-slug
:fix/ci-queue-wait-404-branch-absent
:feat/869-c1-activation-probe
:feat/869-c3-broker-supervisor
:fix/865-tea-cli-comment-invocation
:feat/glpi-skills
:fix/860-deflake-mutator-lease-gate
:fix/850-detect-platform-port-normalization
:fix/856-worktree-deps-preflight
:fix/835-pr-review-approve-reject-comment-flag
:fix/848-truthful-evidence
:fix/812-pr-review-comment
:fix/849-recovery-runtime-fixture-race
:docs/758-ledger-m5-001-sync
:feat/834-tc-server-side-doc
:feat/833-constrained-recovery-command
:feat/827-gate0-probe
:governance/gate0-probe3-amendment
:fix/795-codex-pr-diff
:fix/795-ci-base-jq
:fix/795-ci-base-git
:feat/791-pr3-fleet-regen
:feat/791-pr2-snapshot-restore
:fix/807-glpi-206
:fix/808-agent-send-false-sender
:feat/791-upgrade-config-protection
:feat/790-mosaic-yolo-claudex-pr2
:feat/790-mosaic-yolo-claudex
:feat/758-v1-v2-migrator
:fix/766-exact-fleet-comms
:test/758-reconciler-lifecycle-gates
:docs/771-kbn101-db-role-split
:test/758-example-profile-dispositions
:feat/758-shared-role-resolution
:feat/mos-logical-identity-fencing
:feat/769-kbn100-unified-schema
:docs/753-kbn010-threat-gate
:feat/758-roster-v2-compiler
:feat/756-official-discord-plugin
:docs/758-fleet-config-management
:fix/mos-option2-qualification-format
:docs/issue-758-m0
:docs/mos-option2-qualification
:mos-comms
:feat/tess-interaction-agent
:fix/tess-docs-format
:draft/mosaic-platform-prd
:fix/installer-provider-gate-and-local-gateway-redis
:release/mosaic-cli-0.0.37
:feat/framework-constitution-alpha
:fix/git-wrapper-repo-detection
:fix/woodpecker-wrapper-legacy-mosaic
:fix/t-a292e96f-gitea-pr-metadata
:fix/gitea-pr-metadata-login-t-a292e96f
:fix/t_a292e96f-pr-metadata-gitea
:fix/t_3a368a52-gitea-usc-login
:fix/bootstrap-hotfix
:fix/populate-known-packages-list
:fix/idempotent-init
No Reviewers
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
Assignees
fargo
fred
happy
jason.woltje (Jason Woltje)
merge-gate
ops-01 (Mosaic fleet seat ops-01)
ops-02 (Mosaic fleet seat ops-02)
ops-03 (Mosaic fleet seat ops-03)
ops-ci-01 (Mosaic fleet seat ops-ci-01)
pepper
rev-code-01
rev-code-02
rev-security-01
rev-security-02
sanity
scooby (Scooby)
scrappy
shaggy
tiny
velma
vision
woodpecker
Clear assignees
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: mosaicstack/stack#1228
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
The installer provisions Node itself instead of refusing to run without it.
The installer's promise is that one command turns a bare host into a working one, but Node was carved out of that: it was checked as a prerequisite and the run died on a greenfield host with
✖ Required command not found: node. That made the documented one-command install a two-command install whose first command always failed.How
--next), the installer downloads the official nodejs.org tarball for the platform, verifies it againstSHASUMS256.txt, and unpacks it into~/.mosaic/node/<version>.--no-node-install(orMOSAIC_NO_NODE_INSTALL=1) keeps the old refuse-and-explain behaviour. Neither--checknor--uninstallprovisions anything — they do not install, so they may not install Node.MOSAIC_NODE_HOME,MOSAIC_NODE_VERSION,MOSAIC_NODE_DIST.PATH fix rides along
PATH now lands in the login profile as well as the interactive rc. Writing only
~/.bashrclooked right when you tested it interactively and was invisible to every way an agent seat actually starts —bash -lc,ssh host cmd, a systemd unit — because Debian's.bashrcreturns early when non-interactive. The three previous warn-only PATH blocks collapse into oneensure_prefix_on_path.Evidence
Verified end to end on
mosaic-sbx-dev(VM 1124), rolled back to its permanentgreenfieldsnapshot before each run. Debian 13.6, no node/npm/mosaic, near-empty$HOME.origin/nextinstaller✖ Required command not found: node~/.mosaic/node/v22.23.2; CLI 0.0.50-next.2413 + gateway 0.0.7-next.2413 installedbash -lc, nothing sourced by handnode --version→ v22.23.2,mosaic --version→ 0.0.50-next.2413--no-node-install--checkNODE_HOMEuntouched; rc=0 on a healthy hostTests
New
tools/install-node-provisioning.test.shpins all of the above offline —MOSAIC_NODE_DISTpoints at a local directory laid out likenodejs.org/dist, served overfile://, so the download, the checksum gate and the unpack are the real code paths with no network. Nine cases, wired intopnpm test:installer.Red-first: the suite fails on the first case against unpatched
origin/next.The next-lane test's Node 20 case moves to
--no-node-install. The>= 22gate must still fire before anything is installed, but refusing is no longer the outcome when provisioning is allowed — that path is covered by the new suite.Not fixed here
During the sandbox runs the framework install step emits
[mosaic-link] ERROR: 'mosaic' CLI not found on PATH — cannot confirm lease-enforcement. It runs before the CLI is installed. Pre-existing ordering issue, non-fatal, out of scope for this PR.Second commit added:
installer: stop newest_matching_file from dying on SIGPIPE.Same file, and it is the thing standing between the 0.0.50 integration branch and a green test run, so it belongs in this lane rather than in a competing PR on
tools/install.sh.newest_matching_file()pipedls -1tintohead -1. Underset -o pipefailhead closes the pipe after one line, ls dies on SIGPIPE, and the function returns 141 having printed nothing. All four callers assign it at top level underset -e, so that 141 aborts the run. Two of them are the "find the newest.mosaic-bak-*" lookup a restore depends on.Not theoretical — measured:
origin/nextIt takes roughly 1600 names to fill the pipe buffer, which is why it has sat unnoticed: with two or three files the old code is correct.
It also clears the one remaining violation
scripts/pipefail-early-exit.test.mjsreports againsttools/install.sh. That test lives onmain, not onnext, so it starts failing the momentmainmerges intonext— which is exactly what the 0.0.50 integration does. Verified by applying this commit to the integration branch:pipefail-early-exit.test.mjsgoes 1 failed → 7 passed, 0 failed, and it was that branch's only test failure.New
tools/install-newest-matching-file.test.shpins it, including the large-population case that is the whole point. Red onorigin/next(rc=141), green here. Wired intopnpm test:installeralongside the other two.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.