Files
stack/packages/mosaic/src/commands/brain-provision.spec.ts
T

551 lines
20 KiB
TypeScript

import { afterEach, describe, expect, it } from 'vitest';
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
interface CommandRequest {
readonly program: 'git' | 'mosaic';
readonly args: readonly string[];
readonly env: Readonly<Record<string, string>>;
}
interface CommandResult {
readonly status: number;
readonly stdout: string;
readonly stderr: string;
}
type CommandRunner = (request: CommandRequest) => CommandResult;
type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
interface ProvisionResult {
readonly status: 'provisioned' | 'blocked' | 'failed';
readonly reasonCode: string;
readonly findings: readonly { code: string; reasonCode: string | null }[];
readonly owner: {
readonly verdict: 'resolved' | 'refused' | 'not-measured';
readonly reasonCode: string;
} | null;
readonly migration: {
readonly status: 'migrated' | 'reported' | 'failed';
readonly reported: readonly { path: string; reason: string }[];
} | null;
}
interface ProvisionModule {
provisionBrain(
input: {
readonly estateRegistrySource: string;
readonly ownerPolicySource: string;
readonly targetGitUrl: string;
readonly requestedOwner: string;
readonly identity: string;
readonly refusalIdentity: string;
readonly root: string;
readonly sourceRoot: string;
readonly seat: string;
readonly lane: string;
readonly laneActive: boolean;
},
dependencies: {
readonly run: CommandRunner;
readonly fetch: FetchLike;
readonly absentControlName: () => string;
readonly approveMigrationContent?: (path: string, content: Uint8Array) => boolean;
},
): Promise<ProvisionResult>;
}
const MODULE_PATH = './brain-provision.js';
const roots: string[] = [];
async function loadProvisioner(requirement: string): Promise<ProvisionModule> {
try {
return (await import(MODULE_PATH)) as ProvisionModule;
} catch (error: unknown) {
const detail = error instanceof Error ? error.message : String(error);
throw new Error(`${requirement}: brain provisioner is absent (${detail})`);
}
}
function tempRoot(): string {
const root = mkdtempSync(join(tmpdir(), 'mosaic-brain-provision-'));
roots.push(root);
return root;
}
function estateRegistry(): string {
return JSON.stringify({
version: 1,
estates: [
{
name: 'homelab',
readOnlyControlIdentity: 'read-control',
hosts: [
{
host: 'git.example.invalid',
provider: 'gitea',
apiBaseUrl: 'https://git.example.invalid',
tokenPrefix: 'gitea-example',
},
],
},
],
});
}
function ownerPolicy(): string {
return JSON.stringify({
version: 1,
estates: [
{
estate: 'homelab',
laneArchiveOwners: [{ kind: 'provider-user', login: 'durable-owner' }],
standingProcess: { kind: 'glpi-queue', queue: 'mosaic-brain-remediation' },
controls: { publicIdentity: 'public-control', privateIdentity: 'private-control' },
},
],
});
}
function validateResult(
outcome: 'ok' | 'refused' | 'indeterminate',
reasonCode: string,
identity = 'seat-a',
): string {
const exitCode = outcome === 'ok' ? 0 : outcome === 'refused' ? 10 : 30;
return JSON.stringify({
schemaVersion: 1,
operation: 'validate',
outcome,
exitCode,
retryable: false,
subject: {
identity,
estate: 'homelab',
host: 'git.example.invalid',
repo: 'durable-owner/mosaic-brain',
},
mutation: 'none',
reason: { code: reasonCode, message: 'non-secret' },
evidence: {
providerIdentity:
outcome === 'ok'
? {
login: identity,
endpoint: 'GET /api/v1/user',
contentType: 'application/json',
}
: null,
repositoryPermission:
outcome === 'ok'
? {
requested: 'write',
effective: 'write',
endpoint: 'GET /api/v1/repos/durable-owner/mosaic-brain',
contentType: 'application/json',
}
: null,
writeDifferential:
outcome === 'ok'
? {
state: 'can-write',
credentialBinding: 'same-resolution',
transportPrincipal: identity,
authenticatedReceivePack: 'advertised',
readOnlyControl: {
identity: 'read-control',
providerPermission: 'read',
receivePack: 'refused',
},
unauthenticatedReceivePack: 'refused',
artifactCreated: false,
proves: 'non-secret evidence',
doesNotProve: 'branch update acceptance',
}
: null,
},
audit: { journalId: 'opaque', state: 'sealed' },
});
}
function publicUser(login: string): Response {
return new Response(JSON.stringify({ id: 1, login, visibility: 'public', active: false }), {
status: 200,
headers: { 'content-type': 'application/json' },
});
}
function ownerFetch(ownerStatus = 200): FetchLike {
return async (input): Promise<Response> => {
const raw = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
const identity = decodeURIComponent(new URL(raw).pathname.split('/').at(-1) ?? '');
if (identity === 'public-control') return publicUser(identity);
if (identity === 'private-control' || identity === 'generated-absent-control') {
return new Response(JSON.stringify({ message: 'hidden or absent' }), {
status: 404,
headers: { 'content-type': 'application/json' },
});
}
if (identity === 'durable-owner' && ownerStatus === 200) return publicUser(identity);
return new Response(JSON.stringify({ message: 'hidden or absent' }), {
status: ownerStatus,
headers: { 'content-type': 'application/json' },
});
};
}
function baseInput(root: string): {
readonly estateRegistrySource: string;
readonly ownerPolicySource: string;
readonly targetGitUrl: string;
readonly requestedOwner: string;
readonly identity: string;
readonly refusalIdentity: string;
readonly root: string;
readonly sourceRoot: string;
readonly seat: string;
readonly lane: string;
readonly laneActive: boolean;
} {
return {
estateRegistrySource: estateRegistry(),
ownerPolicySource: ownerPolicy(),
targetGitUrl: 'https://git.example.invalid/example/stack.git',
requestedOwner: 'user:durable-owner',
identity: 'seat-a',
refusalIdentity: 'outside-seat',
root: join(root, 'brain'),
sourceRoot: join(root, 'local-memory'),
seat: 'seat-a',
lane: 'lane-a',
laneActive: false,
};
}
afterEach((): void => {
for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true });
});
describe('P7 brain provisioning orchestration', (): void => {
it('requires the P5 write-capability postcondition and never grants or clones on refusal', async (): Promise<void> => {
const provisioner = await loadProvisioner('MB-REQ-10 P5 before P7');
const root = tempRoot();
const requests: CommandRequest[] = [];
const result = await provisioner.provisionBrain(baseInput(root), {
run: (request): CommandResult => {
requests.push(request);
return {
status: 10,
stdout: validateResult('refused', 'no-token-for-identity'),
stderr: 'refused reason=no-token-for-identity',
};
},
fetch: ownerFetch(),
absentControlName: (): string => 'generated-absent-control',
});
expect(result).toMatchObject({
status: 'blocked',
reasonCode: 'credential-postcondition-failed',
});
expect(requests).toHaveLength(1);
expect(requests[0]?.program).toBe('mosaic');
expect(requests[0]?.args.slice(0, 3)).toEqual(['cred', 'validate', 'seat-a']);
expect(requests.some((request) => request.args.includes('grant'))).toBe(false);
expect(requests.some((request) => request.args.includes('clone'))).toBe(false);
});
it('blocks before clone when the out-of-estate Git and API axes disagree', async (): Promise<void> => {
const provisioner = await loadProvisioner('MB-REQ-05 P7 refusal control gate');
const root = tempRoot();
const requests: CommandRequest[] = [];
const result = await provisioner.provisionBrain(baseInput(root), {
run: (request): CommandResult => {
requests.push(request);
if (request.program === 'mosaic' && request.args[2] === 'outside-seat') {
return {
status: 10,
stdout: validateResult('refused', 'no-token-for-identity', 'outside-seat'),
stderr: 'refused reason=no-token-for-identity',
};
}
if (request.program === 'mosaic') {
return { status: 0, stdout: validateResult('ok', 'validation-verified'), stderr: '' };
}
if (request.args.includes('ls-remote')) {
return { status: 0, stdout: 'refs are visible', stderr: '' };
}
return { status: 99, stdout: '', stderr: 'unexpected command' };
},
fetch: ownerFetch(),
absentControlName: (): string => 'generated-absent-control',
});
expect(result).toMatchObject({
status: 'blocked',
reasonCode: 'refusal-control-failed',
});
expect(requests.some((request) => request.args.includes('clone'))).toBe(false);
expect(requests.some((request) => request.args.includes('grant'))).toBe(false);
});
it('blocks before skeleton publication when the existing checkout is dirty', async (): Promise<void> => {
const provisioner = await loadProvisioner('MB-REQ-06 dirty checkout publication gate');
const root = tempRoot();
const input = baseInput(root);
mkdirSync(join(input.root, '.git'), { recursive: true });
const requests: CommandRequest[] = [];
const result = await provisioner.provisionBrain(input, {
run: (request): CommandResult => {
requests.push(request);
if (request.program === 'mosaic') {
return request.args[2] === 'outside-seat'
? {
status: 10,
stdout: validateResult('refused', 'no-token-for-identity', 'outside-seat'),
stderr: 'refused reason=no-token-for-identity',
}
: { status: 0, stdout: validateResult('ok', 'validation-verified'), stderr: '' };
}
const command = request.args.join(' ');
if (command.includes('ls-remote')) {
return {
status: 128,
stdout: '',
stderr: 'credential helper refused reason=no-token-for-identity',
};
}
if (command.includes('rev-parse --is-inside-work-tree')) {
return { status: 0, stdout: 'true\n', stderr: '' };
}
if (command.includes('remote get-url origin')) {
return {
status: 0,
stdout: 'https://git.example.invalid/durable-owner/mosaic-brain.git\n',
stderr: '',
};
}
if (command.includes('branch --show-current')) {
return { status: 0, stdout: 'main\n', stderr: '' };
}
if (command.includes('status --porcelain')) {
return { status: 0, stdout: '?? .gitignore\n', stderr: '' };
}
return { status: 99, stdout: '', stderr: 'unexpected publication command' };
},
fetch: ownerFetch(),
absentControlName: (): string => 'generated-absent-control',
});
expect(result).toMatchObject({
status: 'blocked',
reasonCode: 'brain-postcondition-failed',
});
expect(requests.some((request) => request.args.includes('commit'))).toBe(false);
expect(requests.some((request) => request.args.includes('push'))).toBe(false);
});
it('clones, seeds, resolves owner, migrates, pushes on each write, and archives source only after reachability', async (): Promise<void> => {
const provisioner = await loadProvisioner('MB-REQ-07 complete migration transaction');
const root = tempRoot();
const input = baseInput(root);
mkdirSync(join(input.sourceRoot, 'lanes', 'lane-a'), { recursive: true });
const source = join(input.sourceRoot, 'lanes', 'lane-a', 'finding.md');
writeFileSync(source, 'durable finding\n');
const requests: CommandRequest[] = [];
let commitOrdinal = 0;
let approvedPaths: string[] = [];
const runner: CommandRunner = (request): CommandResult => {
requests.push(request);
if (request.program === 'mosaic') {
if (request.args[2] === 'outside-seat') {
return {
status: 10,
stdout: validateResult('refused', 'no-token-for-identity', 'outside-seat'),
stderr: 'refused reason=no-token-for-identity',
};
}
return { status: 0, stdout: validateResult('ok', 'validation-verified'), stderr: '' };
}
const command = request.args.join(' ');
if (command.includes('ls-remote')) {
return {
status: 128,
stdout: '',
stderr: 'credential helper refused reason=no-token-for-identity',
};
}
if (request.args[0] === 'clone') {
mkdirSync(join(input.root, '.git'), { recursive: true });
return { status: 0, stdout: '', stderr: '' };
}
if (command.includes('read-tree')) {
approvedPaths = [];
return { status: 0, stdout: '', stderr: '' };
}
if (command.includes('hash-object')) {
return { status: 0, stdout: `${'f'.repeat(40)}\n`, stderr: '' };
}
if (command.includes('update-index')) {
const path = request.args.at(-1);
if (path !== undefined) approvedPaths.push(path);
return { status: 0, stdout: '', stderr: '' };
}
if (command.includes('rev-parse') && request.args.at(-1)?.includes(':')) {
return { status: 0, stdout: `${'f'.repeat(40)}\n`, stderr: '' };
}
if (command.includes('diff --cached --quiet')) {
return { status: 1, stdout: '', stderr: '' };
}
if (command.includes('diff-tree')) {
return { status: 0, stdout: `${approvedPaths.join('\0')}\0`, stderr: '' };
}
if (command.includes('show -s')) {
return {
status: 0,
stdout: 'seat-a\[email protected]\0seat-a\[email protected]\n',
stderr: '',
};
}
if (command.includes('rev-parse --is-inside-work-tree')) {
return { status: 0, stdout: 'true\n', stderr: '' };
}
if (command.includes('remote get-url origin')) {
return {
status: 0,
stdout: 'https://git.example.invalid/durable-owner/mosaic-brain.git\n',
stderr: '',
};
}
if (command.includes('branch --show-current')) {
return { status: 0, stdout: 'main\n', stderr: '' };
}
if (command.includes('status --porcelain')) {
return { status: 0, stdout: '', stderr: '' };
}
if (command.includes('rev-parse HEAD')) {
commitOrdinal += 1;
return {
status: 0,
stdout: `${commitOrdinal === 1 ? 'a' : 'c'.repeat(1)}`.repeat(40) + '\n',
stderr: '',
};
}
if (command.includes('rev-parse origin/main')) {
const value = commitOrdinal === 1 ? 'b' : 'd';
return { status: 0, stdout: `${value.repeat(40)}\n`, stderr: '' };
}
return { status: 0, stdout: '', stderr: '' };
};
const result = await provisioner.provisionBrain(input, {
run: runner,
fetch: ownerFetch(),
absentControlName: (): string => 'generated-absent-control',
approveMigrationContent: (): boolean => true,
});
expect(result).toMatchObject({
status: 'provisioned',
reasonCode: 'brain-provisioned',
owner: { verdict: 'resolved', reasonCode: 'owner-verified' },
migration: { status: 'reported' },
});
expect(existsSync(source)).toBe(true);
const imported = result.migration?.reported ?? [];
expect(imported).toEqual(
expect.arrayContaining([
expect.objectContaining({ path: source, reason: expect.stringMatching(/retained/i) }),
]),
);
const laneImports = join(input.root, 'lanes', 'lane-a', 'findings', 'imports');
const archiveImports = join(input.root, 'archives', 'imports', 'lane');
expect(existsSync(laneImports)).toBe(true);
expect(existsSync(archiveImports)).toBe(true);
expect(
requests.filter((request) => request.program === 'git' && request.args.includes('push')),
).toHaveLength(2);
expect(requests.some((request) => request.args.includes('grant'))).toBe(false);
});
it('keeps every source and reports the owner ambiguity when the public owner cannot be resolved', async (): Promise<void> => {
const provisioner = await loadProvisioner('MB-REQ-07 owner-blocked detection/reporting');
const root = tempRoot();
const input = baseInput(root);
mkdirSync(input.root, { recursive: true });
mkdirSync(join(input.root, '.git'), { recursive: true });
mkdirSync(join(input.sourceRoot, 'lanes', 'lane-a'), { recursive: true });
const source = join(input.sourceRoot, 'lanes', 'lane-a', 'finding.md');
writeFileSync(source, 'retain me\n');
let commitOrdinal = 0;
const result = await provisioner.provisionBrain(input, {
run: (request): CommandResult => {
if (request.program === 'mosaic') {
if (request.args[2] === 'outside-seat') {
return {
status: 10,
stdout: validateResult('refused', 'no-token-for-identity', 'outside-seat'),
stderr: 'refused reason=no-token-for-identity',
};
}
return { status: 0, stdout: validateResult('ok', 'validation-verified'), stderr: '' };
}
const command = request.args.join(' ');
if (command.includes('ls-remote')) {
return {
status: 128,
stdout: '',
stderr: 'credential helper refused reason=no-token-for-identity',
};
}
if (command.includes('rev-parse --is-inside-work-tree')) {
return { status: 0, stdout: 'true\n', stderr: '' };
}
if (command.includes('remote get-url origin')) {
return {
status: 0,
stdout: 'https://git.example.invalid/durable-owner/mosaic-brain.git\n',
stderr: '',
};
}
if (command.includes('branch --show-current')) {
return { status: 0, stdout: 'main\n', stderr: '' };
}
if (command.includes('status --porcelain')) {
return { status: 0, stdout: '', stderr: '' };
}
if (command.includes('rev-parse HEAD')) {
commitOrdinal += 1;
return { status: 0, stdout: `${'a'.repeat(40)}\n`, stderr: '' };
}
if (command.includes('rev-parse origin/main')) {
return { status: 0, stdout: `${'b'.repeat(40)}\n`, stderr: '' };
}
return { status: 0, stdout: '', stderr: '' };
},
fetch: ownerFetch(404),
absentControlName: (): string => 'generated-absent-control',
});
expect(result).toMatchObject({
status: 'blocked',
reasonCode: 'owner-not-resolvable',
owner: { verdict: 'not-measured', reasonCode: 'owner-not-resolvable' },
migration: { status: 'reported' },
});
expect(readFileSync(source, 'utf8')).toBe('retain me\n');
expect(result.migration?.reported).toEqual(
expect.arrayContaining([
expect.objectContaining({ path: source, reason: expect.stringMatching(/owner/i) }),
]),
);
expect(JSON.stringify(result)).not.toMatch(/owner-not-found|does-not-exist/);
expect(commitOrdinal).toBe(0);
});
});