feat(runner): WS protocol server with handshake
apps/runner scaffold (app-tier, walking-skeleton story 04): WS server speaking @repo/core-runner-protocol. Every inbound/outbound frame is envelope-wrapped and zod-parsed; hello/ready handshake gates on the workspace-scoped token (constant-time compare, redacted token on rejection replies); named error events for version/schema/auth rejections. Config via env only (token never argv); port announced on stdout for the story-06 provisioner. Runtime deps: ws (the standard Node WS server; ADR-022 traces do not apply to app-tier) and zod. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
This commit is contained in:
34
apps/runner/src/log.ts
Normal file
34
apps/runner/src/log.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Minimal JSON-lines logger for the runner process.
|
||||
*
|
||||
* The runner logs to stdout so the provisioner (story 06) and the
|
||||
* integration tests can read a structured stream. The sink is injectable
|
||||
* so in-process tests can capture every emitted line and assert
|
||||
* credential-leak absence (spec §15): nothing in this module — and by
|
||||
* convention nothing passed to it — may ever contain a secret. Callers
|
||||
* log event names and safe fields only, never raw protocol payloads.
|
||||
*/
|
||||
export type LogSink = (line: string) => void;
|
||||
|
||||
export interface Logger {
|
||||
info(event: string, fields?: Record<string, unknown>): void;
|
||||
error(event: string, fields?: Record<string, unknown>): void;
|
||||
}
|
||||
|
||||
const stdoutSink: LogSink = (line) => {
|
||||
process.stdout.write(`${line}\n`);
|
||||
};
|
||||
|
||||
export function createLogger(sink: LogSink = stdoutSink): Logger {
|
||||
const emit = (
|
||||
level: "info" | "error",
|
||||
event: string,
|
||||
fields?: Record<string, unknown>,
|
||||
) => {
|
||||
sink(JSON.stringify({ level, event, ...fields }));
|
||||
};
|
||||
return {
|
||||
info: (event, fields) => emit("info", event, fields),
|
||||
error: (event, fields) => emit("error", event, fields),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user