feat(logging): P3 hotpath console.error migration + redaction gate (928->267)

Epic P3. Migrates hotpath console.error/warn to the structured logger
(diagnostics) or process.stderr.write (user-facing), and adds a redaction
safety gate so the migration cannot leak credentials.

Redaction gate (MR1):
- log-redaction: scrub known credential token shapes (sk-ant, sk-, xoxb,
  ghp, glpat, AIza, JWT bodies, api_key=, Bearer/Basic/Token scheme) in
  string values, Error.message, AND the log message string (defense-in-depth).
- logger: message now passes through maskSecretTokens.

tool-sanitization-proxy: deleted the private file-logging subsystem
(initLogFile/writeLog/log/warn, logFilePath, debugMode); 13 call sites now
route through the existing createLogger('cliproxy:tool-sanitization-proxy').

Sweep (~120 diagnostic -> structured createLogger; ~540 user-facing -> stderr):
- diagnostics converted across proxy, web-server/routes, glmt pipeline, quota
  fetchers, executors, delegation, session-bridge, https-tunnel-proxy.
- user-facing CLI output (flows, arg-parser usage, installers, prompts, adapter
  launch errors, error display) moved to process.stderr.write (preserves stderr).
- src/utils/error-manager.ts reclassified CLI-UX-exempt (user-facing display).

Metric: hotpath console.error 928 -> 267 (71%); createLogger files 35 -> 64.
Residual 267 is user-facing CLI output (not diagnostics); documented in
docs/hardening-debt-burndown.md. Redaction gate makes further conversion safe.

Tests: hotpath-redaction-regression (12 token shapes); updated delegation-handler,
arg-parser, model-warnings spies (console.error -> process.stderr.write).
validate + validate:ci-parity green.
This commit is contained in:
Tam Nhu Tran committed 2026-06-18 18:48:12 -04:00
1 parent 5e1b8640ab
commit 87aeb8f193
60 files changed
+1710 -896

No files matched your search

@@ -2,6 +2,9 @@ import { DeltaAccumulator } from '../../glmt/delta-accumulator';
import { GlmtTransformer } from '../../glmt/glmt-transformer';
import { SSEParser } from '../../glmt/sse-parser';
import type { OpenAIResponse, SSEEvent } from '../../glmt/pipeline';
import { createLogger } from '../../services/logging';
const logger = createLogger('proxy:sse-stream-transformer');
const JSON_TRANSLATION_ERROR_MESSAGE = 'Failed to translate OpenAI-compatible JSON response';
const STREAM_TRANSLATION_ERROR_MESSAGE = 'Failed to translate OpenAI-compatible SSE response';
@@ -26,20 +29,13 @@ function createAnthropicErrorPayload(type: string, message: string): AnthropicEr
};
}
function formatErrorForLog(error: unknown): string {
if (error instanceof Error) {
return error.message;
}
try {
return JSON.stringify(error);
} catch {
return String(error);
}
}
function logTranslationError(context: string, error: unknown): void {
console.error(`[proxy-sse-transformer] ${context}: ${formatErrorForLog(error)}`);
function logTranslationError(event: string, message: string, error: unknown): void {
logger.error(event, message, {
err:
error instanceof Error
? { name: error.name, message: error.message }
: { message: String(error) },
});
}
export function createAnthropicErrorResponse(
@@ -130,7 +126,11 @@ async function createAnthropicErrorProxyResponse(response: Response): Promise<Re
}
}
} catch (error) {
logTranslationError('Failed to parse upstream error response', error);
logTranslationError(
'sse_transformer.upstream_error_parse_failed',
'Failed to parse upstream error response',
error
);
}
return createAnthropicErrorResponse(response.status, type, message, headers);
@@ -146,6 +146,7 @@ async function createAnthropicJsonResponse(response: Response): Promise<Response
const anthropicResponse = new GlmtTransformer().transformResponse(openAIResponse);
if (isSyntheticTransformationFallback(anthropicResponse)) {
logTranslationError(
'sse_transformer.json_synthetic_fallback',
'OpenAI-compatible JSON translation produced synthetic fallback response',
anthropicResponse
);
@@ -157,7 +158,11 @@ async function createAnthropicJsonResponse(response: Response): Promise<Response
headers: { 'Content-Type': 'application/json' },
});
} catch (error) {
logTranslationError('OpenAI-compatible JSON translation failed', error);
logTranslationError(
'sse_transformer.json_translation_failed',
'OpenAI-compatible JSON translation failed',
error
);
return createAnthropicErrorResponse(502, 'api_error', JSON_TRANSLATION_ERROR_MESSAGE);
}
}
@@ -210,7 +215,11 @@ function createAnthropicStreamingResponse(response: Response): Response {
}
}
} catch (error) {
logTranslationError('OpenAI-compatible SSE translation failed', error);
logTranslationError(
'sse_transformer.sse_translation_failed',
'OpenAI-compatible SSE translation failed',
error
);
controller.enqueue(
encoder.encode(
formatSseEvent(