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.
4.6 KiB
mesh-reads
A node's files and accounts, read through the mesh (novox/hq ADR 0310, extending ADR 0268 §5; hq to-be 41
WP8; issue 418). It holds the node seat node-reads on every node, the control-node included, so reading a
file, searching one, listing a directory, the owner and mode of each component of a path and looking up an
account or a group never go through the login shell's execute, and an approval is asked for an act, never
for a read.
Who it reads as
The account mesh-reads, which this module makes on every node (runs-as, ADR 0259 §8): no login shell, a
home of its own under /var/lib, and no group beside its own. The tool runner serves it in a runtime of its
own, on its own bus credential, never the machine's runtime, which runs as the operator's account. So the
node's file modes bound what it sees: a file only the operator, root or a module's own account may read is
refused by its mode, and the answer says so. It refuses every read when it finds itself running as root.
What it refuses by name
Before any read, whatever the file modes would allow (ADR 0310 §5):
-
The places the mesh keeps a secret on this node, which the controller composes from the manifests and gives it as
MESH_SECRET_PLACES: the directory of every module's own secret (its bus credential among them), every credential file and grant directory, the vault's directories, and where the operator-sealed secrets are kept. Without that list the module does not start. -
The known credential files of a machine's programs (
refuse.go): an account's.ssh,.gnupg,.aws,.kube; the agent's.credentials.json,.netrc,.pgpass,.git-credentials; private key names (id_ed25519,*.key,ssh_host_*_key);/etc/shadow;/etc/ssl/private,/etc/wireguardand the network manager's connections. -
Histories and profiles: shell and program histories (
.zsh_history,.bash_history,.psql_history,.viminfo…), browser and mail profiles (.mozilla,.config/google-chrome,.config/chromium…), a process'senviron,mem,fd,map_files,rootandcwdunder/proc, and/etc/rancherand/etc/kubernetes/admin.conf.
What was opened is judged, not the name. The type is checked before the open, so a device or a fifo is
never opened; the file is opened non-blocking (in a search without following a link), checked again on its
descriptor, and the path the kernel gives for that descriptor is judged by name like any path asked. A link
flipped between the check and the open therefore reaches nothing a name refuses, and a deleted file is refused.
Limit: a hard link to a secret file under another name is not seen by the name rule; the file's own mode,
and the kernel's protected hard links, are what bound it. stat and readlink say a secret place's owner
and mode, and mark it, because those are not its content; list, read and search refuse it.
The content rule
Every answer passes the content rule's secret class, from mesh-sdk's outward package (ADR 0310 §4): a
line of a file or a matching line shaped like a secret is withheld and its number said, as is a link target
or an account's words. Every line of a BEGIN … END block — a private key's or a certificate's — is withheld whole, because one
base64 line of a key can pass the rule alone. A path and an entry's name are not judged: they are what the caller named or what the
file system calls a thing, and the rule would take a temporary directory's or a container layer's name for a
token.
Its verbs and their bounds
| verb | replaces | bounds |
|---|---|---|
stat |
stat, ls -ld, namei -l, findmnt -T |
200 paths, 64 components each; links followed only with follow |
readlink |
readlink, readlink -f, realpath |
one path |
list |
ls, ls -la |
2000 entries, cut and said |
read |
cat, head, tail, less |
64 KiB, or up to 256 KiB when asked; cut at a line and said; text only |
search |
grep, grep -r, grep -F |
a fixed string; 100 matches (500 asked), 4 deep (8 asked), 5000 files, 4 MiB a file, 20 seconds (checked inside a file too); the named path's file system only, the others named; the bound met is said |
account |
getent passwd, getent group, id, groups |
2000 accounts and groups; never a password field |
No answer is larger than 1 MiB. Nothing here writes a file.
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).