diff --git a/artifacts/api-server/src/routes/relay.ts b/artifacts/api-server/src/routes/relay.ts index 33b72a1..16e8351 100644 --- a/artifacts/api-server/src/routes/relay.ts +++ b/artifacts/api-server/src/routes/relay.ts @@ -30,6 +30,24 @@ const logger = makeLogger("relay-policy"); const router = Router(); const RELAY_POLICY_SECRET = process.env["RELAY_POLICY_SECRET"] ?? ""; +const IS_PROD = process.env["NODE_ENV"] === "production"; + +// Production enforcement: RELAY_POLICY_SECRET must be set in production. +// An unprotected relay policy endpoint in production allows any caller on the +// network to whitelist events — a serious trust-system bypass. +if (!RELAY_POLICY_SECRET) { + if (IS_PROD) { + logger.error( + "RELAY_POLICY_SECRET is not set in production — " + + "POST /api/relay/policy is open to any caller. " + + "Set this secret in the API server environment and in the relay-policy sidecar.", + ); + } else { + logger.warn( + "RELAY_POLICY_SECRET not set — /api/relay/policy accepts local-only requests (dev mode)", + ); + } +} // ── Types ───────────────────────────────────────────────────────────────────── @@ -64,6 +82,23 @@ function reject(id: string, msg: string): PolicyDecision { return { id, action: "reject", msg }; } +// ── GET /relay/policy ───────────────────────────────────────────────────────── +// Health + roundtrip probe. Returns the relay's current policy state and runs +// a synthetic event through evaluatePolicy() so operators can verify the full +// sidecar → API path with: curl https://alexanderwhitestone.com/api/relay/policy +// +// Not secret-gated — it contains no privileged information. + +router.get("/relay/policy", (_req: Request, res: Response) => { + const probe = evaluatePolicy("0000000000000000000000000000000000000000000000000000000000000000", "probe", 1); + res.json({ + ok: true, + secretConfigured: !!RELAY_POLICY_SECRET, + bootstrapDecision: probe.action, + bootstrapMsg: probe.msg, + }); +}); + // ── POST /relay/policy ──────────────────────────────────────────────────────── router.post("/relay/policy", (req: Request, res: Response) => {