feat(server): test-only seed-peer route gated by NODE_ENV+ENABLE_TEST_ROUTES

This commit is contained in:
Jannis Braun
2026-05-03 22:59:46 +02:00
parent 3dbf4dab5e
commit 03165a3b7d
+46
View File
@@ -355,4 +355,50 @@ export async function adminRoutes(app: FastifyInstance): Promise<void> {
return reply.code(200).send({ success: true });
},
);
// Test-only: seed federation_peers row directly. STRICTLY gated by NODE_ENV='test'
// AND ENABLE_TEST_ROUTES='1'. Returns 404 in any other configuration. Used by
// the two-instance integration harness to wire up matching HMAC secrets between
// home and remote without running the multi-step approval flow.
app.post<{ Body: { origin: string; hmacSecret: string; status?: string; instanceName?: string } }>(
'/api/admin/test/seed-peer',
async (request, reply) => {
if (process.env.NODE_ENV !== 'test' || process.env.ENABLE_TEST_ROUTES !== '1') {
return reply.code(404).send({ error: 'Not Found', statusCode: 404 });
}
const { origin, hmacSecret, status, instanceName } = request.body;
if (typeof origin !== 'string' || !origin.startsWith('http')) {
return reply.code(400).send({ error: 'origin must be an http(s) URL', statusCode: 400 });
}
if (typeof hmacSecret !== 'string' || hmacSecret.length < 32) {
return reply.code(400).send({ error: 'hmacSecret must be a string ≥32 chars', statusCode: 400 });
}
const validStatuses = new Set(['active', 'pending', 'awaiting_approval', 'rejected', 'revoked', 'needs_attention', 'unreachable', 'accepted']);
if (status !== undefined && !validStatuses.has(status)) {
return reply.code(400).send({ error: `status must be one of ${[...validStatuses].join(', ')}`, statusCode: 400 });
}
const db = getDb();
const id = crypto.randomUUID();
db.insert(schema.federationPeers)
.values({
id,
origin,
instanceName: instanceName ?? null,
hmacSecret,
status: status ?? 'active',
consecutiveFailures: 0,
consecutiveAuthFailures: 0,
lastSyncedAt: 0,
nonceSupported: 1,
autoRotateIntervalDays: 90,
createdAt: Date.now(),
})
.onConflictDoUpdate({
target: schema.federationPeers.origin,
set: { hmacSecret, status: status ?? 'active', instanceName: instanceName ?? null },
})
.run();
return reply.code(200).send({ ok: true, id });
},
);
}