The packet filter's tools are a bundle the node's runtime serves; its container goes (hq to-be 38 WP4)
nftables drops its container, NET_ADMIN, the container-runtime capability, the runtime base images and the Dockerfile; its tools are declared as a TypeScript bundle the toolchain compiles and node-tools loads on every node. The runtime runs as the operator's account, so the tool runs the filter's commands through sudo without a prompt when it is not root (ADR 0175 §4); the filter file is the path the manifest's filtering names, no container env carrying it.
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
// rule set from every module's `listens` and writes it to the filter file (ADR 0045); the module
|
||||
// loads it through its own unit. This code reads the filter back as the machine enforces it, reloads
|
||||
// the mesh's own table, and removes one thing the mesh did not write when the operator names it
|
||||
// (ADR 0168, ADR 0170) — the seat's three verbs, over the machine's own tools.
|
||||
// (ADR 0168, ADR 0170) — the seat's three verbs, over the machine's own tools, which it runs as root
|
||||
// through sudo when the runtime loading it is not (ADR 0175).
|
||||
|
||||
import { execFile } from "node:child_process";
|
||||
import { promisify } from "node:util";
|
||||
@@ -12,9 +13,27 @@ const execFileP = promisify(execFile);
|
||||
/** A command runner, so the acts can be tested without a packet filter. */
|
||||
export type Runner = (cmd: string, args: string[]) => Promise<string>;
|
||||
|
||||
/** The command as it is run: as given when this process is root, else through sudo without a
|
||||
* prompt. The runtime that loads this bundle runs as the node's operator account, which may
|
||||
* escalate as the operator would (novox/hq ADR 0175 §4); the packet filter answers only to root,
|
||||
* listing included. A command sudo refuses fails by name, saying what the account lacks. */
|
||||
export function escalated(cmd: string, args: string[], uid: number | undefined = process.getuid?.()): [string, string[]] {
|
||||
if (uid === 0) return [cmd, args];
|
||||
return ["sudo", ["-n", cmd, ...args]];
|
||||
}
|
||||
|
||||
export const execRunner: Runner = async (cmd, args) => {
|
||||
const { stdout } = await execFileP(cmd, args, { maxBuffer: 16 * 1024 * 1024 });
|
||||
return stdout;
|
||||
const [program, argv] = escalated(cmd, args);
|
||||
try {
|
||||
const { stdout } = await execFileP(program, argv, { maxBuffer: 16 * 1024 * 1024 });
|
||||
return stdout;
|
||||
} catch (err) {
|
||||
const stderr = String((err as { stderr?: string }).stderr ?? "").trim();
|
||||
if (program === "sudo" && /a password is required|not allowed to execute|not in the sudoers/.test(stderr)) {
|
||||
throw new Error(`${cmd} needs root and the runtime's account may not escalate without a prompt: ${stderr}`);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
/** The mesh's own tables, which `remove` never touches. */
|
||||
|
||||
Reference in New Issue
Block a user