Files
stack/packages/mosaic/src/commands/brain-store.ts
T
2026-08-05 17:19:51 -05:00

1240 lines
39 KiB
TypeScript

import {
chmodSync,
closeSync,
constants as fsConstants,
existsSync,
fsyncSync,
fstatSync,
lstatSync,
linkSync,
mkdirSync,
openSync,
readdirSync,
readFileSync,
rmSync,
unlinkSync,
writeFileSync,
} from 'node:fs';
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
import { createHash, randomUUID } from 'node:crypto';
import { platform } from 'node:os';
import { z } from 'zod';
import { parseCredentialEstateRegistry } from '../credentials/estate-registry.js';
import { assertNoSymlinkAncestors } from '../fleet/secure-file.js';
const SAFE_NAME = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/;
const COMMIT = /^[0-9a-f]{40}$/;
const GITIGNORE_RULES = [
'*.token',
'*.key',
'*.pem',
'.env',
'credentials.json',
'*.TOKEN',
'*.KEY',
'*.PEM',
'*.p12',
'*.pfx',
'*.jks',
'*.keystore',
'.env.*',
'credentials.*',
'secret.*',
'secrets.*',
'id_rsa',
'id_dsa',
'id_ecdsa',
'id_ed25519',
] as const;
const BRAIN_DIRECTORIES = ['agents', 'lanes', 'board', 'specs', 'methods', 'archives'] as const;
const MAX_MIGRATION_FILE_BYTES = 1024 * 1024;
const TERMINAL_EXITS = {
ok: 0,
refused: 10,
error: 20,
indeterminate: 30,
} as const;
const STABLE_REASON_CLASSES: Readonly<Record<string, CredentialOutcome>> = {
'identity-required': 'refused',
'estate-required': 'refused',
'estate-host-mismatch': 'refused',
'cross-estate-resolution': 'refused',
'no-token-for-identity': 'refused',
'tea-login-missing': 'refused',
'tea-login-host-mismatch': 'refused',
'provider-identity-mismatch': 'refused',
'credential-rejected': 'refused',
'permission-denied': 'refused',
'organization-membership-required': 'refused',
'team-membership-required': 'refused',
'invalid-input': 'error',
'estate-registry-invalid': 'error',
'insecure-credential-source': 'error',
'journal-unavailable': 'error',
'internal-invariant': 'error',
'provider-unavailable': 'indeterminate',
'identity-not-visible': 'indeterminate',
'identity-not-measured': 'indeterminate',
'identity-not-found': 'indeterminate',
'unexpected-content-type': 'indeterminate',
'unexpected-provider-shape': 'indeterminate',
'scope-not-evaluable': 'indeterminate',
'permission-evidence-disagrees': 'indeterminate',
'transport-principal-mismatch': 'indeterminate',
'read-only-control-invalid': 'indeterminate',
'readback-missing': 'indeterminate',
'mutation-state-unknown': 'indeterminate',
};
export interface BrainTarget {
readonly estate: string;
readonly host: string;
readonly owner: string;
readonly repo: string;
readonly cloneUrl: string;
}
export type CredentialOutcome = keyof typeof TERMINAL_EXITS;
export interface CredentialAssessment {
readonly outcome: CredentialOutcome;
readonly exitCode: 0 | 10 | 20 | 30;
readonly reasonCode: string;
readonly diagnostic: string;
}
export interface ResolverParityAssessment extends CredentialAssessment {
readonly gitReasonCode: string;
readonly apiReasonCode: string;
}
export interface MigrationOwnerResolution {
readonly verdict: 'resolved' | 'refused' | 'not-measured';
readonly reasonCode: string;
readonly principal: {
readonly name: string;
readonly kind:
| 'active-lane'
| 'durable-team'
| 'durable-human'
| 'durable-queue'
| 'mission-seat';
} | null;
readonly authority: {
readonly system: 'gitea' | 'glpi' | 'mosaic-mission-state';
readonly endpoint: string;
readonly contentType: 'application/json';
} | null;
}
export interface MigrationCandidate {
readonly source: string;
readonly destination: string;
readonly archive: string;
readonly kind: 'lane' | 'seat';
readonly sourceIdentity: {
readonly dev: number | bigint;
readonly ino: number | bigint;
readonly digest: string;
};
}
export interface MigrationReport {
readonly path: string;
readonly reason: string;
}
export interface MigrationPlan {
readonly status: 'ready' | 'blocked';
readonly candidates: readonly MigrationCandidate[];
readonly reported: readonly MigrationReport[];
readonly owner: MigrationOwnerResolution['principal'];
}
export interface MigrationPublishEntry {
readonly path: string;
readonly content: Uint8Array;
}
export interface MigrationPublishEvidence {
readonly commit: string;
readonly remoteHead: string;
readonly reachable: boolean;
}
export interface MigrationHooks {
readonly beforeDestinationWrite?: (destination: string) => void;
readonly beforeSourceCleanup?: (source: string) => void;
}
export interface MigrationResult {
readonly status: 'migrated' | 'reported' | 'failed';
readonly migrated: readonly MigrationCandidate[];
readonly reported: readonly MigrationReport[];
readonly publish: MigrationPublishEvidence | null;
}
export interface BrainDoctorObservation {
readonly rootExists: boolean;
readonly rootPrivate: boolean;
readonly gitRepository: boolean;
readonly remote: string | null;
readonly branch: string | null;
readonly worktreeState: 'clean' | 'dirty' | 'unmeasurable';
readonly access: CredentialAssessment | null;
}
export interface BrainDoctorFinding {
readonly code: string;
readonly repairable: boolean;
readonly reasonCode: string | null;
}
export interface BrainDoctorAction {
readonly program: 'git' | 'mosaic';
readonly args: readonly string[];
readonly findingCode: string;
}
export interface BrainWritePolicy {
readonly allowed: boolean;
readonly mode: 'append-only' | 'single-writer' | 'seat-writer' | 'refused';
readonly reason: string;
}
interface ParsedGitTarget {
readonly host: string;
readonly owner: string;
}
const providerIdentitySchema = z
.object({
login: z.string().min(1),
endpoint: z.literal('GET /api/v1/user'),
contentType: z.string().min(1),
})
.passthrough();
const repositoryPermissionSchema = z
.object({
requested: z.literal('write'),
effective: z.enum(['write', 'admin']),
endpoint: z.string().min(1),
contentType: z.string().min(1),
})
.passthrough();
const writeDifferentialSchema = z
.object({
state: z.literal('can-write'),
credentialBinding: z.literal('same-resolution'),
transportPrincipal: z.string().min(1),
authenticatedReceivePack: z.literal('advertised'),
readOnlyControl: z
.object({
identity: z.string().min(1),
providerPermission: z.literal('read'),
receivePack: z.literal('refused'),
})
.passthrough(),
unauthenticatedReceivePack: z.literal('refused'),
artifactCreated: z.literal(false),
proves: z.string().min(1),
doesNotProve: z.string().min(1),
})
.passthrough();
const credentialResultSchema = z
.object({
schemaVersion: z.literal(1),
operation: z.literal('validate'),
outcome: z.enum(['ok', 'refused', 'error', 'indeterminate']),
exitCode: z.number().int(),
subject: z
.object({
identity: z.string().min(1),
estate: z.string().min(1),
host: z.string().min(1),
repo: z.string().min(1),
})
.strict(),
mutation: z.enum(['none', 'not-started', 'applied', 'unknown']),
reason: z
.object({
code: z.string().min(1),
message: z.string(),
})
.passthrough(),
evidence: z
.object({
providerIdentity: providerIdentitySchema.nullable(),
repositoryPermission: repositoryPermissionSchema.nullable(),
writeDifferential: writeDifferentialSchema.nullable(),
})
.passthrough(),
audit: z
.object({
journalId: z.string().nullable(),
state: z.enum(['not-started', 'open', 'sealed']),
})
.passthrough(),
})
.passthrough();
function safeName(value: string, label: string): string {
if (!SAFE_NAME.test(value)) {
throw new Error(`invalid-${label}`);
}
return value;
}
function parseGitTarget(targetGitUrl: string): ParsedGitTarget {
let host = '';
let pathname = '';
if (/^[^@\s]+@[^:\s]+:.+$/.test(targetGitUrl)) {
const separator = targetGitUrl.indexOf(':');
const authority = targetGitUrl.slice(0, separator);
host = authority.slice(authority.lastIndexOf('@') + 1);
pathname = targetGitUrl.slice(separator + 1);
} else {
let parsed: URL;
try {
parsed = new URL(targetGitUrl);
} catch {
throw new Error('target-git-url-invalid');
}
if (!['https:', 'ssh:'].includes(parsed.protocol) || parsed.password !== '') {
throw new Error('target-git-url-invalid');
}
if (parsed.protocol === 'https:' && parsed.username !== '') {
throw new Error('target-git-url-contains-credential');
}
host = parsed.hostname;
pathname = parsed.pathname;
}
const parts = pathname
.replace(/^\/+/, '')
.replace(/\.git$/, '')
.split('/')
.filter((part: string): boolean => part.length > 0);
if (host.length === 0 || parts.length !== 2) {
throw new Error('target-git-url-invalid');
}
return { host: host.toLowerCase(), owner: safeName(parts[0] ?? '', 'repository-owner') };
}
export function deriveBrainTarget(
registrySource: string,
targetGitUrl: string,
brainNamespace: string,
): BrainTarget {
const target = parseGitTarget(targetGitUrl);
const resolved = parseCredentialEstateRegistry(registrySource).resolveByHost(target.host);
if (resolved === undefined) {
throw new Error(`estate-host-unmapped: ${target.host}`);
}
const owner = safeName(brainNamespace, 'brain-namespace');
const repo = `${owner}/mosaic-brain`;
return {
estate: resolved.estate,
host: target.host,
owner,
repo,
cloneUrl: `${resolved.host.apiBaseUrl}/${repo}.git`,
};
}
function processUid(): number {
if (typeof process.getuid !== 'function') throw new Error('brain-owner-check-unsupported');
return process.getuid();
}
export function brainRootIsPrivate(root: string): boolean {
try {
const status = lstatSync(root);
return (
status.isDirectory() &&
!status.isSymbolicLink() &&
status.uid === processUid() &&
(status.mode & 0o077) === 0
);
} catch {
return false;
}
}
export function ensureBrainRootPrivate(root: string): void {
assertNoSymlinkAncestors(root);
if (!existsSync(root)) mkdirSync(root, { recursive: true, mode: 0o700 });
const status = lstatSync(root);
if (!status.isDirectory() || status.isSymbolicLink() || status.uid !== processUid()) {
throw new Error('brain-layout-root-unsafe');
}
chmodSync(root, 0o700);
if (!brainRootIsPrivate(root)) throw new Error('brain-layout-root-permissions-unsafe');
}
function syncFile(path: string): void {
const descriptor = openSync(path, 'r');
try {
fsyncSync(descriptor);
} finally {
closeSync(descriptor);
}
}
export function createBrainSkeleton(root: string): {
readonly created: readonly string[];
readonly publicationEntries: readonly MigrationPublishEntry[];
} {
const created: string[] = [];
const publicationEntries: MigrationPublishEntry[] = [];
ensureBrainRootPrivate(root);
for (const directory of BRAIN_DIRECTORIES) {
const path = join(root, directory);
if (existsSync(path)) {
const status = lstatSync(path);
if (!status.isDirectory() || status.isSymbolicLink() || status.uid !== processUid()) {
throw new Error('brain-layout-directory-unsafe');
}
chmodSync(path, 0o700);
}
}
for (const directory of BRAIN_DIRECTORIES) {
const path = join(root, directory);
if (!existsSync(path)) {
mkdirSync(path, { recursive: true, mode: 0o700 });
created.push(path);
}
const placeholder = join(path, '.gitkeep');
if (!existsSync(placeholder)) {
writeFileSync(placeholder, '', { encoding: 'utf8', mode: 0o644, flag: 'wx' });
syncFile(placeholder);
created.push(placeholder);
publicationEntries.push({ path: placeholder, content: new Uint8Array() });
} else if (!lstatSync(placeholder).isFile() || lstatSync(placeholder).isSymbolicLink()) {
throw new Error('brain-layout-placeholder-unsafe');
}
}
const ignorePath = join(root, '.gitignore');
if (existsSync(ignorePath)) {
const ignoreStatus = lstatSync(ignorePath);
if (!ignoreStatus.isFile() || ignoreStatus.isSymbolicLink()) {
throw new Error('brain-layout-ignore-unsafe');
}
}
const content = `${GITIGNORE_RULES.join('\n')}\n`;
if (existsSync(ignorePath)) {
const snapshot = stableSourceSnapshot(ignorePath);
if (!snapshot.content.equals(Buffer.from(content, 'utf8'))) {
throw new Error('brain-layout-ignore-content-unsafe');
}
} else {
const temporary = `${ignorePath}.tmp-${process.pid}-${randomUUID()}`;
try {
writeFileSync(temporary, content, { encoding: 'utf8', mode: 0o644, flag: 'wx' });
syncFile(temporary);
linkSync(temporary, ignorePath);
syncFile(ignorePath);
} finally {
rmSync(temporary, { force: true });
}
created.push(ignorePath);
publicationEntries.push({ path: ignorePath, content: new TextEncoder().encode(content) });
}
return { created, publicationEntries };
}
function indeterminate(reasonCode: string): CredentialAssessment {
return {
outcome: 'indeterminate',
exitCode: 30,
reasonCode,
diagnostic: `indeterminate: ${reasonCode}`,
};
}
export function assessCredentialResult(
source: string,
expectedSubject?: {
readonly identity: string;
readonly estate: string;
readonly host: string;
readonly repo: string;
},
): CredentialAssessment {
let raw: unknown;
try {
raw = JSON.parse(source);
} catch {
return indeterminate('unexpected-provider-shape');
}
const parsed = credentialResultSchema.safeParse(raw);
if (!parsed.success) return indeterminate('unexpected-provider-shape');
if (
expectedSubject !== undefined &&
(parsed.data.subject.identity !== expectedSubject.identity ||
parsed.data.subject.estate !== expectedSubject.estate ||
parsed.data.subject.host !== expectedSubject.host ||
parsed.data.subject.repo !== expectedSubject.repo)
) {
return indeterminate('unexpected-provider-shape');
}
const expectedExit = TERMINAL_EXITS[parsed.data.outcome];
if (parsed.data.exitCode !== expectedExit) {
return indeterminate('unexpected-provider-shape');
}
const stableClass = STABLE_REASON_CLASSES[parsed.data.reason.code];
if (stableClass !== undefined && stableClass !== parsed.data.outcome) {
return indeterminate('unexpected-provider-shape');
}
const identity = parsed.data.evidence.providerIdentity;
if (identity !== null) {
if (!identity.contentType.toLowerCase().startsWith('application/json')) {
return indeterminate('unexpected-content-type');
}
if (identity.login !== parsed.data.subject.identity) {
return {
outcome: 'refused',
exitCode: 10,
reasonCode: 'provider-identity-mismatch',
diagnostic: 'refused: provider-identity-mismatch',
};
}
}
if (parsed.data.outcome === 'ok') {
const permission = parsed.data.evidence.repositoryPermission;
const differential = parsed.data.evidence.writeDifferential;
if (
identity === null ||
permission === null ||
differential === null ||
!permission.contentType.toLowerCase().startsWith('application/json') ||
differential.transportPrincipal !== parsed.data.subject.identity ||
parsed.data.mutation !== 'none' ||
parsed.data.audit.state !== 'sealed' ||
parsed.data.audit.journalId === null
) {
return indeterminate('readback-missing');
}
}
if (
parsed.data.reason.code === 'provider-identity-mismatch' &&
(identity === null || identity.login === parsed.data.subject.identity)
) {
return indeterminate('unexpected-provider-shape');
}
return {
outcome: parsed.data.outcome,
exitCode: expectedExit,
reasonCode: parsed.data.reason.code,
diagnostic: `${parsed.data.outcome}: ${parsed.data.reason.code}`,
};
}
export function assessResolverParity(
gitSource: string,
apiSource: string,
): ResolverParityAssessment {
const git = assessCredentialResult(gitSource);
const api = assessCredentialResult(apiSource);
if (git.outcome === 'refused' && api.outcome === 'refused' && git.reasonCode === api.reasonCode) {
return {
...git,
gitReasonCode: git.reasonCode,
apiReasonCode: api.reasonCode,
};
}
return {
...indeterminate('permission-evidence-disagrees'),
gitReasonCode: git.reasonCode,
apiReasonCode: api.reasonCode,
};
}
function filesBelow(root: string): string[] {
if (!existsSync(root)) return [];
const result: string[] = [];
const walk = (directory: string): void => {
for (const entry of readdirSync(directory, { withFileTypes: true })) {
const path = join(directory, entry.name);
if (entry.isDirectory()) walk(path);
else if (entry.isFile()) result.push(path);
else result.push(path);
}
};
walk(root);
return result.sort((left: string, right: string): number => left.localeCompare(right));
}
function ownerIsValid(
resolution: MigrationOwnerResolution,
lane: string,
laneActive: boolean,
): boolean {
if (
resolution.verdict !== 'resolved' ||
resolution.principal === null ||
resolution.authority === null ||
resolution.authority.endpoint.length === 0 ||
resolution.authority.contentType !== 'application/json'
) {
return false;
}
const principal = resolution.principal;
const normalized = principal.name.normalize('NFKC');
if (normalized !== principal.name) return false;
const grammars: Readonly<Record<string, RegExp>> = {
'active-lane': /^lane:[a-z0-9][a-z0-9-]*$/,
'durable-team': /^team:[a-z0-9][a-z0-9-]*$/,
'durable-human': /^user:[a-z0-9][a-z0-9-]*$/,
'durable-queue': /^queue:[a-z0-9][a-z0-9-]*$/,
};
const grammar = grammars[principal.kind];
if (grammar === undefined || !grammar.test(normalized)) return false;
if (principal.kind === 'active-lane') {
return laneActive && principal.name === `lane:${lane}`;
}
return true;
}
interface StableSourceSnapshot {
readonly content: Buffer;
readonly dev: number | bigint;
readonly ino: number | bigint;
readonly digest: string;
}
function stableSourceSnapshot(path: string): StableSourceSnapshot {
const descriptor = openSync(
path,
fsConstants.O_RDONLY | fsConstants.O_NONBLOCK | fsConstants.O_NOFOLLOW,
);
try {
const before = fstatSync(descriptor);
if (!before.isFile()) throw new Error('migration-source-not-regular');
const content = readFileSync(descriptor);
const after = fstatSync(descriptor);
if (
!after.isFile() ||
before.dev !== after.dev ||
before.ino !== after.ino ||
before.size !== after.size ||
before.mtimeMs !== after.mtimeMs ||
content.byteLength !== after.size
) {
throw new Error('migration-source-changed-during-read');
}
return {
content,
dev: after.dev,
ino: after.ino,
digest: createHash('sha256').update(content).digest('hex'),
};
} finally {
closeSync(descriptor);
}
}
function migrationCandidate(
sourceRoot: string,
brainRoot: string,
path: string,
kind: 'lane' | 'seat',
seat: string,
lane: string,
source: StableSourceSnapshot,
): MigrationCandidate {
const key = relative(sourceRoot, path).split(sep).join('/');
const digest = createHash('sha256')
.update(key)
.update('\0')
.update(source.content)
.digest('hex')
.slice(0, 16);
const name = `${digest}-${basename(path)}`;
const destination =
kind === 'lane'
? join(brainRoot, 'lanes', lane, 'findings', 'imports', name)
: join(brainRoot, 'agents', seat, 'state', 'imports', name);
return {
source: path,
destination,
archive: join(brainRoot, 'archives', 'imports', kind, name),
kind,
sourceIdentity: { dev: source.dev, ino: source.ino, digest: source.digest },
};
}
function secretShapedName(value: string): boolean {
const name = value.toLowerCase();
return (
['.npmrc', '.netrc', 'auth.json', '.dockerconfigjson'].includes(name) ||
name === '.env' ||
name.startsWith('.env.') ||
name === 'credentials.json' ||
name.startsWith('credentials.') ||
name === 'secret' ||
name.startsWith('secret.') ||
name === 'secrets' ||
name.startsWith('secrets.') ||
['id_rsa', 'id_dsa', 'id_ecdsa', 'id_ed25519'].includes(name) ||
['.token', '.key', '.pem', '.p12', '.pfx', '.jks', '.keystore'].some((suffix): boolean =>
name.endsWith(suffix),
)
);
}
function secretShapedPath(sourceRoot: string, path: string): boolean {
return relative(sourceRoot, path).split(sep).filter(Boolean).some(secretShapedName);
}
function sourceContainsSecretMaterial(content: Buffer): boolean {
if (content.byteLength > MAX_MIGRATION_FILE_BYTES || content.includes(0)) return true;
let source: string;
try {
source = new TextDecoder('utf-8', { fatal: true }).decode(content);
} catch {
return true;
}
return [
/-----BEGIN [^-\r\n]*PRIVATE KEY-----/i,
/\bauthorization\s*:\s*(?:bearer|basic)\s+\S+/i,
/\b(?:[a-z0-9_-]*(?:token|secret|password|passwd)|(?:x-)?api[_-]?key|aws_secret_access_key)\s*[:=]\s*\S+/i,
/\beyJ[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}\b/,
/https?:\/\/[^/\s:@]+:[^/\s@]+@/i,
/\b[A-Za-z0-9+/_=-]{40,}\b/,
].some((pattern): boolean => pattern.test(source));
}
function reportAll(paths: readonly string[], reason: string): MigrationReport[] {
return paths.map((path: string): MigrationReport => ({ path, reason }));
}
export function discoverBrainMigration(
input: {
readonly sourceRoot: string;
readonly brainRoot: string;
readonly seat: string;
readonly lane: string;
readonly laneActive: boolean;
},
resolveOwner?: (lane: string) => MigrationOwnerResolution,
approveContent?: (path: string, content: Uint8Array) => boolean,
): MigrationPlan {
const seat = safeName(input.seat, 'seat');
const lane = safeName(input.lane, 'lane');
const laneRoot = join(input.sourceRoot, 'lanes', lane);
const seatRoot = join(input.sourceRoot, 'agents', seat);
const laneFiles = filesBelow(laneRoot);
const seatFiles = filesBelow(seatRoot);
const selected = new Set([...laneFiles, ...seatFiles]);
const all = filesBelow(input.sourceRoot);
const unsupported = all.filter((path: string): boolean => !selected.has(path));
let ownerResolution: MigrationOwnerResolution = {
verdict: 'not-measured',
reasonCode: 'owner-resolver-unavailable',
principal: null,
authority: null,
};
if (resolveOwner !== undefined) {
try {
ownerResolution = resolveOwner(lane);
} catch {
ownerResolution = {
verdict: 'not-measured',
reasonCode: 'owner-resolver-failed',
principal: null,
authority: null,
};
}
}
if (!ownerIsValid(ownerResolution, lane, input.laneActive)) {
return {
status: 'blocked',
candidates: [],
reported: reportAll(
all,
'Migration requires a source-of-truth-resolved named durable owner; caller assertions are not evidence.',
),
owner: null,
};
}
const candidates: MigrationCandidate[] = [];
const reported: MigrationReport[] = reportAll(
unsupported,
'Ownership or supported migration shape was not established; retained and reported.',
);
for (const path of laneFiles) {
if (secretShapedPath(input.sourceRoot, path)) {
reported.push({
path,
reason: 'Secret-shaped state is forbidden in the brain; retained and reported.',
});
continue;
}
try {
const source = stableSourceSnapshot(path);
if (sourceContainsSecretMaterial(source.content)) throw new Error('migration-secret-content');
if (approveContent === undefined || !approveContent(path, Buffer.from(source.content))) {
throw new Error('migration-content-unapproved');
}
candidates.push(
migrationCandidate(input.sourceRoot, input.brainRoot, path, 'lane', seat, lane, source),
);
} catch (error: unknown) {
const code = error instanceof Error ? error.message : '';
reported.push({
path,
reason:
code === 'migration-secret-content'
? 'Content may contain secret material; retained and reported.'
: code === 'migration-content-unapproved'
? 'Approved secret scanner or content approval is unavailable; retained and reported.'
: 'Lane state was not a regular file; retained and reported.',
});
}
}
for (const path of seatFiles) {
if (secretShapedPath(input.sourceRoot, path)) {
reported.push({
path,
reason: 'Secret-shaped state is forbidden in the brain; retained and reported.',
});
continue;
}
try {
const source = stableSourceSnapshot(path);
if (sourceContainsSecretMaterial(source.content)) throw new Error('migration-secret-content');
if (approveContent === undefined || !approveContent(path, Buffer.from(source.content))) {
throw new Error('migration-content-unapproved');
}
candidates.push(
migrationCandidate(input.sourceRoot, input.brainRoot, path, 'seat', seat, lane, source),
);
} catch (error: unknown) {
const code = error instanceof Error ? error.message : '';
reported.push({
path,
reason:
code === 'migration-secret-content'
? 'Content may contain secret material; retained and reported.'
: code === 'migration-content-unapproved'
? 'Approved secret scanner or content approval is unavailable; retained and reported.'
: 'Seat state was not a regular file; retained and reported.',
});
}
}
return { status: 'ready', candidates, reported, owner: ownerResolution.principal };
}
function isContained(root: string, path: string): boolean {
const absoluteRoot = resolve(root);
const absolutePath = resolve(path);
return absolutePath === absoluteRoot || absolutePath.startsWith(`${absoluteRoot}${sep}`);
}
function assertSafeDestinationAncestors(root: string, destination: string): void {
if (!isContained(root, destination)) throw new Error('migration-destination-escaped-brain');
if (!existsSync(root)) mkdirSync(root, { recursive: true });
const rootStatus = lstatSync(root);
if (!rootStatus.isDirectory() || rootStatus.isSymbolicLink()) {
throw new Error('migration-destination-ancestor-unsafe');
}
const parts = relative(root, dirname(destination)).split(sep).filter(Boolean);
let cursor = root;
for (const part of parts) {
cursor = join(cursor, part);
if (!existsSync(cursor)) continue;
const status = lstatSync(cursor);
if (!status.isDirectory() || status.isSymbolicLink()) {
throw new Error('migration-destination-ancestor-unsafe');
}
}
}
function procDescriptorPath(descriptor: number, name: string): string {
return `/proc/self/fd/${descriptor}/${name}`;
}
function openDirectorySecure(directory: string): { readonly fd: number; readonly chain: number[] } {
if (platform() !== 'linux')
throw new Error('secure migration requires Linux descriptor traversal');
const chain: number[] = [];
try {
let descriptor = openSync(
sep,
fsConstants.O_RDONLY | fsConstants.O_DIRECTORY | fsConstants.O_NOFOLLOW,
);
chain.push(descriptor);
for (const component of resolve(directory).split(sep).filter(Boolean)) {
descriptor = openSync(
procDescriptorPath(descriptor, component),
fsConstants.O_RDONLY | fsConstants.O_DIRECTORY | fsConstants.O_NOFOLLOW,
);
if (!fstatSync(descriptor).isDirectory()) {
throw new Error('migration destination ancestor is not a directory');
}
chain.push(descriptor);
}
return { fd: descriptor, chain };
} catch (error: unknown) {
for (const descriptor of chain.reverse()) closeSync(descriptor);
throw error;
}
}
function closeDirectorySecure(chain: readonly number[]): void {
for (const descriptor of [...chain].reverse()) closeSync(descriptor);
}
function verifyHeldDestinationVisible(
heldPath: string,
visiblePath: string,
brainRoot: string,
): void {
assertSafeDestinationAncestors(brainRoot, visiblePath);
const held = lstatSync(heldPath);
const visible = lstatSync(visiblePath);
if (
!held.isFile() ||
held.isSymbolicLink() ||
!visible.isFile() ||
visible.isSymbolicLink() ||
held.dev !== visible.dev ||
held.ino !== visible.ino
) {
throw new Error('migration-destination-visibility-changed');
}
}
function sourceSnapshotMatches(
snapshot: StableSourceSnapshot,
identity: MigrationCandidate['sourceIdentity'],
): boolean {
return (
snapshot.dev === identity.dev &&
snapshot.ino === identity.ino &&
snapshot.digest === identity.digest
);
}
function copyVerified(
source: StableSourceSnapshot,
destination: string,
brainRoot: string,
hooks: MigrationHooks,
): boolean {
assertSafeDestinationAncestors(brainRoot, destination);
mkdirSync(dirname(destination), { recursive: true, mode: 0o700 });
assertSafeDestinationAncestors(brainRoot, destination);
const opened = openDirectorySecure(dirname(destination));
const name = basename(destination);
const heldDestination = procDescriptorPath(opened.fd, name);
const temporaryName = `.${name}.tmp-${process.pid}-${randomUUID()}`;
const heldTemporary = procDescriptorPath(opened.fd, temporaryName);
try {
hooks.beforeDestinationWrite?.(destination);
if (existsSync(heldDestination)) {
const status = lstatSync(heldDestination);
if (!status.isFile() || status.isSymbolicLink()) {
throw new Error('append-only-destination-unsafe');
}
const destinationDigest = createHash('sha256')
.update(readFileSync(heldDestination))
.digest('hex');
if (source.digest !== destinationDigest) throw new Error('append-only-collision');
verifyHeldDestinationVisible(heldDestination, destination, brainRoot);
return false;
}
writeFileSync(heldTemporary, source.content, { mode: 0o600, flag: 'wx' });
const temporaryStatus = lstatSync(heldTemporary);
if (!temporaryStatus.isFile() || temporaryStatus.isSymbolicLink()) {
throw new Error('migration-copy-target-unsafe');
}
syncFile(heldTemporary);
const copiedDigest = createHash('sha256').update(readFileSync(heldTemporary)).digest('hex');
if (source.digest !== copiedDigest) throw new Error('migration-copy-verification-failed');
linkSync(heldTemporary, heldDestination);
syncFile(heldDestination);
try {
verifyHeldDestinationVisible(heldDestination, destination, brainRoot);
} catch (error: unknown) {
unlinkSync(heldDestination);
throw error;
}
return true;
} finally {
rmSync(heldTemporary, { force: true });
closeDirectorySecure(opened.chain);
}
}
export function migrateBrainState(
plan: MigrationPlan,
publish: (
brainRoot: string,
entries: readonly MigrationPublishEntry[],
) => MigrationPublishEvidence,
brainRoot: string,
hooks: MigrationHooks = {},
): MigrationResult {
if (plan.status !== 'ready' || plan.candidates.length === 0) {
return {
status: 'reported',
migrated: [],
reported: plan.reported,
publish: null,
};
}
const created: string[] = [];
const published: MigrationPublishEntry[] = [];
let publicationAttempted = false;
let evidence: MigrationPublishEvidence;
try {
for (const candidate of plan.candidates) {
if (
!isContained(brainRoot, candidate.destination) ||
!isContained(brainRoot, candidate.archive)
) {
throw new Error('migration-destination-escaped-brain');
}
const source = stableSourceSnapshot(candidate.source);
if (!sourceSnapshotMatches(source, candidate.sourceIdentity)) {
throw new Error('migration-source-changed-before-copy');
}
if (copyVerified(source, candidate.destination, brainRoot, hooks)) {
created.push(candidate.destination);
}
if (copyVerified(source, candidate.archive, brainRoot, hooks)) {
created.push(candidate.archive);
}
published.push(
{ path: candidate.destination, content: Uint8Array.from(source.content) },
{ path: candidate.archive, content: Uint8Array.from(source.content) },
);
}
publicationAttempted = true;
evidence = publish(brainRoot, published);
if (!COMMIT.test(evidence.commit) || !COMMIT.test(evidence.remoteHead) || !evidence.reachable) {
throw new Error('remote reachability was not established');
}
} catch (error: unknown) {
// Once publication is attempted its remote mutation state may be unknown.
// Keep the local copies so the checkout does not silently diverge from a
// commit that may already be reachable; sources always remain intact.
if (!publicationAttempted) {
for (const path of created.reverse()) rmSync(path, { force: true });
}
const detail = error instanceof Error ? error.message : 'migration failed';
return {
status: 'failed',
migrated: [],
reported: [
...plan.reported,
...plan.candidates.map(
(candidate: MigrationCandidate): MigrationReport => ({
path: candidate.source,
reason: `Migration retained source: ${detail}`,
}),
),
],
publish: null,
};
}
const retentionReports = plan.candidates.map((candidate: MigrationCandidate): MigrationReport => {
hooks.beforeSourceCleanup?.(candidate.source);
return {
path: candidate.source,
reason:
'Published snapshot is remotely reachable; automatic path-based cleanup is unsafe, so Mosaic retained and reported the source.',
};
});
return {
status: 'reported',
migrated: [],
reported: [...plan.reported, ...retentionReports],
publish: evidence,
};
}
function accessFinding(access: CredentialAssessment | null): BrainDoctorFinding | null {
if (access === null) {
return {
code: 'brain-write-access-indeterminate',
repairable: false,
reasonCode: 'readback-missing',
};
}
if (access.outcome === 'ok') return null;
return {
code: `brain-write-access-${access.outcome}`,
repairable:
access.outcome === 'refused' &&
['permission-denied', 'no-token-for-identity'].includes(access.reasonCode),
reasonCode: access.reasonCode,
};
}
export function evaluateBrainDoctor(
observation: BrainDoctorObservation,
expectedRemote: string,
): readonly BrainDoctorFinding[] {
const access = accessFinding(observation.access);
if (!observation.rootExists) {
return [
{ code: 'brain-clone-missing', repairable: true, reasonCode: null },
...(access === null ? [] : [access]),
];
}
const findings: BrainDoctorFinding[] = [];
if (!observation.rootPrivate) {
findings.push({
code: 'brain-root-permissions-unsafe',
repairable: false,
reasonCode: 'owner-only-root-required',
});
}
if (!observation.gitRepository) {
findings.push({ code: 'brain-not-git-repository', repairable: true, reasonCode: null });
if (access !== null) findings.push(access);
return findings;
}
if (observation.remote === null) {
findings.push({
code: 'brain-git-state-indeterminate',
repairable: false,
reasonCode: 'remote-unmeasurable',
});
} else if (observation.remote !== expectedRemote) {
findings.push({ code: 'brain-remote-mismatch', repairable: true, reasonCode: null });
}
if (observation.branch === null) {
findings.push({
code: 'brain-git-state-indeterminate',
repairable: false,
reasonCode: 'branch-unmeasurable',
});
} else if (observation.branch !== 'main') {
findings.push({ code: 'brain-branch-mismatch', repairable: false, reasonCode: null });
}
if (observation.worktreeState === 'unmeasurable') {
findings.push({
code: 'brain-git-state-indeterminate',
repairable: false,
reasonCode: 'status-unmeasurable',
});
} else if (observation.worktreeState === 'dirty') {
findings.push({ code: 'brain-uncommitted-state', repairable: false, reasonCode: null });
}
if (access !== null) findings.push(access);
return findings;
}
export function planBrainDoctorFix(input: {
readonly findings: readonly BrainDoctorFinding[];
readonly target: BrainTarget;
readonly identity: string;
readonly root: string;
}): readonly BrainDoctorAction[] {
safeName(input.identity, 'identity');
const actions: BrainDoctorAction[] = [];
const priority: Readonly<Record<string, number>> = {
'brain-write-access-refused': 0,
'brain-clone-missing': 1,
'brain-remote-mismatch': 2,
};
const ordered = [...input.findings].sort(
(left: BrainDoctorFinding, right: BrainDoctorFinding): number =>
(priority[left.code] ?? 99) - (priority[right.code] ?? 99),
);
for (const finding of ordered) {
if (!finding.repairable) continue;
if (finding.code === 'brain-clone-missing') {
actions.push({
program: 'git',
args: ['clone', '--branch', 'main', '--single-branch', input.target.cloneUrl, input.root],
findingCode: finding.code,
});
} else if (finding.code === 'brain-remote-mismatch') {
actions.push({
program: 'git',
args: ['-C', input.root, 'remote', 'set-url', 'origin', input.target.cloneUrl],
findingCode: finding.code,
});
} else if (finding.code === 'brain-write-access-refused') {
actions.push({
program: 'mosaic',
args: [
'cred',
'grant',
input.identity,
'--estate',
input.target.estate,
'--host',
input.target.host,
'--repo',
input.target.repo,
'--permission',
'write',
'--json',
],
findingCode: finding.code,
});
}
}
return actions;
}
function safeRelativePath(path: string): string[] | null {
if (isAbsolute(path) || path.includes('\\')) return null;
const parts = path.split('/').filter((part: string): boolean => part.length > 0);
if (parts.length === 0 || parts.some((part: string): boolean => part === '.' || part === '..')) {
return null;
}
return parts;
}
export function classifyBrainWrite(input: {
readonly path: string;
readonly actor: string;
readonly seat: string;
readonly boardWriter?: string;
}): BrainWritePolicy {
const parts = safeRelativePath(input.path);
if (parts === null || !SAFE_NAME.test(input.actor) || !SAFE_NAME.test(input.seat)) {
return { allowed: false, mode: 'refused', reason: 'invalid-write-subject' };
}
if (parts[0] === 'lanes' && parts.length >= 3) {
return { allowed: true, mode: 'append-only', reason: 'lane-content-is-findings' };
}
if (parts[0] === 'board') {
if (input.boardWriter !== undefined && input.actor === input.boardWriter) {
return { allowed: true, mode: 'single-writer', reason: 'named-board-writer' };
}
return { allowed: false, mode: 'refused', reason: 'board-writer-mismatch' };
}
if (parts[0] === 'agents' && parts.length >= 3) {
if (parts[1] === input.seat && input.actor === input.seat) {
return { allowed: true, mode: 'seat-writer', reason: 'seat-owned-state' };
}
return { allowed: false, mode: 'refused', reason: 'seat-writer-mismatch' };
}
return { allowed: false, mode: 'refused', reason: 'unsupported-write-path' };
}