Files
core2026/tools/sync-image-repository.test.mjs
T

68 lines
2.7 KiB
JavaScript

import { createHmac } from 'node:crypto';
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import test from 'node:test';
import assert from 'node:assert/strict';
import { syncImageRepository } from './sync-image-repository.mjs';
test('signs a scoped Core2026 fallback sync without exposing the secret', async (t) => {
const directory = await mkdtemp(path.join(tmpdir(), 'sammo-image-sync-'));
t.after(() => rm(directory, { recursive: true, force: true }));
const secretFile = path.join(directory, 'secret');
const secret = 's'.repeat(32);
await writeFile(secretFile, `${secret}\n`, { mode: 0o600 });
let captured;
const result = await syncImageRepository({
baseUrl: 'https://sam-image.hided.net/',
secretFile,
commit: 'a'.repeat(40),
now: () => Date.parse('2026-08-08T00:00:00Z'),
requestIdFactory: () => 'request-1',
fetchImpl: async (url, init) => {
captured = { url, init };
return new Response(JSON.stringify({ ok: true, changed: false }), { status: 200 });
},
});
assert.deepEqual(result, { ok: true, changed: false });
assert.equal(captured.url, 'https://sam-image.hided.net/v1/sync');
assert.equal(captured.init.body, JSON.stringify({ commit: 'a'.repeat(40) }));
assert.equal(captured.init.headers['x-image-client'], 'core2026');
assert.equal(
captured.init.headers['x-image-signature'],
createHmac('sha256', secret)
.update(`${captured.init.headers['x-image-timestamp']}.request-1.${captured.init.body}`)
.digest('hex')
);
assert.equal(Object.values(captured.init.headers).includes(secret), false);
});
test('rejects invalid commits before reading the secret or making a request', async () => {
await assert.rejects(
syncImageRepository({
secretFile: '/does/not/exist',
commit: 'main',
fetchImpl: async () => {
throw new Error('must not fetch');
},
}),
/Commit must be a full/
);
});
test('reports authentication failures without returning a response body', async (t) => {
const directory = await mkdtemp(path.join(tmpdir(), 'sammo-image-sync-'));
t.after(() => rm(directory, { recursive: true, force: true }));
const secretFile = path.join(directory, 'secret');
await writeFile(secretFile, 's'.repeat(32), { mode: 0o600 });
await assert.rejects(
syncImageRepository({
secretFile,
fetchImpl: async () => new Response('{"reason":"sensitive detail"}', { status: 401 }),
}),
/HTTP 401/
);
});