forked from devsam/image
feat: add scoped image sync endpoint
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user