← back to Secrets Manager
test/verify-all.test.js
120 lines
'use strict';
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { boundedVerify, buildVerifyAllReport, cmdVerifyAll, main } = require('../cli.js');
const routes = {
_comment: { text: 'metadata is not a secret' },
leak_patterns: [{ regex: 'unused' }],
services: {
GOOD_KEY: { verify: { url: 'https://unused.test' } },
BAD_KEY: { verify: { url: 'https://unused.test' } },
MANUAL_KEY: { label: 'manual only' },
MISSING_KEY: { verify: { url: 'https://unused.test' } },
},
};
const master = { GOOD_KEY: 'secret-good', BAD_KEY: 'secret-bad', MANUAL_KEY: 'secret-manual' };
test('builds a deterministic FAIL report without retaining secret values or response bodies', async () => {
const seen = [];
const report = await buildVerifyAllReport({
master, routes, now: new Date('2026-08-29T05:20:00Z'),
verifier: async (key, value) => {
seen.push([key, value]);
return key === 'GOOD_KEY' ? { ok: true, status: 200, body: value } : { ok: false, status: 401, body: value };
},
});
assert.equal(report.status, 'FAIL');
assert.deepEqual(report.summary, { total: 4, PASS: 1, WARN: 1, FAIL: 2 });
assert.deepEqual(seen.map(([key]) => key), ['BAD_KEY', 'GOOD_KEY']);
const serialized = JSON.stringify(report);
assert.doesNotMatch(serialized, /secret-good|secret-bad|secret-manual/);
assert.doesNotMatch(serialized, /body/);
assert.equal(report.generated_at, '2026-08-29T05:20:00.000Z');
});
test('status is WARN for unverified keys and PASS when every configured key verifies', async () => {
const warn = await buildVerifyAllReport({ master: { MANUAL_KEY: 'x' }, routes: { services: { MANUAL_KEY: {} } } });
assert.equal(warn.status, 'WARN');
const pass = await buildVerifyAllReport({
master: { GOOD_KEY: 'x' }, routes: { services: { GOOD_KEY: { verify: {} } } },
verifier: async () => ({ ok: true, status: 204 }),
});
assert.equal(pass.status, 'PASS');
});
test('writes the latest report atomically for local consumers without network calls', async (t) => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'secret-freshness-'));
t.after(() => fs.rmSync(dir, { recursive: true, force: true }));
const outputPath = path.join(dir, 'data', 'latest.json');
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, '{}\n', { mode: 0o644 });
const report = await cmdVerifyAll({
master: { GOOD_KEY: 'x' }, routes: { services: { GOOD_KEY: { verify: {} } } },
verifier: async () => ({ ok: true, status: 200 }), outputPath,
now: new Date('2026-08-29T05:21:00Z'),
});
assert.equal(report.status, 'PASS');
assert.deepEqual(JSON.parse(fs.readFileSync(outputPath, 'utf8')), report);
assert.equal(fs.statSync(outputPath).mode & 0o777, 0o600);
});
test('timeouts, throws, and malformed results fail safely while later checks continue', async () => {
const calls = [];
const allRoutes = { services: Object.fromEntries(['A_TIMEOUT', 'B_THROW', 'C_UNDEFINED', 'D_MALFORMED', 'E_PASS']
.map((key) => [key, { verify: {} }])) };
const allMaster = Object.fromEntries(Object.keys(allRoutes.services).map((key) => [key, `value-${key}`]));
const report = await buildVerifyAllReport({
master: allMaster, routes: allRoutes, timeoutMs: 5,
verifier: async (key) => {
calls.push(key);
if (key === 'A_TIMEOUT') return new Promise(() => {});
if (key === 'B_THROW') throw new Error('secret value-B_THROW');
if (key === 'C_UNDEFINED') return undefined;
if (key === 'D_MALFORMED') return { ok: 'yes', body: 'secret malformed body' };
return { ok: true, status: 200, body: 'secret body' };
},
});
assert.deepEqual(calls, ['A_TIMEOUT', 'B_THROW', 'C_UNDEFINED', 'D_MALFORMED', 'E_PASS']);
assert.deepEqual(report.checks.map((check) => check.reason || 'pass'),
['timeout', 'verifier-error', 'malformed-result', 'malformed-result', 'pass']);
assert.equal(report.status, 'FAIL');
assert.doesNotMatch(JSON.stringify(report), /value-|secret body|B_THROW.*secret/);
});
test('blank secrets count as missing and CLI exit code fails only aggregate FAIL', async (t) => {
const base = fs.mkdtempSync(path.join(os.tmpdir(), 'secret-exit-'));
t.after(() => fs.rmSync(base, { recursive: true, force: true }));
const run = (name, masterValue, route, verifier) => main(['verify-all'], { verifyAllOptions: {
master: { TEST_KEY: masterValue }, routes: { services: { TEST_KEY: route } }, verifier,
outputPath: path.join(base, `${name}.json`), timeoutMs: 5,
} });
assert.equal(await run('fail', ' ', { verify: {} }, async () => ({ ok: true })), 1);
assert.equal(await run('warn', 'value', {}, async () => ({ ok: true })), 0);
assert.equal(await run('pass', 'value', { verify: {} }, async () => ({ ok: true, status: 200 })), 0);
});
test('allowlists verifier output fields and rejects hostile timeout configuration', async () => {
const marker = 'token-do-not-leak';
for (const result of [
{ ok: false, reason: marker },
{ ok: false, status: { credential: marker } },
{ ok: true, status: { body: marker } },
{ ok: false, reason: { body: marker } },
]) {
const normalized = await boundedVerify(async () => result, 'TEST_KEY', 'secret', 5);
assert.doesNotMatch(JSON.stringify(normalized), new RegExp(marker));
assert.ok(normalized.status === null || normalized.status === undefined);
if (!normalized.ok) assert.match(normalized.reason, /^(provider-rejected|network-error)$/);
}
for (const timeoutMs of [0, -1, NaN, Infinity, 60001, 1.5]) {
const normalized = await boundedVerify(async () => ({ ok: true, status: 204 }), 'TEST_KEY', 'secret', timeoutMs);
assert.deepEqual(normalized, { ok: true, status: 204 });
}
});