mesh/merge-gate checking again: the gate refused `unknown` because the controller judged with a node-engine validator pinned before mesh-host #117; mesh-co…
mesh/repo-check checking again: the gate refused `unknown` because the controller judged with a node-engine validator pinned before mesh-host #117; mesh-co…
mesh/delivery-group group feat/owned-paths checking: 0 of 2 member(s) ready
mesh/delivery superseded: a newer head of the same pull request
Every directory and archive resource carries `unknown`: move-out for a home folder whose program writes nothing there (the node-engine, delivered in mesh-host #117, moves the rest to ~/.local/state/mesh-moved/<module>/ with a list), module for ~/.ssh and ~/.claude, program elsewhere; `knows` keeps what a program or the operator relies on (powerlevel10k's compiled files, i3's scripts and the asus/g14 drop-ins, dunst's slack rule, betterbird's records, node-env's forge credential, issue 1033). Two shared folders are no longer declared. Each module's README says it. checks/owned holds every manifest to it; checks/sshdir stays while main's merge check runs it (issue 1035). Tests that pin a manifest follow the new key only. Reviewed in three rounds.
70 lines
3.7 KiB
Markdown
70 lines
3.7 KiB
Markdown
# mesh-files
|
|
|
|
The holder of the node seat `node-files` (novox/hq ADR 0394, issue 900; to-be 41 WP9). It reads and manages
|
|
the files and accounts of the node it runs on, through the mesh, so nothing about a node's files goes through
|
|
a shell.
|
|
|
|
It replaces `mesh-reads` (ADR 0310), which stays beside it until `mesh-files` is assigned on every node (ADR 0394 §9).
|
|
|
|
## Verbs
|
|
|
|
The seat's verbs, with the descriptions the controller defines (`internal/catalogue/files.go`).
|
|
|
|
- **Reads:** `stat`, `readlink`, `list`, `read`, `search`, `account`. As in mesh-reads: bounded answers, a place a
|
|
secret is kept refused by name before any read, a line shaped like a secret withheld.
|
|
- **Writes:** `write` (a text file whole, with an optional mode), `copy`, `move`, `delete` (recursive on
|
|
request), `mkdir` (parents on request), `chmod` (octal or `u+x,go-w`, recursive on request), `chown` (owner,
|
|
optional group, recursive on request).
|
|
- **Trash:** `trash` lists it, `restore` puts an item back.
|
|
|
|
Every write verb takes `reason` (required, for the audit trail) and `override` (a reason; needed only for a
|
|
path a module owns).
|
|
|
|
## Rights
|
|
|
|
It runs as the tool runner's account, the node's operator account, and declares no account of its own. An act
|
|
is tried with that account's rights first. Where that fails with a permission error, the act is repeated
|
|
through `sudo -n` with a fixed binary (cat, cp, mv, stat, chmod, chown, mkdir, rm under `/usr/bin`) and an
|
|
argument list built from fixed words and one path, never a shell (`sudo.go`). Tests use a fake runner.
|
|
Not yet through sudo: `stat`, `list`, `readlink` and `search` (they answer what the account reaches and say what it
|
|
may not); `read` and every write do.
|
|
|
|
## Owners and modes
|
|
|
|
- `copy` and `move` keep owner and mode (`cp -a`); a copy refuses a target that exists.
|
|
- A new file or folder takes its folder's owner and group.
|
|
- An overwrite keeps the overwritten file's owner and mode.
|
|
|
|
## Trash
|
|
|
|
`delete`, and the overwrite of `write`, first move the old item to `<state>/trash/<id>/item` with a
|
|
`meta.json` (original path, owner, group, mode, caller, reason, time). `restore` puts it back and refuses when
|
|
the path is taken now. Entries older than 7 days are emptied on every write call and every `trash` list.
|
|
|
|
## Owned paths
|
|
|
|
The controller gives the holder `MESH_OWNED_PATHS`, a JSON object from an absolute path to `module (tool)`. A
|
|
write, move or delete of such a path, anything under it, or (for delete, move and recursive chmod and chown) a
|
|
folder that holds it, is refused naming the module and tool, unless `override` gives a reason. The override is
|
|
recorded in the act log and told to the operator, in words without a path, through `operator-channel.tell`.
|
|
Without the word, the module starts and owns nothing.
|
|
|
|
## The act log
|
|
|
|
Each write act that was done is one JSON line in `<state>/acts.log`: time, caller, verb, paths, reason, and for
|
|
an override the override and the owned paths it went through. The caller is the bus user the runtime proved
|
|
(`stdio.CallerOf`), or `unproven`; it is never read from the arguments. A refused act is not logged.
|
|
|
|
## What it refuses
|
|
|
|
- A place a secret is kept (`MESH_SECRET_PLACES`, and the known credential files in `refuse.go`) is refused by
|
|
name for `read`, `list` and `search`. Copying or moving such a place is allowed: nothing is printed.
|
|
- A copy or move to or from `<node>:/path` is refused: copying between nodes comes in step 2 (issue 903).
|
|
- A write without a reason; a path that is not absolute; a mode that is not a mode.
|
|
|
|
## Files it does not know
|
|
|
|
Each directory or archive this module declares says how it treats a file it did not write (ADR 0422, ADR 0416).
|
|
|
|
- `${dir:state}`: everything in it is the program's; the mesh moves nothing out (ADR 0422 §2).
|