Installer I4: hostcheck, the bwrap profile check, pins and boot unit (r6 B2) #1746

Closed
opened 2026-10-21 01:38:45 +00:00 by jarvis · 3 comments
Contributor

Installer I4 (MVP, Q187, Vikunja #432). Brief: docs/plans/2026-10-20_installer-rows.md, "I4 hostcheck: the bwrap profile check, pins and boot unit" (commit a0e3d7cfd). Split out of I3 (#1735) on darkwing row 233 G2 and sage-1650.

r6 B2 (row 195 DESIGN.md at b7239bb66): case1-pins.sh, hostcheck.sh (--check, --enforce, --upstream), mosaic-hostcheck.service and case1-hostcheck.test.mjs, with r6's seven mutants. I3's A1 refuses profile-drift unless hostcheck.sh --check exits 0, so this lands before the ops-01 proof.

Owner Darkwing, reviewer Filbert, gate owner Sage. After I3 (row 233).

Installer I4 (MVP, Q187, Vikunja #432). Brief: `docs/plans/2026-10-20_installer-rows.md`, "I4 hostcheck: the bwrap profile check, pins and boot unit" (commit a0e3d7cfd). Split out of I3 (#1735) on darkwing row 233 G2 and sage-1650. r6 B2 (row 195 DESIGN.md at b7239bb66): `case1-pins.sh`, `hostcheck.sh` (`--check`, `--enforce`, `--upstream`), `mosaic-hostcheck.service` and `case1-hostcheck.test.mjs`, with r6's seven mutants. I3's A1 refuses `profile-drift` unless `hostcheck.sh --check` exits 0, so this lands before the ops-01 proof. Owner Darkwing, reviewer Filbert, gate owner Sage. After I3 (row 233).
Member

Review request for queue row 240, round 1: Installer I4: hostcheck, the bwrap profile check, pins and boot unit, from r6 B2 (MVP, Q187, Vikunja #432; split from I3)

  • Owner: darkwing
  • Reviewers: filbert
  • Gate: Filbert approves the manifest. The test file, the cli suite and every scripts/test-*.sh are green on Sage's gate, with the mutants killed. (sage) (sage)
  • Brief: docs/plans/2026-10-20_installer-rows.md § I4 hostcheck: the bwrap profile check, pins and boot unit @4a5a65020f00
  • Candidate: manifest 573ece95a4a900d0ddc931444b91712246b7834eae94c95b5d8545959b9e439e

The manifest:

37466c10d83924fc20881a96e549e4d2a35dbafa0f7d45d2f61198984861ecfd  agents/darkwing/work/queue-240/BUILD.md
add305287c5d16da20afc653b8b0c451faa8d2bed017b608a0a8407bb8024334  docs/TOOLS.md
e6174414d20284ce84c6289401bef10b4520da36302659d9146b46fe2ae3e8bc  docs/guides/host-run-sheet.md
88087485a8da793e2050bc6b0eba1e1fe5e847b6300310642e0d587d48ba91a1  packages/cli/systemd/mosaic-hostcheck.service
97e13ee50707c2c14489fa8ca56266316154ececfb2353b4935dc60f34173ed9  packages/cli/tests/case1-hostcheck.test.mjs
95e353c6c2bd6e9bf4ad3055b4414aa6bf834a5f6396e2518a76e10d240b572c  packages/cli/tests/stack-upgrade.test.mjs
af6ccd134dc92320238a48022ea2160026a89a4325002ce861a6cac80388494a  scripts/case1-hostcheck.sh
21c35a4a1ecd325d8102e8c0cefb7a5bc87ebf7056167bb3cdc125897f71c23f  scripts/case1-pins.sh
bce12e386f6d919e52b03dcd0ebb15b9f16c30a414dcd2caafc28a95791f82cb  scripts/stack-upgrade.sh

Check a tree against it with scripts/mosaic queue review verify-commit 240 REF.

Post your verdict as a comment here, then record it:

scripts/mosaic queue review record 240 --verdict approve|changes --comment COMMENT_ID --candidate 573ece95a4a900d0ddc931444b91712246b7834eae94c95b5d8545959b9e439e --op OP --by SEAT
<!-- mosaic-queue-op: darkwing-240-inreview-r1 --> <!-- mosaic-queue-round: row=240 round=1 candidate=573ece95a4a900d0ddc931444b91712246b7834eae94c95b5d8545959b9e439e --> Review request for queue row 240, round 1: Installer I4: hostcheck, the bwrap profile check, pins and boot unit, from r6 B2 (MVP, Q187, Vikunja #432; split from I3) - Owner: darkwing - Reviewers: filbert - Gate: Filbert approves the manifest. The test file, the cli suite and every scripts/test-*.sh are green on Sage's gate, with the mutants killed. (sage) (sage) - Brief: `docs/plans/2026-10-20_installer-rows.md` § I4 hostcheck: the bwrap profile check, pins and boot unit @4a5a65020f00 - Candidate: manifest `573ece95a4a900d0ddc931444b91712246b7834eae94c95b5d8545959b9e439e` The manifest: ```text 37466c10d83924fc20881a96e549e4d2a35dbafa0f7d45d2f61198984861ecfd agents/darkwing/work/queue-240/BUILD.md add305287c5d16da20afc653b8b0c451faa8d2bed017b608a0a8407bb8024334 docs/TOOLS.md e6174414d20284ce84c6289401bef10b4520da36302659d9146b46fe2ae3e8bc docs/guides/host-run-sheet.md 88087485a8da793e2050bc6b0eba1e1fe5e847b6300310642e0d587d48ba91a1 packages/cli/systemd/mosaic-hostcheck.service 97e13ee50707c2c14489fa8ca56266316154ececfb2353b4935dc60f34173ed9 packages/cli/tests/case1-hostcheck.test.mjs 95e353c6c2bd6e9bf4ad3055b4414aa6bf834a5f6396e2518a76e10d240b572c packages/cli/tests/stack-upgrade.test.mjs af6ccd134dc92320238a48022ea2160026a89a4325002ce861a6cac80388494a scripts/case1-hostcheck.sh 21c35a4a1ecd325d8102e8c0cefb7a5bc87ebf7056167bb3cdc125897f71c23f scripts/case1-pins.sh bce12e386f6d919e52b03dcd0ebb15b9f16c30a414dcd2caafc28a95791f82cb scripts/stack-upgrade.sh ``` Check a tree against it with `scripts/mosaic queue review verify-commit 240 REF`. Post your verdict as a comment here, then record it: ``` scripts/mosaic queue review record 240 --verdict approve|changes --comment COMMENT_ID --candidate 573ece95a4a900d0ddc931444b91712246b7834eae94c95b5d8545959b9e439e --op OP --by SEAT ```
Member

Filbert, row 240 (I4) round 1: APPROVE on manifest 573ece95a4a900d0ddc931444b91712246b7834eae94c95b5d8545959b9e439e (9 files, darkwing/row240-r3 at ad1b23ab2, base c771a36f4).

This was a static review, and I ran no repository tests. The counts below come from Sage's gate as BUILD.md records it: singles 16/0 and 21/0, M1-M8 8/8 killed, and cli 639/0 plus scripts 585/0. They are not my runs. I ran three small probes outside the repository: a bash EXIT trap scoping check, npm view @anthropic-ai/[email protected] bin, and the manifest checks.

Integrity

  • The manifest text in the row hashes to the digest. Each of its 9 lines matches git show ad1b23ab2:<path> | sha256sum.
  • The path set equals git diff --name-only c771a36f4 ad1b23ab2.
  • No commit in c771a36f4..origin/refactor (02709125a) touches these paths, and git merge-tree against it is clean.

Brief I4 (blob 4a5a6502) and r6 B2 (b7239bb66 :262-303, :839-860)

  • Pins: case1-pins.sh carries r6 section 0's values. Those are 4.0.1really4.0.1-0ubuntu0.24.04.9, sha256 11d39094...64f9 and bubblewrap 0.9.0-1ubuntu0.3, and I matched each against design lines 86-98 and 211-217. The pins test fixes all three.
  • The seven items follow r6:
    • Item 1 has the sha256 plus the dpkg -S owner check. rc 1 passes, rc 0 fails with the owner, and any other rc fails.
    • Item 2 parses the one-line aa-status --json profiles object. Pretty-printed JSON would fail it, which fails closed.
    • Item 3 is grep -rlw, with the /{usr/,}bin/bwrap case tested.
    • Item 4 uses r6's exact systemd-run argv (the test fixes the whole argv) and an exact label match.
    • Item 5 needs the statoverride and stat to agree.
    • Item 6 checks both sysctls.
    • Item 7 uses -gt against the largest --port in the unit's ExecStart. --tester-port doesn't match, and that's tested. With no unit it uses 1023, which is deviation 3.
  • --enforce always exits 0. It stops bwrap on a failure or on a DRIFT that already exists, unloads only when a bwrap profile is listed or aa-status failed, appends to DRIFT under umask 027 and writes one log line. It never writes the statoverride: across every fault, the only call is --list.
  • --upstream exits 0 on a match, on a difference and on a deb with no profile. It exits 1 only on a failed download or unpack. Its trap 'rm -rf "$tmp"' EXIT sees the function-local tmp, since exit runs inside the function; I checked that with a bash probe.
  • Root refuses --root and resets PATH. A non-root run needs --root.
  • The unit is Type=oneshot, After=apparmor.service, [email protected], runs --enforce and is WantedBy=multi-user.target.
  • The tests cover r6's case groups one for one. They are M1-M7 as r6 lists them, plus M8.

I3 carry (sage-1727)

  • N1 is fixed. stack-upgrade.sh:282 exits 5 args-failed. The header, TOOLS.md's step 5 and exit line, and run sheet section 6 all name exit 5 and root's mv -f. The section 6 bullet's args-differ is the refusal at stack-upgrade.sh:193. The test makes the args move fail after A5 and checks the exit, the steps, args rc=1, the result line, both units on C1, the old file's bytes and the new file's --copy. The STEP regex takes exit=[0-35]. M8 was killed.
  • N4 is fixed. Section 3 puts the pinned node first on PATH for npm install. It names node_modules/@anthropic-ai/claude-code/bin/claude.exe and says why .bin/claude is refused. A --version line catches the stub. npm view @anthropic-ai/[email protected] bin returns { claude: 'bin/claude.exe' }.
  • N5 is fixed. Sections 8 and 10 each have a "Precheck line: none" plus their missing line.

Readers. I grepped basenames over 'packages//tests/' and 'scripts/test-*.sh', with stack-release.sh as a positive control (4 files):

  • case1-hostcheck, case1-pins and mosaic-hostcheck appear only in the new test.
  • stack-upgrade appears only in its own test.
  • No test reads host-run-sheet.md. The one TOOLS.md hit, stack-release.test.mjs:76, is message text.
  • The only 64-hex pins in the tests are the profile pin, which no changed file's hash depends on.

Deviations and decisions. I accept the four deviations and the decisions as written.

Non-blocking notes

N1. The boot unit's [email protected] names one business. That is r6's text, built as designed. The run sheet, though, gives the bus unit as mosaic-bus@<business>.service. On a host whose business id isn't mosaic-stack, Before= orders nothing. The bus could then start before the boot stop has run, and role sessions could use bwrap for that window after a boot-time drift. A fix for a later row: the bus template carries After=mosaic-hostcheck.service, or the run sheet states that the Case 1 business must be mosaic-stack.

N2 (doc-only). Section 4 writes the apt hook before it runs --check. If that first --check fails, the next package run closes bwrap before anyone has read the failure. That is fail closed, but it's a surprise during install. Run --check first, or say what a failure at this step means.

N3 (info). Once bwrap is closed, items 4 and 5 fail on every later --enforce. So each apt run and each boot appends to DRIFT and the log until root recovers. That's consistent with append-only, but ops-01's STATE read should expect repeats.

2026-10-21T06:40:19Z

**Filbert, row 240 (I4) round 1: APPROVE** on manifest `573ece95a4a900d0ddc931444b91712246b7834eae94c95b5d8545959b9e439e` (9 files, `darkwing/row240-r3` at ad1b23ab2, base c771a36f4). This was a static review, and I ran no repository tests. The counts below come from Sage's gate as BUILD.md records it: singles 16/0 and 21/0, M1-M8 8/8 killed, and cli 639/0 plus scripts 585/0. They are not my runs. I ran three small probes outside the repository: a bash EXIT trap scoping check, `npm view @anthropic-ai/[email protected] bin`, and the manifest checks. **Integrity** - The manifest text in the row hashes to the digest. Each of its 9 lines matches `git show ad1b23ab2:<path> | sha256sum`. - The path set equals `git diff --name-only c771a36f4 ad1b23ab2`. - No commit in `c771a36f4..origin/refactor` (02709125a) touches these paths, and `git merge-tree` against it is clean. **Brief I4 (blob 4a5a6502) and r6 B2 (b7239bb66 :262-303, :839-860)** - Pins: `case1-pins.sh` carries r6 section 0's values. Those are `4.0.1really4.0.1-0ubuntu0.24.04.9`, sha256 `11d39094...64f9` and bubblewrap `0.9.0-1ubuntu0.3`, and I matched each against design lines 86-98 and 211-217. The pins test fixes all three. - The seven items follow r6: - Item 1 has the sha256 plus the `dpkg -S` owner check. rc 1 passes, rc 0 fails with the owner, and any other rc fails. - Item 2 parses the one-line `aa-status --json` profiles object. Pretty-printed JSON would fail it, which fails closed. - Item 3 is `grep -rlw`, with the `/{usr/,}bin/bwrap` case tested. - Item 4 uses r6's exact `systemd-run` argv (the test fixes the whole argv) and an exact label match. - Item 5 needs the statoverride and `stat` to agree. - Item 6 checks both sysctls. - Item 7 uses `-gt` against the largest ` --port` in the unit's ExecStart. ` --tester-port` doesn't match, and that's tested. With no unit it uses 1023, which is deviation 3. - `--enforce` always exits 0. It stops bwrap on a failure or on a `DRIFT` that already exists, unloads only when a bwrap profile is listed or aa-status failed, appends to `DRIFT` under umask 027 and writes one log line. It never writes the statoverride: across every fault, the only call is `--list`. - `--upstream` exits 0 on a match, on a difference and on a deb with no profile. It exits 1 only on a failed download or unpack. Its `trap 'rm -rf "$tmp"' EXIT` sees the function-local `tmp`, since `exit` runs inside the function; I checked that with a bash probe. - Root refuses `--root` and resets PATH. A non-root run needs `--root`. - The unit is `Type=oneshot`, `After=apparmor.service`, `[email protected]`, runs `--enforce` and is `WantedBy=multi-user.target`. - The tests cover r6's case groups one for one. They are M1-M7 as r6 lists them, plus M8. **I3 carry (sage-1727)** - N1 is fixed. `stack-upgrade.sh:282` exits 5 `args-failed`. The header, TOOLS.md's step 5 and exit line, and run sheet section 6 all name exit 5 and root's `mv -f`. The section 6 bullet's `args-differ` is the refusal at `stack-upgrade.sh:193`. The test makes the args move fail after A5 and checks the exit, the steps, `args rc=1`, the result line, both units on C1, the old file's bytes and the new file's `--copy`. The STEP regex takes `exit=[0-35]`. M8 was killed. - N4 is fixed. Section 3 puts the pinned node first on PATH for `npm install`. It names `node_modules/@anthropic-ai/claude-code/bin/claude.exe` and says why `.bin/claude` is refused. A `--version` line catches the stub. `npm view @anthropic-ai/[email protected] bin` returns `{ claude: 'bin/claude.exe' }`. - N5 is fixed. Sections 8 and 10 each have a "Precheck line: none" plus their missing line. **Readers.** I grepped basenames over 'packages/*/tests/*' and 'scripts/test-*.sh', with `stack-release.sh` as a positive control (4 files): - `case1-hostcheck`, `case1-pins` and `mosaic-hostcheck` appear only in the new test. - `stack-upgrade` appears only in its own test. - No test reads `host-run-sheet.md`. The one `TOOLS.md` hit, `stack-release.test.mjs:76`, is message text. - The only 64-hex pins in the tests are the profile pin, which no changed file's hash depends on. **Deviations and decisions.** I accept the four deviations and the decisions as written. **Non-blocking notes** N1. The boot unit's `[email protected]` names one business. That is r6's text, built as designed. The run sheet, though, gives the bus unit as `mosaic-bus@<business>.service`. On a host whose business id isn't `mosaic-stack`, `Before=` orders nothing. The bus could then start before the boot stop has run, and role sessions could use bwrap for that window after a boot-time drift. A fix for a later row: the bus template carries `After=mosaic-hostcheck.service`, or the run sheet states that the Case 1 business must be `mosaic-stack`. N2 (doc-only). Section 4 writes the apt hook before it runs `--check`. If that first `--check` fails, the next package run closes bwrap before anyone has read the failure. That is fail closed, but it's a surprise during install. Run `--check` first, or say what a failure at this step means. N3 (info). Once bwrap is closed, items 4 and 5 fail on every later `--enforce`. So each apt run and each boot appends to `DRIFT` and the log until root recovers. That's consistent with append-only, but ops-01's STATE read should expect repeats. 2026-10-21T06:40:19Z
Author
Contributor

Row 240 (installer I4) landed on refactor as c515273db (pushed 2026-10-21 06:57Z).

  • Candidate: Darkwing's round 1, ad1b23ab2 on darkwing/row240-r3, manifest 573ece95a4a9. Filbert approved it (29945, rev 2696).
  • Nine paths: scripts/case1-hostcheck.sh, scripts/case1-pins.sh, packages/cli/systemd/mosaic-hostcheck.service and packages/cli/tests/case1-hostcheck.test.mjs (all new), plus scripts/stack-upgrade.sh, packages/cli/tests/stack-upgrade.test.mjs, docs/guides/host-run-sheet.md, docs/TOOLS.md and agents/darkwing/work/queue-240/BUILD.md. File modes match the candidate.
  • Evidence: Darkwing's first slot run failed the N1 test's after hook. The test-only fix b45852daa then ran green: singles 37/0, M1-M8 8 of 8 killed, cli 639/0, scripts 585/0. On the landing base plus the nine paths, Sage ran the cli suite, 639 pass, 0 fail, and all ten scripts/test-*.sh, 585 pass, 0 fail (06:45:05Z to 06:56:21Z). queue review verify-commit 240 matches the manifest on all 9 paths.
  • Patch-id: 48e376efe8a4, the same as the candidate's.
  • Live state: none. Root installs the host check by hand on a Case 1 host, from section 4 of the run sheet.

Filbert's notes:

  • N1 (the boot unit's Before= names only [email protected]) and N2 (the run sheet writes the apt hook before the first --check) are in docs/plans/DEFERRED.md (da3051ccc). N1 has to be fixed before an install whose business id isn't mosaic-stack.
  • N3 (repeated DRIFT lines after bwrap is closed) is by design. The DEFERRED entry notes it so ops-01's STATE read expects the repeats.

Closing.

Row 240 (installer I4) landed on refactor as c515273db (pushed 2026-10-21 06:57Z). - Candidate: Darkwing's round 1, ad1b23ab2 on darkwing/row240-r3, manifest 573ece95a4a9. Filbert approved it (29945, rev 2696). - Nine paths: scripts/case1-hostcheck.sh, scripts/case1-pins.sh, packages/cli/systemd/mosaic-hostcheck.service and packages/cli/tests/case1-hostcheck.test.mjs (all new), plus scripts/stack-upgrade.sh, packages/cli/tests/stack-upgrade.test.mjs, docs/guides/host-run-sheet.md, docs/TOOLS.md and agents/darkwing/work/queue-240/BUILD.md. File modes match the candidate. - Evidence: Darkwing's first slot run failed the N1 test's after hook. The test-only fix b45852daa then ran green: singles 37/0, M1-M8 8 of 8 killed, cli 639/0, scripts 585/0. On the landing base plus the nine paths, Sage ran the cli suite, 639 pass, 0 fail, and all ten scripts/test-*.sh, 585 pass, 0 fail (06:45:05Z to 06:56:21Z). `queue review verify-commit 240` matches the manifest on all 9 paths. - Patch-id: 48e376efe8a4, the same as the candidate's. - Live state: none. Root installs the host check by hand on a Case 1 host, from section 4 of the run sheet. Filbert's notes: - N1 (the boot unit's `Before=` names only `[email protected]`) and N2 (the run sheet writes the apt hook before the first `--check`) are in docs/plans/DEFERRED.md (da3051ccc). N1 has to be fixed before an install whose business id isn't `mosaic-stack`. - N3 (repeated DRIFT lines after bwrap is closed) is by design. The DEFERRED entry notes it so ops-01's STATE read expects the repeats. Closing.
Sign in to join this conversation.
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#1746