Files
ccs/docs/reports/hardening-inventory.json
T
Tam Nhu Tran 87aeb8f193 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.
2026-06-18 18:48:12 -04:00

773 lines
23 KiB
JSON

{
"scope": "src/**/*.{ts,tsx,js,jsx,mjs,cjs}",
"syncFs": {
"totalOccurrences": 2301,
"filesAffected": 242,
"hotpathOccurrences": 1946,
"hotpathFilesAffected": 192,
"topHotpathFiles": [
{
"file": "src/cliproxy/__tests__/pool-routing-phase3.test.ts",
"count": 96,
"calls": [
"existsSync",
"mkdirSync",
"mkdtempSync",
"readFileSync",
"rmSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/cliproxy/config/__tests__/config-generator.test.js",
"count": 88,
"calls": [
"existsSync",
"mkdirSync",
"mkdtempSync",
"readFileSync",
"rmSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/management/shared-manager.ts",
"count": 86,
"calls": [
"copyFileSync",
"cpSync",
"existsSync",
"lstatSync",
"mkdirSync",
"readdirSync",
"readFileSync",
"readlinkSync",
"rmSync",
"statSync",
"symlinkSync",
"unlinkSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/cliproxy/config/__tests__/claude-model-neutral.test.ts",
"count": 63,
"calls": [
"existsSync",
"mkdirSync",
"mkdtempSync",
"readFileSync",
"rmSync",
"statSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/cliproxy/accounts/__tests__/account-safety-quota-exhaustion.test.ts",
"count": 48,
"calls": [
"existsSync",
"mkdirSync",
"mkdtempSync",
"readFileSync",
"rmSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/cliproxy/accounts/__tests__/account-registry-integrity.test.ts",
"count": 45,
"calls": [
"existsSync",
"mkdirSync",
"mkdtempSync",
"readdirSync",
"readFileSync",
"rmSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/cliproxy/executor/__tests__/variant-port-integration.test.js",
"count": 36,
"calls": [
"existsSync",
"mkdirSync",
"readdirSync",
"readFileSync",
"rmSync",
"unlinkSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/cliproxy/executor/__tests__/composite-variant-service.test.ts",
"count": 33,
"calls": [
"existsSync",
"mkdirSync",
"mkdtempSync",
"readFileSync",
"rmSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/cliproxy/executor/__tests__/variant-port-edge-cases.test.js",
"count": 33,
"calls": [
"existsSync",
"mkdirSync",
"readdirSync",
"rmSync",
"unlinkSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/utils/browser/mcp-installer.ts",
"count": 32,
"calls": [
"chmodSync",
"copyFileSync",
"existsSync",
"mkdirSync",
"readFileSync",
"renameSync",
"statSync",
"unlinkSync",
"writeFileSync"
],
"markers": []
}
],
"topFilesOverall": [
{
"file": "src/cliproxy/__tests__/pool-routing-phase3.test.ts",
"count": 96,
"calls": [
"existsSync",
"mkdirSync",
"mkdtempSync",
"readFileSync",
"rmSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/cliproxy/config/__tests__/config-generator.test.js",
"count": 88,
"calls": [
"existsSync",
"mkdirSync",
"mkdtempSync",
"readFileSync",
"rmSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/management/shared-manager.ts",
"count": 86,
"calls": [
"copyFileSync",
"cpSync",
"existsSync",
"lstatSync",
"mkdirSync",
"readdirSync",
"readFileSync",
"readlinkSync",
"rmSync",
"statSync",
"symlinkSync",
"unlinkSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/cliproxy/config/__tests__/claude-model-neutral.test.ts",
"count": 63,
"calls": [
"existsSync",
"mkdirSync",
"mkdtempSync",
"readFileSync",
"rmSync",
"statSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/cliproxy/accounts/__tests__/account-safety-quota-exhaustion.test.ts",
"count": 48,
"calls": [
"existsSync",
"mkdirSync",
"mkdtempSync",
"readFileSync",
"rmSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/cliproxy/accounts/__tests__/account-registry-integrity.test.ts",
"count": 45,
"calls": [
"existsSync",
"mkdirSync",
"mkdtempSync",
"readdirSync",
"readFileSync",
"rmSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/cliproxy/executor/__tests__/variant-port-integration.test.js",
"count": 36,
"calls": [
"existsSync",
"mkdirSync",
"readdirSync",
"readFileSync",
"rmSync",
"unlinkSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/cliproxy/executor/__tests__/composite-variant-service.test.ts",
"count": 33,
"calls": [
"existsSync",
"mkdirSync",
"mkdtempSync",
"readFileSync",
"rmSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/cliproxy/executor/__tests__/variant-port-edge-cases.test.js",
"count": 33,
"calls": [
"existsSync",
"mkdirSync",
"readdirSync",
"rmSync",
"unlinkSync",
"writeFileSync"
],
"markers": []
},
{
"file": "src/utils/browser/mcp-installer.ts",
"count": 32,
"calls": [
"chmodSync",
"copyFileSync",
"existsSync",
"mkdirSync",
"readFileSync",
"renameSync",
"statSync",
"unlinkSync",
"writeFileSync"
],
"markers": []
}
]
},
"legacyShim": {
"totalMarkers": 424,
"filesAffected": 163,
"topFiles": [
{
"file": "src/auth/profile-detector.ts",
"count": 18,
"calls": [],
"markers": [
"? `Using legacy API profile \"${candidate}\" for \"${profileName}\".`",
"' 1. Run: ccs legacy cursor enable\\n' +",
"' 2. Import auth: ccs legacy cursor auth\\n' +",
"' 3. Start daemon: ccs legacy cursor start\\n\\n' +",
"'Legacy Cursor profile is not enabled.\\n\\n' +",
"* - Legacy JSON format (config.json, profiles.json) as fallback",
"* 2. User-defined CLIProxy variants (config.cliproxy section) [legacy]",
"* 3. Settings-based profiles (config.profiles section) [legacy]",
"* 4. Account-based profiles (profiles.json) [legacy]",
"* Priority: settings-based profiles (glm/km) checked FIRST for backward compatibility.",
"// Check if account-based default exists (legacy)",
"// Fall back to legacy config",
"// Fall back to legacy config display",
"// Fall through to legacy if not found in unified config",
"// Priority 0.25: Check explicit legacy Cursor bridge profile.",
"// Priority 3: Check settings-based profiles (glm, km) - LEGACY FALLBACK",
"// Priority 4: Check account-based profiles (work, personal) - LEGACY FALLBACK"
]
},
{
"file": "src/utils/config-manager.ts",
"count": 13,
"calls": [],
"markers": [
"* Get config file path (legacy JSON path)",
"* Precedence: --config-dir flag > CCS_DIR env > CCS_HOME env (legacy, appends .ccs) > ~/.ccs default",
"* Read and parse config (legacy compatibility)",
"* Returns Config with profiles from unified config.yaml or legacy config.json.",
"* Returns config.yaml in unified mode, config.json in legacy mode.",
"* then falls back to config.json for backward compatibility.",
"// Convert unified cliproxy variants to legacy format",
"// Convert unified profiles to legacy format for compatibility",
"// If not found in unified config, try legacy config.json as fallback",
"// Legacy config is invalid JSON - that's OK in unified mode",
"// Legacy mode - read from config.json only",
"// Legacy mode: read config.json",
"// Merge legacy profiles into available list (avoid duplicates)"
]
},
{
"file": "src/cliproxy/__tests__/pool-onboarding-phase5.test.ts",
"count": 12,
"calls": [],
"markers": [
"* 12. Legacy-only install: dismissOnboardingHint does not create config.yaml",
"* 14. Legacy-only install: hasUnifiedConfig() returns false, enforcing call-site gate",
"/** Create a legacy-only home: has profiles.json but NO config.yaml */",
"// ── 12. Legacy-only install: dismissal does not create config.yaml ────────",
"// ── 14. Legacy-only install: hasUnifiedConfig() is false at account-flow / create-command sites ──",
"// Intentionally no config.yaml - legacy install",
"// meaning those call sites silently skip the hint and legacy users receive",
"// Override tempHome with a legacy-only home (no config.yaml)",
"// The call-site guard must return false - legacy install has no config.yaml",
"const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-pool-onboarding-legacy-'));",
"it('dismissOnboardingHint does not create config.yaml for legacy profiles.json-only installs', async () => {",
"it('hasUnifiedConfig returns false for legacy profiles.json-only installs (call-site gate)', async () => {"
]
},
{
"file": "src/cliproxy/executor/__tests__/variant-port-allocation.test.js",
"count": 12,
"calls": [],
"markers": [
"// Create legacy variant without port",
"// Create variant without port (legacy format)",
"// Should return first port since legacy variant has no port",
"assert.strictEqual(variants.legacy.port, undefined);",
"assert.strictEqual(variants.legacy.provider, 'gemini');",
"describe('getNextAvailablePort - Legacy Variant Handling', function () {",
"it('handles mixed legacy and modern variants', function () {",
"it('returns undefined port for legacy variants', function () {",
"legacy: {",
"settings: path.join(ccsDir, 'legacy.settings.json'),"
]
},
{
"file": "src/config/schemas/websearch.ts",
"count": 10,
"calls": [],
"markers": [
"* - Legacy CLI fallbacks: Gemini, Grok, OpenCode",
"* Legacy AI CLI fallbacks remain available for compatibility only.",
"* Uses deterministic search backends first, with optional legacy CLI fallback.",
"/** Enable Gemini CLI legacy fallback (default: false) */",
"/** Enable Grok CLI legacy fallback (default: false - requires GROK_API_KEY) */",
"/** Enable OpenCode CLI legacy fallback (default: false) */",
"/** Gemini CLI - optional legacy LLM fallback */",
"/** Grok CLI - optional legacy LLM fallback */",
"/** OpenCode - optional legacy LLM fallback */",
"// Legacy fields (deprecated, kept for backwards compatibility)"
]
},
{
"file": "src/commands/cursor-command-display.ts",
"count": 9,
"calls": [],
"markers": [
"' disable Disable legacy cursor integration in unified config',",
"' enable Enable legacy cursor integration in unified config',",
"' status Show legacy integration, authentication, and daemon status',",
"'Legacy auth options:',",
"'Legacy bridge quick start:',",
"'Legacy Cursor Compatibility',",
"'Legacy runtime entry (deprecated compatibility):',",
"console.log(` - Legacy auth: ${LEGACY_CURSOR_COMMAND} auth`);",
"const LEGACY_CURSOR_COMMAND = 'ccs legacy cursor';"
]
},
{
"file": "src/config/migration-manager.ts",
"count": 9,
"calls": [],
"markers": [
"* Check if there are legacy profiles that haven't been migrated to config.yaml.",
"* Handles migration from legacy JSON config (v1) to unified YAML config (v2).",
"// Deterministic priority: explicit canonical profile wins over legacy alias rename.",
"`Profile \"${targetName}\" exists in both configs with different settings - keeping existing (${existingSettings}), skipping legacy ${sourceName} (${pathStr})`",
"`Renamed legacy API profile \"${sourceName}\" to \"${targetName}\" (ccs kimi API profile is now ccs km)`",
"console.log(infoBox('Migrated legacy profiles to config.yaml', 'SUCCESS'));",
"console.log(infoBox('Migration failed - using legacy config', 'WARNING'));"
]
},
{
"file": "src/cliproxy/config/__tests__/env-builder-provider-url.test.ts",
"count": 8,
"calls": [],
"markers": [
"ANTHROPIC_API_KEY: 'legacy-cursor-api-key',",
"it('imports legacy cursor settings into the dedicated provider path without reusing legacy transport auth', () => {",
"name: 'legacy-45',",
"name: 'legacy-codex',",
"name: 'legacy-iflow',",
"name: 'legacy',"
]
},
{
"file": "src/cliproxy/executor/__tests__/variant-port-edge-cases.test.js",
"count": 8,
"calls": [],
"markers": [
"* legacy migration, permission errors, and config corruption.",
"// Create legacy variant without port",
"assert.strictEqual(variants.legacy.port, undefined);",
"describe('Legacy Variant Migration', function () {",
"it('legacy variant does not block port allocation', function () {",
"legacy: {"
]
},
{
"file": "src/cliproxy/config/__tests__/config-generator.test.js",
"count": 7,
"calls": [],
"markers": [
"'Should preserve lone manual high-version aliases during legacy cleanup'",
"'Should preserve manual aliases after legacy migration has already run'",
"'Should preserve the manual 3.2 compatibility cluster during legacy cleanup'",
"'Should preserve the pruned legacy alias in the migration backup'",
"assert(fs.existsSync(backupPath), 'Should keep a backup of the legacy config before pruning');",
"it('prunes partially retained broad guessed ranges during legacy cleanup', () => {",
"it('writes a one-time backup before pruning legacy Gemini aliases during migration', () => {"
]
}
],
"explicitShimFiles": [
"src/cliproxy/__tests__/model-catalog-compat.test.ts",
"src/cliproxy/ai-providers/__tests__/codex-plan-compatibility.test.ts",
"src/cliproxy/ai-providers/__tests__/openai-compat-manager.test.js",
"src/cliproxy/ai-providers/openai-compat-manager.ts",
"src/cliproxy/types/__tests__/types-backward-compat.test.ts",
"src/utils/profile-compat.ts",
"src/web-server/services/compatible-cli-docs-registry.ts"
]
},
"maintainability": {
"typedErrors": {
"totalThrows": 431,
"typedThrows": 4,
"plainThrows": 369,
"otherThrows": 58,
"adoptionRatio": 0.0093,
"topSubdomainsByThrows": [
{
"subdomain": "web-server",
"count": 103,
"typed": 4,
"plain": 57
},
{
"subdomain": "proxy",
"count": 38,
"typed": 0,
"plain": 34
},
{
"subdomain": "commands",
"count": 33,
"typed": 0,
"plain": 32
},
{
"subdomain": "utils",
"count": 33,
"typed": 0,
"plain": 33
},
{
"subdomain": "codex-auth",
"count": 31,
"typed": 0,
"plain": 27
},
{
"subdomain": "targets",
"count": 27,
"typed": 0,
"plain": 25
},
{
"subdomain": "cursor",
"count": 23,
"typed": 0,
"plain": 21
},
{
"subdomain": "cliproxy/accounts",
"count": 13,
"typed": 0,
"plain": 13
},
{
"subdomain": "auth",
"count": 12,
"typed": 0,
"plain": 12
},
{
"subdomain": "cliproxy/ai-providers",
"count": 12,
"typed": 0,
"plain": 12
}
]
},
"typedErrorAdoption": {
"subdomains": [
"cliproxy/quota",
"cliproxy/auth",
"web-server/routes",
"auth"
],
"numerator": 0,
"denominator": 23,
"ratio": 0,
"targetRatio": 0.4
},
"loggerCoverage": {
"filesWithCreateLogger": 64,
"totalSourceFiles": 685,
"coverageRatio": 0.0934,
"subdomainsWithZeroCreateLogger": [
"api",
"bin",
"channels",
"cliproxy",
"cliproxy/accounts",
"cliproxy/ai-providers",
"cliproxy/binary",
"cliproxy/config",
"cliproxy/management",
"cliproxy/sync",
"cliproxy/types",
"config",
"dispatcher",
"shared",
"types"
],
"topSubdomainsByFiles": [
{
"subdomain": "web-server",
"count": 103,
"withLogger": 10
},
{
"subdomain": "utils",
"count": 87,
"withLogger": 1
},
{
"subdomain": "commands",
"count": 85,
"withLogger": 2
},
{
"subdomain": "cliproxy/auth",
"count": 30,
"withLogger": 1
},
{
"subdomain": "config",
"count": 27,
"withLogger": 0
},
{
"subdomain": "cursor",
"count": 24,
"withLogger": 2
},
{
"subdomain": "codex-auth",
"count": 23,
"withLogger": 8
},
{
"subdomain": "management",
"count": 22,
"withLogger": 1
},
{
"subdomain": "auth",
"count": 20,
"withLogger": 1
},
{
"subdomain": "cliproxy/executor",
"count": 17,
"withLogger": 4
}
]
},
"hotpathConsoleErrors": {
"totalOccurrences": 569,
"exemptOccurrences": 302,
"hotpathOccurrences": 267,
"filesAffected": 82,
"topFiles": [
{
"file": "src/errors/error-handler.ts",
"count": 11
},
{
"file": "src/utils/prompt.ts",
"count": 11
},
{
"file": "src/utils/websearch/profile-hook-injector.ts",
"count": 10
},
{
"file": "src/cliproxy/accounts/account-safety-cross-lane.ts",
"count": 9
},
{
"file": "src/utils/hooks/image-analyzer-profile-hook-injector.ts",
"count": 9
},
{
"file": "src/utils/websearch/hook-installer.ts",
"count": 8
},
{
"file": "src/cliproxy/auth/token-manager.ts",
"count": 7
},
{
"file": "src/cliproxy/binary/downloader.ts",
"count": 7
},
{
"file": "src/cliproxy/executor/account-resolution.ts",
"count": 7
},
{
"file": "src/config/unified-config-loader.ts",
"count": 7
},
{
"file": "src/targets/claude-adapter.ts",
"count": 7
},
{
"file": "src/utils/shell-executor.ts",
"count": 7
},
{
"file": "src/utils/websearch/hook-config.ts",
"count": 7
},
{
"file": "src/targets/droid-detector.ts",
"count": 6
},
{
"file": "src/utils/hooks/image-analyzer-hook-installer.ts",
"count": 6
}
]
},
"largeFiles": {
"countOver400": 95,
"countOver600": 45,
"topOver400": [
{
"file": "src/management/shared-manager.ts",
"loc": 1631
},
{
"file": "src/web-server/routes/cliproxy-auth-routes.ts",
"loc": 1515
},
{
"file": "src/cliproxy/auth/oauth-handler.ts",
"loc": 1453
},
{
"file": "src/web-server/routes/cliproxy-stats-routes.ts",
"loc": 1238
},
{
"file": "src/cursor/cursor-executor.ts",
"loc": 1234
},
{
"file": "src/cliproxy/quota/quota-fetcher-gemini-cli.ts",
"loc": 1183
},
{
"file": "src/commands/cliproxy/quota-subcommand.ts",
"loc": 1130
},
{
"file": "src/cliproxy/quota/quota-fetcher.ts",
"loc": 1094
},
{
"file": "src/commands/persist-command.ts",
"loc": 1071
},
{
"file": "src/web-server/model-pricing.ts",
"loc": 1070
},
{
"file": "src/web-server/routes/settings-routes.ts",
"loc": 1040
},
{
"file": "src/cliproxy/config/env-builder.ts",
"loc": 1037
},
{
"file": "src/cliproxy/proxy/tool-sanitization-proxy.ts",
"loc": 1022
},
{
"file": "src/cliproxy/auth/oauth-process.ts",
"loc": 1018
},
{
"file": "src/cliproxy/config/generator.ts",
"loc": 1012
}
]
}
}
}