mirror of
https://github.com/ruvnet/RuView
synced 2026-07-29 18:31:44 +00:00
2b7853b18f
* feat(ruview): add secure community metaharness flywheel * fix(ruview): canonicalize manifest line endings
53 lines
3.6 KiB
JavaScript
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);
|
|
});
|