Rocko's round 2 candidate, approved by Darkwing (#1519 comment 26757).
build.patch 40d7e838, manifest 61519059, 24 files under packages/bus,
schema v3b (179ffe35, lead decision 60). Integration gate in a git
worktree of 942dca9e (S1 in the tree) plus the patch: bus 43/43 and
business 60/60 on Node 24 and 26, every package test and every
scripts/test-*.sh green, test-task 98/98 with the live-provider cases.
Rulings from lead decisions 62 and 63: the human proof is cooperative in
slice 1, and a self-raised cross-role decision routes to the human.
Single-use gated approvals follow in row 43.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
113 lines
4.3 KiB
JavaScript
113 lines
4.3 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { mkdtempSync, writeFileSync, chmodSync, symlinkSync, rmSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
const { Credentials } = await import('../src/credentials.mjs').catch((e) => {
|
|
if (e.code === 'ERR_MODULE_NOT_FOUND') return {};
|
|
throw e;
|
|
});
|
|
function fixture(t) {
|
|
assert.equal(typeof Credentials, 'function');
|
|
const root = mkdtempSync(join(tmpdir(), 'bus-token-'));
|
|
t.after(() => rmSync(root, { recursive: true, force: true }));
|
|
const token = 'fixture_only_0123456789abcdef';
|
|
const path = join(root, 'token');
|
|
writeFileSync(path, token + '\n', { mode: 0o600 });
|
|
return { root, path, token, ref: { file: path, rotateBy: '2099-01-01' } };
|
|
}
|
|
test('only validated broker references load; returned data and exceptions cannot expose a known token', async (t) => {
|
|
const { ref, token } = fixture(t);
|
|
const c = new Credentials({
|
|
references: { coder: { gitea: ref } },
|
|
repoRoots: [],
|
|
dataRoot: '/nonexistent-data',
|
|
});
|
|
assert.equal(
|
|
await c.use('coder', 'gitea', async (value) => ({ matches: value === token })).then((x) => x.matches),
|
|
true,
|
|
);
|
|
await assert.rejects(
|
|
c.use('coder', 'gitea', async (value) => ({ echo: value })),
|
|
/credential-leak/,
|
|
);
|
|
await assert.rejects(
|
|
c.use('coder', 'gitea', async (value) => {
|
|
throw Error(value);
|
|
}),
|
|
/service-failed/,
|
|
);
|
|
assert.throws(() => c.assertClean({ [token]: 'x' }), /credential-leak/);
|
|
assert.throws(() => c.assertClean({ nested: ['prefix ' + token] }), /credential-leak/);
|
|
c.close();
|
|
await assert.rejects(
|
|
c.use('coder', 'gitea', () => true),
|
|
/credential-unavailable/,
|
|
);
|
|
});
|
|
test('bad file modes, symlinks, repository/data paths, malformed tokens and missing dates refuse', (t) => {
|
|
const { path, root, ref } = fixture(t);
|
|
const create = (r = ref, extra = {}) =>
|
|
new Credentials({ references: { coder: { gitea: r } }, repoRoots: [], dataRoot: '/no-data', ...extra });
|
|
chmodSync(path, 0o644);
|
|
assert.throws(() => create(), /credential-file/);
|
|
chmodSync(path, 0o600);
|
|
const link = join(root, 'link');
|
|
symlinkSync(path, link);
|
|
assert.throws(() => create({ ...ref, file: link }), /credential-file/);
|
|
assert.throws(() => create(ref, { repoRoots: [root] }), /credential-location/);
|
|
assert.throws(() => create(ref, { dataRoot: root }), /credential-location/);
|
|
assert.throws(() => create({ file: path }), /credential-date/);
|
|
for (const value of ['', 'value\nsecond', 'value\r\n', 'space value', '"value"']) {
|
|
writeFileSync(path, value);
|
|
assert.throws(() => create(), /credential-format/);
|
|
}
|
|
});
|
|
test('expiry refuses use and env references never become client data', async (t) => {
|
|
fixture(t);
|
|
const c = new Credentials({
|
|
references: { coder: { vikunja: { env: 'FIXTURE_BUS_TOKEN', expires: '2000-01-01' } } },
|
|
env: { FIXTURE_BUS_TOKEN: 'fixture_expired_0123456789' },
|
|
repoRoots: [],
|
|
dataRoot: '/no-data',
|
|
});
|
|
await assert.rejects(
|
|
c.use('coder', 'vikunja', () => true),
|
|
/credential-expired/,
|
|
);
|
|
await assert.rejects(
|
|
c.use('pm', 'vikunja', () => true),
|
|
/credential-unavailable/,
|
|
);
|
|
});
|
|
test('S1 parsed service refs work, service mismatch refuses, Gitea rotation due is a warning state', async (t) => {
|
|
const { ref } = fixture(t);
|
|
const c = new Credentials({
|
|
references: { coder: { gitea: { ...ref, service: 'gitea', rotateBy: '2000-01-01' } } },
|
|
});
|
|
assert.equal(await c.use('coder', 'gitea', () => true), true);
|
|
assert.deepEqual(c.status(), [
|
|
{ instance: 'coder', service: 'gitea', date: '2000-01-01', state: 'rotation-due' },
|
|
]);
|
|
assert.throws(
|
|
() => new Credentials({ references: { coder: { gitea: { ...ref, service: 'vikunja' } } } }),
|
|
/credential-reference/,
|
|
);
|
|
});
|
|
test('opaque tokens shorter than 16 characters refuse before use', () => {
|
|
for (const value of ['a', 'a'.repeat(15), 'a'.repeat(15) + '\n'])
|
|
assert.throws(
|
|
() =>
|
|
new Credentials({
|
|
references: { coder: { gitea: { env: 'FIXTURE_TOKEN', rotateBy: '2099-01-01' } } },
|
|
env: { FIXTURE_TOKEN: value },
|
|
}),
|
|
/credential-format/,
|
|
);
|
|
const c = new Credentials({
|
|
references: { coder: { gitea: { env: 'FIXTURE_TOKEN', rotateBy: '2099-01-01' } } },
|
|
env: { FIXTURE_TOKEN: 'a'.repeat(16) },
|
|
});
|
|
c.close();
|
|
});
|