added deploy watch, pull script. minor refactors
This commit is contained in:
47
app/api/deploy/route.ts
Normal file
47
app/api/deploy/route.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { createHash, timingSafeEqual } from "node:crypto";
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
/**
|
||||
* POST /api/deploy
|
||||
*
|
||||
* Drops the redeploy flag that scripts/deploy-watch.sh polls for. Requires
|
||||
* `Authorization: Bearer <DEPLOY_TRIGGER_SECRET>`.
|
||||
*
|
||||
* DEPLOY_TRIGGER_DIR must point at the same directory the watcher reads
|
||||
* (mounted into the container by docker-compose.yml).
|
||||
*/
|
||||
|
||||
const TRIGGER_DIR = process.env.DEPLOY_TRIGGER_DIR ?? "/deploy-trigger";
|
||||
const TRIGGER_FILE = path.join(TRIGGER_DIR, "redeploy.flag");
|
||||
|
||||
// Hashing both sides gives equal-length buffers, so the comparison is
|
||||
// constant-time regardless of the supplied token's length.
|
||||
function tokenMatches(supplied: string, expected: string): boolean {
|
||||
const a = createHash("sha256").update(supplied).digest();
|
||||
const b = createHash("sha256").update(expected).digest();
|
||||
return timingSafeEqual(a, b);
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const secret = process.env.DEPLOY_TRIGGER_SECRET;
|
||||
if (!secret) {
|
||||
// Not configured: behave as if the route doesn't exist.
|
||||
return new Response(null, { status: 404 });
|
||||
}
|
||||
|
||||
const header = request.headers.get("authorization") ?? "";
|
||||
const match = /^Bearer\s+(.+)$/i.exec(header);
|
||||
if (!match || !tokenMatches(match[1].trim(), secret)) {
|
||||
return Response.json({ error: "unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
try {
|
||||
await writeFile(TRIGGER_FILE, new Date().toISOString() + "\n");
|
||||
} catch (err) {
|
||||
console.error("[deploy] failed to write trigger file", TRIGGER_FILE, err);
|
||||
return Response.json({ error: "failed to queue redeploy" }, { status: 500 });
|
||||
}
|
||||
|
||||
return Response.json({ status: "queued" }, { status: 202 });
|
||||
}
|
||||
Reference in New Issue
Block a user