Commit Graph
3 Commits
Author SHA1 Message Date
jochen 08c0f40ff0 review: refuse a process named ".", ".." or with a leading dash, so removing one cannot delete the mesh's own directory (hq ADR 0118)
removeProcess deletes filepath.Join(daemonRoot, name) whole; a process named ".." made that
/var/lib/mesh. The declaration and the removal now hold the name to one rule.
2026-09-27 00:41:02 +02:00
jschoubben de5160de4a A unit file reinterprets an environment value; a container does not
Found by being asked whether processes and containers handle environment the
same way. They do not, and the difference is not cosmetic.

Docker passes --env through literally. A unit file reads three things out of a
value that nothing else does, and a module's environment routinely contains all
three because a generated password is arbitrary bytes:

  - % begins a specifier. %H is the hostname. A password containing one is
    silently replaced, and it fails later as an authentication error nobody can
    explain by reading the declaration.
  - whitespace separates assignments. Unquoted, K=a b sets K to "a" and reads
    "b" as another assignment.
  - a newline ends the line, and what follows is read as a unit DIRECTIVE.

The first two are escaped: quoted, with quotes and backslashes escaped and
percent doubled. The third cannot be — a unit's environment has no way to carry
a line break — so it is refused in validation, near whoever wrote it. Without
that, an environment value could write ExecStart= and have the machine run
something nobody declared.

Ordinary awkward values stay accepted, because refusing those too would leave a
module unable to hold a generated password.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
2026-09-15 12:40:36 +02:00
jschoubben f5cf9510c1 One kind for the module's own code, with three modes
The first cut of this added a `daemon` for the long-running case alone. That
would have meant a new vocabulary entry for each of the others — a scheduled
task, a run-once migration, a health check — when they are one thing run at
different cadences. That is a field, not four entries in a vocabulary where every
entry widens what a compromised control plane can express.

So it mirrors a container exactly, because it IS a container's twin: the same
intent, hosted by the machine's own supervisor instead of a runtime. Stays up,
runs once, or runs on a schedule.

Tools, hooks and event consumers are not further modes. They are loaded by a tool
host, which is itself a process that stays up — so the generic case already
covers them, which is the test of whether it is generic.

A scheduled process gets a timer and a unit that finishes; a long-running one
gets a unit that is restarted when it exits. Getting that wrong either way is a
second copy running continuously between fires, or a schedule that never fires.
The modes are exclusive and validation says so near the author: something that
runs once does not run on a schedule, and something not running between fires
cannot be restarted when a file changes.

A missed fire happens when the machine comes back rather than being skipped,
which is the difference between a machine that was down and a schedule that
quietly stopped.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
2026-09-15 10:26:31 +02:00