Add the Node build module's manifest, ssh files, toolchain package, build step and toolchain tests (issues 1488, 1484, 1490), part 15 of 19
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# mesh-build-node — the Node and TypeScript build module
|
||||
|
||||
Design 47, release R4c-3 (novox/hq ADR 0405, ADR 0466 §1, ADR 0469 §1 and §4). The module that builds and checks
|
||||
TypeScript code on a build machine, as an account of its own (`runs-as`, no login shell, home at mode 0700), with the
|
||||
packages it declares (`nodejs`, `npm`, `git`, `openssh`) and the capability `user-namespaces`. The bundle is Go
|
||||
(`cmd/mesh-build-node`). It claims no seat: it is assigned to the build machines (ADR 0469 §6) and runs dark until the
|
||||
builder uses it. Its forge key and ssh files are the same as mesh-build-go's (issue 1484).
|
||||
|
||||
## The recipe
|
||||
|
||||
`recipe.go` names the one Node version it builds with (`RecipeNode`, `v26.10.0`, as `node --version` prints it) and the
|
||||
recipe's own version (`RecipeSteps`). The recipe version is a hash of those two and of the bytes of the lock file
|
||||
`files/toolchain/package-lock.json`, so one changed byte of the lock, another Node or another recipe moves it.
|
||||
|
||||
## The toolchain directory
|
||||
|
||||
`files/toolchain/package.json` and its committed `package-lock.json` name typescript 5.9.3, esbuild 0.25.12, @types/node 22.20.1 (the types tsc checks node imports against),
|
||||
@novox/mesh-sdk 0.1.14 and nats 2.29.3. The mesh writes both into `<home>/toolchain/` (resources `toolchain-package`
|
||||
and `toolchain-lock`); the program reads the lock from there. When `<cache dir>/toolchain/<recipe version>` is missing
|
||||
the module runs `npm ci --ignore-scripts` there once (a directory without its `.installed` mark counts as missing).
|
||||
|
||||
**How the registry is reached** (the choice of issue 1488): the lock holds @novox/mesh-sdk at the forge's public
|
||||
address, and npm 12 installs a locked tarball only from the registry it is configured with. The module therefore
|
||||
requires `npm-package-registry` (read access, provided by gitea) and, like the lab module, takes its binding and sealed
|
||||
secret as files in its home. The install gets a private npm config file with the `@novox` scope at the binding's
|
||||
`public-root` (else scheme, address, port and npm path) and the bound account's credential, and removes it afterwards;
|
||||
every other package resolves from the public registry. This is the way today's build agent names it.
|
||||
|
||||
The runtime tree for bundles with externals (the pruned sdk and nats today in `/app/runtime`) is not installed
|
||||
separately: sdk and nats are in this directory's `node_modules`, and the build step (issue 1490) takes them from there.
|
||||
|
||||
## The guard and the health
|
||||
|
||||
At start, every ten minutes, before every step and at every health look, the module reads the lock again and the
|
||||
installed Node (`node --version`) and writes it with the recipe version to `<node>.typescript` of its `toolchains`
|
||||
state. A machine whose Node is not the recipe's refuses every step, the step ending `refused` on its key in `steps` with
|
||||
both versions named, and `build_node_health` (the module's `runtime-health`) answers unhealthy with the same text, so
|
||||
the controller raises the machine's condition. A step runs only after the toolchain directory is installed.
|
||||
|
||||
## Tools
|
||||
|
||||
`build_node_status` and `build_node_health` answer in their call. The step tools run behind the guard and the
|
||||
toolchain install: a long step answers at once with its id and ends on `<node>.<id>` of `steps` (ADR 0469 §2).
|
||||
|
||||
- `build_node_fetch` {repository, commit, ref} (issue 1489): the commit over ssh as the module's account
|
||||
(`buildstep.FetchCommit`, remote `ssh://mesh-forge/<owner>/<name>.git`) into `<work>/<id>/tree`, then for each
|
||||
TypeScript module (a module.json with a typescript artifact) the packages its package.json names beyond the SDK,
|
||||
`typescript` and `@types/*` (the toolchain carries those): none installs nothing; some need a package-lock.json, else
|
||||
the step fails naming the directory, and are installed as the build agent does (scratch copy without the SDK,
|
||||
devDependencies and scripts; `npm ci --omit=dev --omit=peer --ignore-scripts --no-bin-links`; copies of the SDK
|
||||
removed). A dependency on another `@novox/` package fails the step: a fetch holds no registry credential
|
||||
(ADR 0466 §4). Every command runs through `forgekey.ExecRunnerClean(0)` with PATH, HOME, the locale and its own
|
||||
words, nothing of this process's environment. Workspaces older than a day are removed at each fetch.
|
||||
- `build_node_test` {workspace, module, level} (issue 1491): the unit level is the type-check (the toolchain's tsc, the
|
||||
package's `tsconfig.json` or the build agent's flags over its .ts files) and the `test` script; the integration level
|
||||
is the `test:integration` script, the type-check being its setup. Bounds (the Go module's; ADR 0445 names none for
|
||||
TypeScript): unit 5 s, integration 30 s setup and 60 s running. A level over its bound says `over_bound` and passes;
|
||||
a failed one finishes the step with `passed` false and the output (the step fails only when the tests could not be run). Neither script nor .ts files: no tests. The toolchain makes no bin
|
||||
links, so a script runs `node` and files, not `tsc` by name.
|
||||
- `build_node_build` {workspace, module, artifact} (issue 1490): the build agent's tsc and esbuild lines
|
||||
(mesh-controller internal/builder, cited in `build.go`), the launchers, `package.json`, `buildstep.Pack`, and the
|
||||
digest. No network. The toolchain's packages (not typescript or esbuild) are copied to `<work>/<id>/node_modules`,
|
||||
above the tree, which is where tsc, esbuild and node find `@novox/mesh-sdk` and the types by walking up; a copy and
|
||||
not a link, because the mesh makes no symlink. A bundle that keeps an external gets them in its own `node_modules`.
|
||||
The packed archive is written beside the tree as `<artifact>.tar.gz`.
|
||||
Reference in New Issue
Block a user