feat(guild): system-key bypass + announce-only system path + gen CLI
Three coupled changes that let Dialectic.Backend (and future system broadcasters) post to announce channels without needing a Fabric user bearer. 1. ApiKeyGuard: when x-fabric-system-key matches FABRIC_BACKEND_GUILD_SYSTEM_API_KEY env, skip the Bearer requirement and set req.isSystem=true. Pre-Bearer system bypass; no per-user session token needed. Empty env -> bypass disabled (closed by default). 2. messaging.controller POST /channels/:id/messages: when req.isSystem, skip assertParticipant + fetch channel directly. Enforce xType=announce (system key only writes to announce channels - never to regular chats). Persist with sentinel author 00000000-0000-0000-0000-000000000000. Emit message.created + realtime.emitMessageCreated with xType=announce so the Phase 1 busy-discard logic kicks in for recipients. 3. New cli: src/cli/gen-system-api-key.ts. Generates a random 32-byte hex key (same shape as agent + admin keys) and prints it. Does NOT store - operator pastes into compose env and restarts guild. Pattern mirrors the existing print-commands-sync-key.ts. Removes the need for a FABRIC_BOT_BEARER_TOKEN concept entirely - the system key alone is sufficient. announce-channel posts by regular authenticated users (who happen to know channel id but no system key) are now 403 announce_system_only.
This commit is contained in:
@@ -21,6 +21,23 @@ export class ApiKeyGuard implements CanActivate {
|
||||
return true;
|
||||
}
|
||||
|
||||
// System-key bypass: when a caller presents x-fabric-system-key matching
|
||||
// FABRIC_BACKEND_GUILD_SYSTEM_API_KEY, skip the Bearer requirement and
|
||||
// mark this as a system caller (no userId). Downstream handlers (e.g.
|
||||
// messaging.controller for announce-type channels) gate per-route on
|
||||
// req.isSystem instead of req.userId.
|
||||
//
|
||||
// This is what makes Dialectic.Backend's lifecycle broadcasts work
|
||||
// without needing a per-user Fabric session token — the system key
|
||||
// alone is sufficient for posting to announce channels.
|
||||
const sysExpected = process.env.FABRIC_BACKEND_GUILD_SYSTEM_API_KEY ?? '';
|
||||
const sysHeader = req.headers['x-fabric-system-key'];
|
||||
const sysProvided = Array.isArray(sysHeader) ? sysHeader[0] : sysHeader;
|
||||
if (sysExpected && sysProvided && sysProvided === sysExpected) {
|
||||
(req as { isSystem?: boolean }).isSystem = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const auth = req.headers['authorization'];
|
||||
const authValue = Array.isArray(auth) ? auth[0] : auth;
|
||||
let token = authValue?.startsWith('Bearer ') ? authValue.slice(7) : '';
|
||||
|
||||
Reference in New Issue
Block a user