Files
ruvnet--RuView/harness/ruview/test/hosts.test.mjs
T
rUv 2b7853b18f feat(ruview): secure community metaharness flywheel (#1467)
* feat(ruview): add secure community metaharness flywheel

* fix(ruview): canonicalize manifest line endings
2026-07-28 23:57:16 -04:00

53 lines
3.6 KiB
JavaScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import { runClaudeCode, buildClaudeCodeArgs } from '../src/hosts/claude-code.js';
import { runCodex, buildCodexArgs } from '../src/hosts/codex.js';
import { runProcess, scrubEnvironment } from '../src/process-runner.js';
import { redact } from '../src/redact.js';
import { assertTrustedRuViewRepo } from '../src/repo-trust.js';
function fixture() {
const dir = mkdtempSync(join(tmpdir(), 'ruview-hosts-'));
mkdirSync(join(dir, '.git')); mkdirSync(join(dir, 'v2')); mkdirSync(join(dir, 'firmware'));
writeFileSync(join(dir, 'README.md'), '# RuView\nWiFi DensePose repository\n');
const cli = join(dir, 'fake-cli.mjs');
writeFileSync(cli, `let input='';process.stdin.setEncoding('utf8');for await(const chunk of process.stdin)input+=chunk;process.stdout.write(JSON.stringify({argv:process.argv.slice(2),input,cwd:process.cwd(),secret:process.env.TEST_SECRET}));`);
return { dir, cli };
}
test('redacts common and environment-provided secrets', () => {
const clean = redact('Authorization: Bearer abc.def password=hunter2 key=sk-super-secret-value', { env: { OPENAI_API_KEY: 'sk-super-secret-value' } });
assert.doesNotMatch(clean, /abc\.def|hunter2|super-secret/);
});
test('environment is an explicit allowlist', () => {
assert.deepEqual(scrubEnvironment({ PATH: 'ok', TEST_SECRET: 'no', HOME: 'yes' }), { PATH: 'ok', HOME: 'yes' });
});
test('trust preflight rejects a different anchor', () => {
const { dir } = fixture(); const other = mkdtempSync(join(tmpdir(), 'ruview-anchor-'));
try { assert.equal(assertTrustedRuViewRepo(dir), dir); assert.throws(() => assertTrustedRuViewRepo(dir, { trustedRoot: other }), /trusted root/); }
finally { rmSync(dir, { recursive: true, force: true }); rmSync(other, { recursive: true, force: true }); }
});
test('Claude adapter sends prompt over stdin in plan mode', async () => {
const { dir, cli } = fixture();
try {
const seen = JSON.parse((await runClaudeCode({ prompt: 'inspect only', repoRoot: dir, command: process.execPath, commandArgs: [cli], env: { ...process.env, TEST_SECRET: 'must-not-leak' } })).stdout);
assert.equal(seen.input, 'inspect only'); assert.equal(seen.secret, undefined); assert.deepEqual(seen.argv, buildClaudeCodeArgs());
} finally { rmSync(dir, { recursive: true, force: true }); }
});
test('Codex adapter uses exec stdin and read-only ephemeral JSON mode', async () => {
const { dir, cli } = fixture();
try {
const seen = JSON.parse((await runCodex({ prompt: 'map the repository', repoRoot: dir, command: process.execPath, commandArgs: [cli] })).stdout);
assert.equal(seen.input, 'map the repository'); assert.deepEqual(seen.argv, buildCodexArgs(dir)); assert.equal(seen.cwd, dir);
} finally { rmSync(dir, { recursive: true, force: true }); }
});
test('write mode maps to explicit host write policies', () => {
assert.ok(buildClaudeCodeArgs({ write: false }).includes('plan')); assert.ok(buildClaudeCodeArgs({ write: true }).includes('acceptEdits'));
assert.ok(buildCodexArgs('X', { write: false }).includes('read-only')); assert.ok(buildCodexArgs('X', { write: true }).includes('workspace-write'));
});
test('runner bounds output and times out', async () => {
await assert.rejects(runProcess(process.execPath, ['-e', 'process.stdout.write("x".repeat(200))'], { maxOutputBytes: 32 }), (error) => error.truncated);
await assert.rejects(runProcess(process.execPath, ['-e', 'setTimeout(() => {}, 10000)'], { timeoutMs: 20 }), (error) => error.timedOut);
});