36 lines
2.5 KiB
JavaScript
36 lines
2.5 KiB
JavaScript
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, readFileSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
const secret = 'sk-test-NOT-A-SECRET-1234';
|
|
function scratch(t) { const root = mkdtempSync(join(tmpdir(), 'r4-')); t.after(() => rmSync(root, { recursive: true, force: true })); return root; }
|
|
function safe(label, Type, props = {}, omitted = secret) { return error => {
|
|
assert.ok(error instanceof Type, error.stack);
|
|
for (const [key, value] of Object.entries(props)) assert.equal(error[key], value);
|
|
assert.ok(error.message.includes(label), error.message);
|
|
assert.doesNotMatch(error.message + error.stack, /sk-test|NOT-A-SECRET|Unexpected token/);
|
|
assert.ok(!error.message.includes(omitted), error.message);
|
|
assert.equal(error.cause, undefined);
|
|
return true;
|
|
}; }
|
|
import { loadInterviewTemplate, OnboardingError } from '../src/onboarding.mjs';
|
|
import { initProject, writeRecord, ProjectError } from '../src/index.mjs';
|
|
test('onboarding template parser omits file bytes and keeps its code', t => {
|
|
const file = join(scratch(t), 'template.json'); writeFileSync(file, secret);
|
|
assert.throws(() => loadInterviewTemplate(file), safe(file, OnboardingError, { code: 'onboarding-template-invalid', stage: 'check' }));
|
|
});
|
|
test('project nonobject record already reports only its type (BASE control)', async t => {
|
|
const root = scratch(t), context = { business: { id: 'acme', human: 'jason', projects: { stack: { root: join(root, 'code') } } }, project: 'stack', dataRoot: join(root, 'data') };
|
|
await initProject(context);
|
|
await assert.rejects(() => writeRecord({ ...context, path: 'requirements/REQ-1.json', record: JSON.stringify(secret), author: { name: 'Tester', email: '[email protected]' } }), safe('object', ProjectError, { code: 'project-record-invalid' }));
|
|
});
|
|
import { INTERVIEW_TEMPLATE_URL } from '../src/onboarding.mjs';
|
|
for (const at of ['question', 'placeholder']) test(`template ${at} semantic refusal omits its value`, t => {
|
|
const d = JSON.parse(readFileSync(INTERVIEW_TEMPLATE_URL, 'utf8'));
|
|
if (at === 'question') { d.questions[0].key = secret.toLowerCase(); d.questions[1].key = secret.toLowerCase(); }
|
|
else d.prompt.push(`{${secret}}`);
|
|
const file = join(scratch(t), 'template.json'); writeFileSync(file, JSON.stringify(d));
|
|
assert.throws(() => loadInterviewTemplate(file), safe(at === 'question' ? 'questions[1].key' : 'placeholder', OnboardingError, { code: 'onboarding-template-invalid' }, secret.toLowerCase()));
|
|
});
|