plans: Case 2 row briefs from Gosalyn's eac92d956 (design r11, approved webby-0038: C2-13 split into C2-13a unit render and host precheck and C2-13b install script and library precheck, C2-04 owner Herb, Console unit without [Install] per mos-1097)
This commit is contained in:
@@ -18,9 +18,9 @@ packages adapters roles scripts` touches only `scripts/stack-release.sh` and its
|
||||
is in either.
|
||||
|
||||
Order (design 8, "Parallel waves"):
|
||||
1. Start now: C2-01, C2-08, C2-11a.
|
||||
1. Start now: C2-01, C2-08, C2-11a, C2-13a.
|
||||
2. On C2-01's candidate: C2-04, C2-05a, C2-06, C2-12. On C2-08's: C2-09a, C2-10a, C2-20.
|
||||
3. Then C2-03a and C2-07. Then C2-05b, C2-10b and C2-13.
|
||||
3. Then C2-03a and C2-07. Then C2-05b, C2-10b and C2-13b.
|
||||
4. Last: C2-14.
|
||||
|
||||
A row whose parent hasn't landed builds on the parent's candidate and rebases onto its landing (Q177).
|
||||
@@ -34,7 +34,7 @@ Rules every row keeps:
|
||||
text wherever a test checks that output holds none.
|
||||
- No credential value in any output, test, log or message (CONSTITUTION gate 13). Tests use a fixture
|
||||
token file with a made-up value.
|
||||
- No live stack change. Nothing here re-pins, restarts or activates anything. C2-13's run on the host
|
||||
- No live stack change. Nothing here re-pins, restarts or activates anything. C2-13a and C2-13b's runs on the host
|
||||
needs Jason's go (design 10).
|
||||
- Before in-review, grep `packages/*/tests` and `scripts/test-*.sh` for each changed path and for any
|
||||
64-hex pin of it, and run every changed or touched test file on its own. Suites need Sage's slot.
|
||||
@@ -172,7 +172,7 @@ Tests, all named in the design 8 C2-08 row:
|
||||
### Out of scope
|
||||
|
||||
Thread creation per instance and the launcher (C2-09a), the lookup tools (C2-05b), the cited-reply guard
|
||||
(C2-06). Checking the host's claude for `--system-prompt-file` is C2-13's precheck. If the C2-20 dry run
|
||||
(C2-06). Checking the host's claude for `--system-prompt-file` is C2-13a's precheck. If the C2-20 dry run
|
||||
finds heading lines in a real persona, the fence rule changes in a follow-up to this row, reviewed,
|
||||
before the import (design 9.1).
|
||||
|
||||
@@ -230,7 +230,7 @@ from changing `projects`, and nothing creates a mirror.
|
||||
|
||||
### Owner and reviewer
|
||||
|
||||
- Owner: Rocko, gpt-6.1-sol.
|
||||
- Owner: Herb, gpt-6.1-sol. Herb replaces Rocko, who holds five other rows (sage-1482).
|
||||
- Reviewer: Filbert.
|
||||
- After: C2-01.
|
||||
|
||||
@@ -706,27 +706,236 @@ Dewey approves the manifest. The webui suite is green on Sage's gate, along with
|
||||
|
||||
---
|
||||
|
||||
## C2-13 install script and precheck for the host
|
||||
## C2-13a unit render and host precheck
|
||||
|
||||
### Problem
|
||||
|
||||
The hub runs on 10.1.1.54 as `mosaic` under `/srv/mosaic`, as `mosaic-stack.service` with
|
||||
`ProtectHome` (design 9, Q181). Nothing installs a library business there, or checks the host before it
|
||||
starts.
|
||||
The hub runs on 10.1.1.54 as `mosaic` under `/srv/mosaic`, as two system units,
|
||||
`mosaic-bus@<business>.service` and `mosaic-webui.service` (design 9 and 10 step 2c, r11). Nothing
|
||||
renders those units for a system install, and nothing checks the host before the start. Row 195 needs
|
||||
the same render and precheck for Case 1 on 10.1.1.53, so this part comes first and has no library
|
||||
dependency (sage-1480, Q177).
|
||||
|
||||
### Owner and reviewer
|
||||
|
||||
- Owner: Gosalyn, Opus 5.5. The scripts run on a host only under Jason's go, by him or his delegate
|
||||
(design 10).
|
||||
- Reviewer: Webby.
|
||||
- After: nothing. Row 195 chains on this row's candidate.
|
||||
|
||||
### Files owned
|
||||
|
||||
`scripts/case2-unit.sh` and `scripts/case2-precheck.sh` (new), `packages/cli/tests/case2-unit.test.mjs`
|
||||
(new), and one line of `packages/cli/README.md`: at `:713`, "nothing in the repository creates or reads
|
||||
it" changes to say that nothing creates it, that only the Case 2 precheck reads it, and that the
|
||||
precheck prints only variable names, never values (webby-0034 N2, webby-0035).
|
||||
|
||||
### What ships: `case2-unit.sh`
|
||||
|
||||
`case2-unit.sh` is the 2c step. Root runs it from a root-owned checkout of the reviewed commit outside
|
||||
`/srv/mosaic`, never from the release, because `mosaic` can write the release.
|
||||
|
||||
Inputs. `--profile factory|library` (default `library`), `--user`, `--home`, `--business`, `--copy ID`,
|
||||
`--node PATH`, and the Console's serve flags after `--`. Row 195 calls it with those names.
|
||||
- `--node` must be an absolute path to a root-owned regular file outside `<home>`.
|
||||
- The copy id must be exactly 40 lowercase hex characters naming a directory that holds
|
||||
`scripts/mosaic`, directly under `<home>/.local/share/mosaic-stack/copies`. That is the rule
|
||||
`copy_root` uses (`scripts/stack-copy.sh:6`, `:20`). Anything else refuses before the render.
|
||||
- The serve flags. The script copies the checks from `serve_flags` (`scripts/webui-service.sh:146-207`)
|
||||
into its own function, with its own tests. It doesn't source or change that script, because its
|
||||
proof-file check compares the owner to `id -u` (`:201`), which is root here, and its render finds
|
||||
node with `command -v` (`:237`), not `--node` (webby-0036 N3). The library profile takes exactly
|
||||
these flags, each once, and refuses any other:
|
||||
- `--port N`, with N in 1..1023 (design 9.3).
|
||||
- `--business ID`, equal to `--business`.
|
||||
- `--public-host NAME`, `--auth-header HEADER` and `--allow-user ID`, checked as
|
||||
`webui-service.sh` checks them. Their values come from design 10 step 5.
|
||||
- `--send`, because C2-10b's chat needs it.
|
||||
- `--proof-header NAME` and `--proof-file PATH`. The proof is required, not optional (design 9.3).
|
||||
The file must be a regular file, not a symlink, owned by `<user>`'s uid from `getent passwd`, mode
|
||||
0600 or 0400, under `<home>/.config/mosaic-dev/secrets/`. That keeps it out of the data root, where
|
||||
a session's run directory is. The script stats it and never opens it.
|
||||
- It refuses `--tester-port`. The tester listener takes instance, route, name and chat writes from
|
||||
loopback with no sign-in (`packages/webui/src/serve.mjs:472`, `:532-542`).
|
||||
- It refuses `--checkout`. Her host has no canonical checkout, and the queue store refuses a read
|
||||
from the copy, so the queue panel isn't part of Case 2 (webby-0036 N4).
|
||||
- It refuses `--board`. Case 2 runs no control board, and design 9.3 says why the default stays.
|
||||
The factory profile takes the same set plus an optional `--tester-port N` in 1024..65535, never equal
|
||||
to `--port`, because Case 1's acceptance uses the tester. Row 195 names any other difference in its
|
||||
own brief.
|
||||
|
||||
The render. It renders two system units from the checkout's existing templates and changes neither:
|
||||
`[email protected]` from `packages/cli/systemd/mosaic-bus.service.in`, enabled as
|
||||
`mosaic-bus@<business>.service`, and `mosaic-webui.service` from
|
||||
`packages/webui/systemd/mosaic-webui.service.in`. Every token has one value (webby-0036 B2):
|
||||
- `@REPO@` is the copy directory.
|
||||
- `@NODE@` is `--node`.
|
||||
- `@PATH@` is the directory of `--node` first, then whichever of `/usr/local/bin`, `/usr/bin` and `/bin`
|
||||
it isn't, in that order. The bus's `ExecStart=` is `scripts/mosaic`, which runs `exec node` from
|
||||
PATH (`scripts/mosaic:22-40`), so this line picks the bus's node. It differs from
|
||||
`scripts/webui-service.sh:246-248` in one case on purpose. That script leaves the list alone when the
|
||||
node's directory is already in it, so with `--node /usr/bin/node` a node in `/usr/local/bin` would
|
||||
come first and the bus would run it.
|
||||
- `@FLAGS@` is the checked serve flags, in the order given.
|
||||
- `@PM_FLAGS@` and `@CLAUDE_ENV@` render empty.
|
||||
- `%h` becomes the literal `--home`, because in a system unit `%h` is root's home.
|
||||
- After the render it refuses any `@[A-Z_]+@` or `%h` left in either unit.
|
||||
|
||||
Lines it adds or replaces. At the end of `[Service]` in both units it adds `User=<user>`,
|
||||
`Group=<user's primary group>` and these four lines, in this order (webby-0036 B3):
|
||||
```
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=<home>
|
||||
ProtectHome=yes
|
||||
PrivateTmp=yes
|
||||
```
|
||||
The templates' own `NoNewPrivileges=yes` stays. The Console unit also gets
|
||||
`AmbientCapabilities=CAP_NET_BIND_SERVICE` and `CapabilityBoundingSet=CAP_NET_BIND_SERVICE`, so it can
|
||||
bind its port below 1024 (design 9.3). The bus unit gets no capability line. It adds nothing else. No
|
||||
line restricts namespaces or system calls. A session's bwrap needs a user, PID and IPC namespace
|
||||
(`packages/seat/src/sandbox.mjs:67`) and a mount namespace, and `RestrictNamespaces=`,
|
||||
`PrivateUsers=` or `SystemCallFilter=` can each take one away, so it refuses a template or render that
|
||||
holds any of them.
|
||||
- `[Install]`. In the bus unit, `WantedBy=default.target` is replaced by `WantedBy=multi-user.target`,
|
||||
not followed by a second line (webby-0036 N1). The Console unit renders with no `[Install]` section
|
||||
(webby-0036 B1, mos-1097). The script enables only the bus unit. Jason starts the Console at design
|
||||
10 step 9 and after each boot.
|
||||
- No `After=` or `Wants=`. The Console never starts at boot, so there is no boot order to set, and
|
||||
serve calls the bus per request, so it starts without the bus (webby-0036 N2). The step 9 order is
|
||||
manual: the bus, then the Console. Stop in reverse.
|
||||
|
||||
Checks. It refuses unless `User=`, `Group=`, `ExecStart=`, the bus unit's `EnvironmentFile=`, the
|
||||
hardening lines and the Console's two capability lines match fixed values. `EnvironmentFile=` is the
|
||||
line in `packages/cli/systemd/mosaic-bus.service.in:24`, with the literal home. The Console unit has
|
||||
none, and it refuses one. It also refuses:
|
||||
- any `PermissionsStartOnly=`, and any `Exec*=` value whose leading run of prefix characters (`@`, `-`,
|
||||
`:`, `+`, `!`) holds a `+` or `!`. systemd takes those prefixes in any order, so `-+/srv/mosaic/x`
|
||||
runs as root even with `User=mosaic`. The named-line check doesn't read these lines (webby-0026 N1,
|
||||
webby-0027, defence in depth).
|
||||
- on a re-install, an installed pair whose two units name different copy ids (webby-0036 N5). The bus
|
||||
accepts only its own `human-cli.mjs` path, so a split pair breaks the human proof
|
||||
(`scripts/webui-service.sh:266-273`).
|
||||
- on a re-install, an installed unit that differs from the render in anything but the copy id. So the
|
||||
node path and serve flags must equal the installed ones. The copy id is the one value that may
|
||||
change, so a re-pin or a rollback to another copy re-renders both units together (row 195).
|
||||
|
||||
It writes both units under `/etc/systemd/system/` as `root:root` 0644. It never uses `systemctl link`,
|
||||
and it refuses a symlink at either unit path. It opens no file under `<home>`. It only stats the copy
|
||||
directory, its `scripts/mosaic` and the proof file.
|
||||
|
||||
### What ships: `case2-precheck.sh`
|
||||
|
||||
It runs as `<user>` and takes `--profile factory|library`, default `library`. C2-13a ships the host
|
||||
checks below. C2-13b adds the library checks to the same file. It refuses unless all of these hold:
|
||||
- The config validates.
|
||||
- `sudo -n true` fails as `<user>`, and `id -G` prints exactly one entry, its primary group. A system
|
||||
user always has one, so the check is for supplementary groups.
|
||||
- `bus.tester`: `library` refuses it on. `factory` requires it on, because Case 1's acceptance uses the
|
||||
tester. `factory` refuses a business file that has a `kind: "library"` project, with
|
||||
`profile-library-business`, so Case 2 can't reach a tester-on check through a wrong flag.
|
||||
- The run root is 0700.
|
||||
- `XDG_DATA_HOME` is unset or is `<home>/.local/share`. `copy_root` reads the copies dir from it
|
||||
(`scripts/stack-copy.sh:6`), and the unit fixes `<home>/.local/share`, so any other value would put
|
||||
the copy where the unit refuses it (webby-0032 N2).
|
||||
- `node --version` is 24 or later, because every package's `engines` field says `>=24` (row 195: .53
|
||||
has v22.22.2).
|
||||
- `bwrap --unshare-all --ro-bind / / true` exits 0 as `<user>`. Without it no session starts. Row 195
|
||||
found no bwrap on .53, and `kernel.apparmor_restrict_unprivileged_userns=1`, and .54 may be the same.
|
||||
On a refusal, the precheck prints the sysctl's value and whether `bwrap` is on PATH. This runs in
|
||||
`<user>`'s shell, outside the unit's hardening, so it can't show that the unit lets bwrap run. Design
|
||||
10 step 9 checks that.
|
||||
- `net.ipv4.ip_unprivileged_port_start` is above the Console's `--port`, read from the installed
|
||||
Console unit. It refuses when the floor is at or below the port, because a lowered floor lets any
|
||||
`mosaic` process bind the port, a session included, and makes the Console's capability pointless
|
||||
(design 9.3, mos-1100).
|
||||
- When some instance's harness is claude-code, one marker prompt run through the host's claude with
|
||||
`--system-prompt-file` shows that it replaces the default prompt. The claude version is printed. With
|
||||
the design's model path, Bean and Chet run pi, so this check is skipped unless she adds a claude-code
|
||||
specialist.
|
||||
- When an instance's provider is `zai`, `<configDir>/secrets/claude-session.env` exists, is a regular
|
||||
file owned by `<user>` at 0600, and sets a nonempty `ZAI_API_KEY` (design 10 step 2d). It parses the
|
||||
file the way systemd does, so the last assignment of a name wins (webby-0032 N3). A pi launch has no
|
||||
credential check, so without this the first turn is where a missing key shows. The precheck prints
|
||||
the name and never the value.
|
||||
|
||||
It also prints free memory and verifies that HOME is `<home>`.
|
||||
|
||||
### Tests
|
||||
|
||||
`case2-unit.sh` runs against a scratch unit directory. A clean render writes 0644 files, and these hold:
|
||||
- the bus unit's `Environment=PATH=` starts with the `--node` directory, both for a `--node` outside the
|
||||
default list and for `/usr/bin/node`, which gives `/usr/bin:/usr/local/bin:/bin`. Its `ExecStart=` is
|
||||
the copy's `scripts/mosaic`
|
||||
- the Console unit's `ExecStart=` starts with `--node` and holds the flags in order
|
||||
- the bus unit has exactly one `WantedBy=`, `multi-user.target`, and the Console unit has no `[Install]`
|
||||
- both units hold the four hardening lines once, in order, and only the Console holds the two
|
||||
capability lines
|
||||
- a check of the script for `systemctl link` finds nothing
|
||||
|
||||
These cases refuse:
|
||||
- an installed unit edited to `User=root`
|
||||
- an edited `ExecStart=`
|
||||
- an installed unit with a hardening line removed, and a template with `RestrictNamespaces=`,
|
||||
`PrivateUsers=` or `SystemCallFilter=` added
|
||||
- a bus template with the `EnvironmentFile=` line removed or pointing elsewhere, and a Console template
|
||||
with one added
|
||||
- a symlink at either unit path
|
||||
- a `--node` that is relative, not root-owned, or under `<home>`
|
||||
- a re-install with a different `--node` or different serve flags
|
||||
- an installed pair whose units name different copy ids
|
||||
- a template holding an unknown `@TOKEN@`, and an unrendered `%h` left in either unit
|
||||
- a template with `ExecStartPre=+/srv/mosaic/x`, and one with `ExecStartPre=-+/srv/mosaic/x`
|
||||
- a copy id that is short, uppercase, holds `/` or `..`, or names no directory
|
||||
- with `library`: `--port 7332`, a missing proof pair, a proof file owned by root, at 0644, a symlink, or
|
||||
under the data root, `--tester-port`, `--checkout`, `--board`, a `--business` different from the
|
||||
unit's, and an unknown flag. With `factory`: `--tester-port` equal to `--port`.
|
||||
|
||||
The precheck runs against a scratch data root. Each refusal has a case. A fake `node` printing v22
|
||||
refuses, a fake `bwrap` that exits 1 refuses, and an unprivileged port start at or below the Console's
|
||||
port refuses. The claude check runs against a fake claude that appends rather than replaces, and that
|
||||
case refuses. With no claude-code instance the claude check doesn't run, and a test shows a missing
|
||||
claude passes. The key file refuses when missing, at 0644, a symlink, with `ZAI_API_KEY=` empty, and
|
||||
with `ZAI_API_KEY=x` followed by `ZAI_API_KEY=`. A search of the test output for the fixture key value
|
||||
finds nothing. `factory` passes with the tester on and refuses a business file with a library project.
|
||||
`library` refuses with the tester on.
|
||||
|
||||
The bind test (mos-1100). A session can't take the Console's port. The test builds the argv a real
|
||||
session gets, with `binds()` and `sandboxArgv()` from `packages/seat/src/sandbox.mjs`, around a node
|
||||
one-liner that binds `127.0.0.1` on a port below 1024 and prints the error code. Inside bwrap the bind
|
||||
fails with `EACCES`. The control runs the same one-liner in the same sandbox on a free port of 1024 or
|
||||
above, and that bind succeeds, so the failure comes from the port floor and not from a broken sandbox.
|
||||
The test reads `net.ipv4.ip_unprivileged_port_start` first. If the test host's floor is at or below the
|
||||
chosen port, the test fails and says so, rather than skipping.
|
||||
|
||||
### Out of scope
|
||||
|
||||
Running either script on a host. Design 10 steps 2 to 9 are Jason's, and the root step 2c is ops-01's
|
||||
over ssh as `localadmin`. The library checks and the install are C2-13b.
|
||||
|
||||
### Gate
|
||||
|
||||
Webby approves the manifest. The test file and the cli suite are green on Sage's gate, along with every
|
||||
`scripts/test-*.sh`. A run on a host is a separate window with Jason's go.
|
||||
|
||||
---
|
||||
|
||||
## C2-13b install script and library precheck
|
||||
|
||||
### Problem
|
||||
|
||||
Nothing installs a library business on her host, and C2-13a's precheck doesn't yet check the library
|
||||
parts.
|
||||
|
||||
### Owner and reviewer
|
||||
|
||||
- Owner: Gosalyn, Opus 5.5. The script runs only under Jason's go, by him or his delegate (design 10).
|
||||
- Reviewer: Webby.
|
||||
- After: C2-04, C2-03a, C2-20.
|
||||
- After: C2-13a, C2-04, C2-03a, C2-20.
|
||||
|
||||
### Files owned
|
||||
|
||||
`scripts/case2-install.sh`, `scripts/case2-precheck.sh` and `scripts/case2-unit.sh` (new), the template
|
||||
`packages/cli/systemd/mosaic-stack.service.in` (new), `packages/cli/tests/case2-install.test.mjs`
|
||||
(new), and one line of `packages/cli/README.md`: at `:713`, "nothing in the repository creates or reads
|
||||
it" changes to say that nothing creates it, that only the Case 2 precheck reads it, and that the
|
||||
precheck prints only variable names, never values (webby-0034 N2, webby-0035).
|
||||
`scripts/case2-install.sh` (new), `scripts/case2-precheck.sh` (the library checks only) and
|
||||
`packages/cli/tests/case2-install.test.mjs` (new).
|
||||
|
||||
### What ships
|
||||
|
||||
@@ -736,92 +945,31 @@ path. It runs as `<user>` through `sudo -u mosaic -H` from `localadmin`, and `mo
|
||||
doesn't create `<user>` and writes no unit file. Root does those in design 10 steps 2a and 2c. Every
|
||||
host value is an input, so a later host move changes only inputs.
|
||||
|
||||
Row 195 runs these scripts by input for Case 1 on 10.1.1.53 (darkwing to gosalyn, design at
|
||||
`agents/darkwing/work/queue-195/DESIGN.md` section 2). They don't copy them. So the install and the
|
||||
precheck take `--profile factory|library`, default `library`:
|
||||
Row 195 runs the install by input for Case 1 on 10.1.1.53 (darkwing to gosalyn, design at
|
||||
`agents/darkwing/work/queue-195/DESIGN.md` section 2). It doesn't copy it. So the install takes
|
||||
`--profile factory|library`, default `library`, as the precheck does:
|
||||
- `library` is everything this brief lists.
|
||||
- `factory` skips the library mapping, the persona files and digests, the token slot, and
|
||||
`library.sync` and `library.status`. It requires `bus.tester` on, because Case 1's acceptance uses the
|
||||
tester.
|
||||
- `factory` refuses a business file that has a `kind: "library"` project, with
|
||||
`profile-library-business`. So Case 2 can't reach a tester-on check through a wrong flag.
|
||||
- `library` refuses with `bus.tester` on, as before.
|
||||
`library.sync` and `library.status`.
|
||||
|
||||
`case2-unit.sh` is the 2c step. Root runs it from a root-owned checkout of the reviewed commit outside
|
||||
`/srv/mosaic`, never from the release, because `mosaic` can write the release. It does the following:
|
||||
- It renders the unit from the checkout's template, with the user, the home and the copy id as inputs.
|
||||
- It refuses unless `User=`, `Group=`, `ExecStart=`, `EnvironmentFile=` and the hardening lines match
|
||||
fixed values. `EnvironmentFile=` is the line in `packages/cli/systemd/mosaic-bus.service.in:24`. The
|
||||
copy id is the one part of `ExecStart=` that varies, so a re-pin to a new copy can re-render the
|
||||
unit (row 195). It must be exactly 40 lowercase hex characters naming a copy that holds `scripts/mosaic`,
|
||||
directly under `<home>/.local/share/mosaic-stack/copies`. That is the rule `copy_root` uses
|
||||
(`scripts/stack-copy.sh:6`, `:20`). Anything else refuses before the render.
|
||||
- It refuses any `PermissionsStartOnly=`, and any `Exec*=` value whose leading run of prefix
|
||||
characters (`@`, `-`, `:`, `+`, `!`) holds a `+` or `!`. systemd takes those prefixes in any order,
|
||||
so `-+/srv/mosaic/x` runs as root even with `User=mosaic`. The named-line check doesn't read these
|
||||
lines (webby-0026 N1, webby-0027, defence in depth).
|
||||
- It writes `/etc/systemd/system/mosaic-stack.service` as `root:root` 0644. It never uses
|
||||
`systemctl link`, and it refuses a symlink at the unit path.
|
||||
- On a re-install, it refuses an installed unit that differs from the render.
|
||||
- It reads nothing from under `<user>`'s home.
|
||||
|
||||
The precheck refuses unless all of these hold:
|
||||
- The config validates.
|
||||
- `sudo -n true` fails as `<user>`, and `id -G` prints exactly one entry, its primary group. A system
|
||||
user always has one, so the check is for supplementary groups. `bus.tester` is not on.
|
||||
- The business file, `.history`, `changes.jsonl` and persona files have the modes in design 4, and
|
||||
each persona digest matches.
|
||||
- The run root is 0700.
|
||||
- `XDG_DATA_HOME` is unset or is `<home>/.local/share`. `copy_root` reads the copies dir from it
|
||||
(`scripts/stack-copy.sh:6`), and the unit fixes `<home>/.local/share`, so any other value would
|
||||
put the copy where the unit refuses it (webby-0032 N2). A test sets it elsewhere and the precheck
|
||||
refuses.
|
||||
- `node --version` is 24 or later, because every package's `engines` field says `>=24` (row 195: .53
|
||||
has v22.22.2).
|
||||
- `bwrap --unshare-all --ro-bind / / true` exits 0 as `<user>`. Without it no session starts. Row 195
|
||||
found no bwrap on .53, and `kernel.apparmor_restrict_unprivileged_userns=1`, and .54 may be the same.
|
||||
On a refusal, the precheck prints the sysctl's value and whether `bwrap` is on PATH.
|
||||
- When some creative instance's harness is claude-code, one marker prompt run through the host's claude
|
||||
with `--system-prompt-file` shows that it replaces the default prompt. The claude version is printed.
|
||||
With design r9's model path, Bean and Chet run pi, so this check is skipped unless she adds a
|
||||
claude-code specialist.
|
||||
- When an instance's provider is `zai`, `<configDir>/secrets/claude-session.env` exists, is a regular
|
||||
file owned by `<user>` at 0600, and sets a nonempty `ZAI_API_KEY` (design 10 step 2d). It parses the
|
||||
file the way systemd does, so the last assignment of a name wins (webby-0032 N3). A pi launch
|
||||
has no credential check, so without this the first turn is where a missing key shows. The precheck
|
||||
prints the name and never the value.
|
||||
The precheck's library profile adds these checks to C2-13a's:
|
||||
- The business file, `.history`, `changes.jsonl` and persona files have the modes in design 4, and each
|
||||
persona digest matches.
|
||||
- `library.sync` fetches her repo read-only, and `library.status` lists R-problems.
|
||||
- No Discord binding exists.
|
||||
|
||||
It also prints free memory and verifies HOME is `/srv/mosaic`.
|
||||
### Tests
|
||||
|
||||
Tests run against a scratch data root and a local bare repo. Each precheck refusal has a case. The
|
||||
claude check runs against a fake claude that appends rather than replaces, and that case refuses. With
|
||||
no claude-code instance the claude check doesn't run, and a test shows a missing claude passes. The key
|
||||
file refuses when missing, at 0644, a symlink, with `ZAI_API_KEY=` empty, and with `ZAI_API_KEY=x`
|
||||
followed by `ZAI_API_KEY=`. A search of the test
|
||||
output for the fixture key value finds nothing.
|
||||
`case2-unit.sh` runs against a scratch unit directory. These cases refuse:
|
||||
- an installed unit edited to `User=root`
|
||||
- an edited `ExecStart=`
|
||||
- a template with a hardening line removed
|
||||
- a template with the `EnvironmentFile=` line removed or pointing elsewhere
|
||||
- a symlink at the unit path
|
||||
- a template with `ExecStartPre=+/srv/mosaic/x`
|
||||
- a template with `ExecStartPre=-+/srv/mosaic/x`
|
||||
- a copy id that is short, uppercase, holds `/` or `..`, or names no directory
|
||||
|
||||
Precheck cases for the new lines: a fake `node` printing v22 refuses, and a fake `bwrap` that exits 1
|
||||
refuses. `--profile factory` passes with the tester on and no library items, and refuses a business
|
||||
file with a library project. `--profile library` refuses with the tester on.
|
||||
A clean render writes a 0644 file. A test checks the script for `systemctl link`.
|
||||
They run against a scratch data root and a local bare repo. Each new precheck refusal has a case: a
|
||||
persona file at 0644, a digest mismatch, a business file at the wrong mode, a sync failure and a
|
||||
Discord binding. The install's `factory` profile writes no library mapping, persona file or token slot.
|
||||
|
||||
### Out of scope
|
||||
|
||||
Running it on the host. Design 10 steps 2 to 7 are Jason's. Step 1 no longer waits on #421 (Q183), and
|
||||
Mos lifted its hold (mos-1074). The root steps 2a and 2c are ops-01's, over ssh as `localadmin`,
|
||||
so the install waits on #423 step 1 and on nothing else in #423. The Gitea bot account and the token slot are steps 3 and 4. Stopping Hermes
|
||||
is step 9 and her choice.
|
||||
Mos lifted its hold (mos-1074). The root steps 2a and 2c are ops-01's, over ssh as `localadmin`, so the
|
||||
install waits on #423 step 1 and on nothing else in #423. The Gitea bot account and the token slot are
|
||||
steps 3 and 4. Stopping Hermes is step 9 and her choice.
|
||||
|
||||
### Gate
|
||||
|
||||
@@ -896,7 +1044,7 @@ its first turn, as `packages/cli/README.md:439-444` says.
|
||||
shell inside any of them can read it. Where the README names `claude-session.env` ("Unit", `:711`),
|
||||
"The file holds one line" becomes "The file holds one line per variable", followed by a sentence
|
||||
saying it holds every session provider key, not only Claude's (webby-0032, webby-0034 N1). Leave
|
||||
`:713`, "nothing in the repository creates or reads it", alone. C2-13 owns that line.
|
||||
`:713`, "nothing in the repository creates or reads it", alone. C2-13a owns that line.
|
||||
- One test in `session.test.mjs`: `ENV_ALLOW` includes `ZAI_API_KEY`, and
|
||||
`sessionEnv({ ZAI_API_KEY: "fixture-zai", ZAI_TOKEN: "t" }, run)` returns `ZAI_API_KEY` with the fixture
|
||||
value and no `ZAI_TOKEN`. The existing allowlist test (`:51-59`) stays as it is.
|
||||
|
||||
Reference in New Issue
Block a user