feat: add scoped image sync endpoint

This commit is contained in:
2026-08-06 14:58:41 +00:00
parent 5078f6f3b1
commit 2fb618aa5c
11 changed files with 229 additions and 6 deletions
+37 -2
View File
@@ -35,8 +35,8 @@ function parseJson(body) {
}
}
export async function createApp(config = loadConfig()) {
const service = new GitService(config);
export async function createApp(config = loadConfig(), dependencies = {}) {
const service = dependencies.service ?? new GitService(config);
await service.initialize();
const server = createServer(async (request, response) => {
@@ -100,6 +100,41 @@ export async function createApp(config = loadConfig()) {
const result = await service.deployAdmin({ requestId, branch: payload.branch, expectedCommit: payload.commit });
return json(response, 200, { ok: true, ...result });
}
if (request.method === 'POST' && url.pathname === '/v1/sync') {
if (!request.headers['content-type']?.toLowerCase().startsWith('application/json')) {
throw new DeploymentError('Content-Type must be application/json', 415);
}
const body = await readBody(request, config.maxBodyBytes);
const client = request.headers['x-image-client'];
const timestamp = request.headers['x-image-timestamp'];
const requestId = request.headers['x-image-request-id'];
const knownClient = typeof client === 'string'
&& Object.hasOwn(config.syncClientSecrets, client);
const signatureValid = verifyAdminSignature({
secret: knownClient ? config.syncClientSecrets[client] : 'invalid-client-secret'.padEnd(32, '!'),
timestamp,
requestId,
body,
supplied: request.headers['x-image-signature'],
});
if (!knownClient || !signatureValid) {
return json(response, 401, { ok: false, reason: 'invalid sync signature' });
}
const payload = parseJson(body);
if (!payload || Array.isArray(payload) || typeof payload !== 'object'
|| Object.keys(payload).some((key) => key !== 'commit')) {
throw new DeploymentError('Sync body may only contain commit', 400);
}
if (payload.commit !== undefined
&& (typeof payload.commit !== 'string' || !/^[0-9a-f]{40,64}$/i.test(payload.commit))) {
throw new DeploymentError('Invalid target commit', 400);
}
const result = await service.deploySync({
requestKey: `${client}:${requestId}`,
expectedCommit: payload.commit,
});
return json(response, 200, { ok: true, ...result });
}
return json(response, 404, { ok: false, reason: 'not found' });
} catch (error) {
await service.recordError(error).catch(() => undefined);