Files
stack/packages/bus/src/human.mjs
T
jason.woltjeandClaude Opus 5.5 38828a2cb3 feat(bus): the bus and the broker core (row 37, S2, rocko)
Rocko's round 2 candidate, approved by Darkwing (#1519 comment 26757).
build.patch 40d7e838, manifest 61519059, 24 files under packages/bus,
schema v3b (179ffe35, lead decision 60). Integration gate in a git
worktree of 942dca9e (S1 in the tree) plus the patch: bus 43/43 and
business 60/60 on Node 24 and 26, every package test and every
scripts/test-*.sh green, test-task 98/98 with the live-provider cases.
Rulings from lead decisions 62 and 63: the human proof is cooperative in
slice 1, and a self-raised cross-role decision routes to the human.
Single-use gated approvals follow in row 43.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 17:15:53 -05:00

102 lines
3.1 KiB
JavaScript

import { readFileSync, lstatSync } from 'node:fs';
import { basename, resolve } from 'node:path';
import { BusError } from './broker.mjs';
const MARKERS = [
'MOSAIC_BUS_CAP',
'MOSAIC_RUN_ID',
'MOSAIC_AGENT_RUN',
'CLAUDECODE',
'CLAUDE_CODE_ENTRYPOINT',
'CODEX_THREAD_ID',
'PI_AGENT_DIR',
];
const refuse = () => {
throw new BusError('human-required');
};
export function readProcess(pid, { readFile = readFileSync, stat = lstatSync } = {}) {
if (!Number.isSafeInteger(pid) || pid < 1) refuse();
try {
const dir = `/proc/${pid}`,
raw = readFile(dir + '/stat', 'utf8'),
fields = raw.slice(raw.lastIndexOf(')') + 2).split(' ');
let env = {};
let environment;
try {
environment = readFile(dir + '/environ', 'utf8');
} catch (e) {
if (e.code !== 'EACCES') throw e;
env = null;
}
if (environment !== undefined)
for (const entry of environment.split('\0')) {
const i = entry.indexOf('=');
const key = entry.slice(0, i);
if (key === 'MOSAIC_BUS_CLI_NONCE' || MARKERS.includes(key)) env[key] = entry.slice(i + 1);
}
return {
pid,
ppid: Number(fields[1]),
startTime: fields[19],
uid: stat(dir).uid,
argv: readFile(dir + '/cmdline', 'utf8')
.split('\0')
.filter(Boolean),
env,
};
} catch {
refuse();
}
}
// Cooperative same-UID process checks, not peer credentials or a hostile-process wall.
// A nonce in the CLI's launch environment binds the submitted PID to a live CLI.
export function verifyHuman(proof, { cliPath, launches = [], readProcess: read = readProcess }) {
if (
!proof ||
typeof proof !== 'object' ||
Object.keys(proof).some((k) => !['pid', 'startTime', 'nonce', 'business'].includes(k)) ||
!Number.isSafeInteger(proof.pid) ||
proof.pid < 2 ||
typeof proof.business !== 'string' ||
typeof proof.nonce !== 'string' ||
!/^[a-f0-9]{64}$/.test(proof.nonce)
)
refuse();
try {
const p = read(proof.pid);
if (
p.uid !== process.getuid() ||
p.startTime !== proof.startTime ||
p.env?.MOSAIC_BUS_CLI_NONCE !== proof.nonce ||
p.argv[1] !== resolve(cliPath)
)
refuse();
const seen = new Set();
let current = p;
for (let depth = 0; depth < 128; depth++) {
if (seen.has(current.pid)) refuse();
seen.add(current.pid);
if (
(current.env !== null && MARKERS.some((k) => current.env[k])) ||
launches.some((r) => r.pid === current.pid && r.startTime === current.startTime)
)
refuse();
const command = basename(current.argv[0] ?? '');
if (
/^(pi|claude|claude-code|codex)(?:\.js)?$/.test(command) ||
current.argv.some((v) => /\/(?:pi-coding-agent|codex)\/(?:dist|bin)\//.test(v))
)
refuse();
if (current.ppid === 1) {
const again = read(proof.pid);
if (again.startTime !== proof.startTime || again.ppid !== p.ppid) refuse();
return { business: proof.business };
}
if (current.ppid < 2) refuse();
current = read(current.ppid);
}
} catch {
refuse();
}
refuse();
}