Repository navigation
fix(governance): broken featureFlags imports + 3 silent fail-opens + extras test - #507
Conversation
…extras test Continuation of the governance-debt cleanup started in PRs #505 and #506. Six independent fixes, each addressing a class of silent-failure pattern that the audits surfaced. Changes: 1. **`src/lib/resilience/anomalyHook.ts:12`** — Broken import path. `isFeatureFlagEnabled` was imported from `@/lib/featureFlags`, but the module lives at `@/shared/utils/featureFlags`. This bug was masked because `tsconfig.typecheck-core.json` does not include `src/lib/resilience/` and no test loads the module successfully. After the fix, the module loads and exports the expected surface. 2. **`src/server-init.ts:128`** — Same broken import path. The surrounding try/catch at lines 130-139 silently swallowed the import failure. Fix: correct the path AND upgrade the catch log from `warn` to `error` (matches PR #506 pattern). 3. **`src/lib/versionManager/processManager.ts:155`** — `getProcessInfo` catch returned `{pid, alive: true}` after `ps`/readFile failures, which lies when the process is actually gone. Fix: catch now logs the error and returns `{pid, alive: false}` (honest about not being able to read process state). 4. **`src/server/ws/liveServer.ts:479`** — `loadAuthModule().catch(() => {})` silently swallowed initial auth module load failures, allowing the WS server to come up without auth configured. Fix: catch now logs `log.error`; fallback behavior preserved per the existing comment ("handler retries the import lazily"). 5. **`src/lib/machineToken.ts:1-10`** — Crypto-relevant: empty catch around `require("node-machine-id")` silently fell back to `() => ""`, which collapses HMAC inputs to a constant. Fix: catch now logs `log.error` with security-context message, gated by a `fallbackLogged` flag so the log fires only once per process (avoiding log spam from any downstream reload). 6. **`tests/unit/quota/keyvQuotaStoreExtras.test.ts`** (new) — Closes spec §8.2 reachability test gap. 5 sanity tests for the `recordPlanUsage` / `upsertProviderPlan` / `listProviderPlans` / `setPools` / `getPool` surface on KeyvQuotaStore. Note: this branch is based on `origin/agent/migration-version-collision-fix` (pre-PR-#505), so the methods live directly on KeyvQuotaStore. When PR #505 lands, update the test to import from `keyvQuotaStoreExtras.ts` instead. Verification: - TSC error count: 8 unchanged (all pre-existing quota keystore errors that PR #505 fixes; this PR is independent of #505) - Vitest extras test: 5/5 pass - Node:test combined (processManager + machineToken + WS): 47/47 pass - All success-path behavior preserved; only catch/fallback paths now log Out of scope (separate PRs): - Promote Keyv to "embedded default" driver (spec §10) - Pre-existing e2e failure at `tests/e2e/quota-store.e2e.ts:117` (poolUsageWithDimensions shape mismatch — fixed in PR #505) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
🤖 CodeAnt AI — Review Status
|
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
|
Tick the box to add this pull request to the merge queue (same as
|
| await loadAuthModule().catch((err) => | ||
| log.error( | ||
| { err }, | ||
| "liveServer: failed to warm auth module — clients may experience cold-import latency" | ||
| ) | ||
| ); |
There was a problem hiding this comment.
Suggestion: The warm-up catches the rejected dynamic import, but loadAuthModule memoizes that rejected promise in authModulePromise. Consequently, every later API-key authorization receives the same rejection and returns Auth system unavailable; the documented lazy retry never occurs after a transient startup failure. Clear the cached promise when the import rejects, or avoid caching rejected imports. [logic error]
Severity Level: Major ⚠️
- ❌ API-key WebSocket clients remain unauthorized after transient startup recovery.
- ⚠️ Live dashboard authentication requires process restart.
- ⚠️ Cookie-authenticated clients may continue while API-key clients fail.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** src/server/ws/liveServer.ts
**Line:** 482:487
**Comment:**
*Logic Error: The warm-up catches the rejected dynamic import, but `loadAuthModule` memoizes that rejected promise in `authModulePromise`. Consequently, every later API-key authorization receives the same rejection and returns `Auth system unavailable`; the documented lazy retry never occurs after a transient startup failure. Clear the cached promise when the import rejects, or avoid caching rejected imports.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| } | ||
| } catch (err) { | ||
| startupLog.warn({ err }, "Self-healing hydration skipped (non-fatal)"); | ||
| startupLog.error({ err }, "Self-healing hydration skipped (non-fatal)"); |
There was a problem hiding this comment.
WARNING: Log severity says "error" but message says "non-fatal"
The startupLog.error call carries the text "Self-healing hydration skipped (non-fatal)". If your monitoring/alerting treats error as actionable, this will page on-call for a condition that explicitly does not require human intervention. Either downgrade to warn to match the message, or update the message to reflect that this is treated as an error-level event.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| { err, pid, platform: process.platform }, | ||
| "processManager.getProcessInfo: failed to read process info" | ||
| ); | ||
| return { pid, alive: false }; |
There was a problem hiding this comment.
SUGGESTION: alive: false conflates "dead" with "unreadable"
The catch now returns { pid, alive: false } on any read failure. This is correct for the documented race-condition case (process died between isProcessRunning and the /proc/ps read), but it also maps transient failures (e.g. permissions, platform quirks) to alive: false. If future callers use getProcessInfo to drive restart decisions, a temporarily unreadable alive process could be restarted unnecessarily. Consider adding an unknown state or a separate readable flag so callers can distinguish "confirmed dead" from "state unreadable".
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
Code Review SummaryStatus: 2 Issues Found | Recommendation: Approve with notes Overview
Issue Details (click to expand)WARNING
SUGGESTION
Files Reviewed (6 files)
Fix these issues in Kilo Cloud Reviewed by step-3.7-flash · Input: 117.3K · Output: 18.8K · Cached: 1.3M |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Note
|
|
7456226
into
agent/migration-version-collision-fix
…onical base) (#509) This branch has been surgically rebased onto origin/agent/migration-version-collision-fix to remove accidental contamination from PR #507's branch base. In all three cases, the empty-string return collapses HMAC/HMAC-SHA256 inputs into a constant-key value, so security-relevant operations on the fallback path produce identical tokens regardless of input. Fixes: 1. src/lib/machineToken.ts:44 - getMachineTokenSync catch: log.error + return "" 2. src/lib/machineToken.ts:62 - getLegacyCliTokenSync catch: log.error + return "" 3. src/lib/db/encryption.ts:87-95 - getLegacyDynamicKey catch: added pino logger (createLogger("db:encryption")) + log.error instead of returning null silently 4. (incidental) src/lib/machineToken.ts module-load catch: also gains log.error so the new runtime catches have a 'log' constant to reference. This subsumes PR #507's machineToken.ts hunk. NOTE: PR #507 will need its machineToken.ts hunk resolved when it merges (this branch already provides the 'log' logger constant it tries to add). Verification: - TSC: 8 unchanged (pre-existing quota keystore errors, PR #505 territory) - Targeted machineToken + encryption unit tests pass - All success-path behaviors preserved Co-authored-by: KooshaPari <koosha@example.com>
Follows the PR #506/#507/#509/#510 pattern of replacing console.* with createLogger("db:<subsystem>") to provide structured logging across the SQLite persistence layer. Files modified (~155 callsites across 17 files): - src/lib/db/adapters/driverFactory.ts - src/lib/db/adapters/sqljsAdapter.ts - src/lib/db/apiKeys.ts - src/lib/db/backup.ts - src/lib/db/cleanup.ts (~30 sites) - src/lib/db/core.ts (~30 sites) - src/lib/db/migrationRunner.ts (~22 sites, removed test-suppressing local console wrapper) - src/lib/db/models.ts - src/lib/db/optimizationSettings.ts - src/lib/db/providers.ts - src/lib/db/quotaPools.ts - src/lib/db/quotaSnapshots.ts - src/lib/db/schemaColumns.ts (~35 sites) - src/lib/db/sessionAccountAffinity.ts - src/lib/db/settings.ts - src/lib/db/settings/cacheMetrics.ts - src/lib/db/stateReset.ts Per AGENTS.md guidance, never log SQLite encryption keys or raw secrets; all logger calls redact sensitive material. Behavior preservation: - All success-path behavior unchanged - Only the logging mechanism changes - Targeted tests pass One console.error preserved in core.ts:migrateFromJson because tests/unit/db-core-migration.test.ts overrides console.error to detect the failure; both console.error and log.error are emitted so the test passes and pino is the canonical sink. Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(governance): rebase mergify config request-review fixes onto main * fix(desktop): target fork-owned Electron releases * ci: align workflows with selected action policy * fix(governance): replace silent try/catch with explicit log.error in 5 modules (#506) Builds on PR #505 (quota keystore type-drift fix). The audit of that PR revealed 5 additional silent fail-open catch patterns across `src/` and `open-sse/` that hide the same class of bug: a TypeScript compile error or missing module is silently swallowed at runtime, falling back to a default with no operator-visible signal. This commit replaces those silent catches with explicit `log.error` calls that surface the actual error to monitoring. Fallback behavior is preserved (each fallback is intentional, but it must be LOUD). Changes: 1. `src/lib/quota/storeFactory.ts:67-77` — `readDbSettings` now logs the actual error when `getSettings()` fails or `@/lib/db/settings` import fails. Same root cause as the previously-fixed Keyv/Redis catches. 2. `src/lib/quota/storeFactory.ts:138-147` — Redis driver catch upgraded from `log.warn` to `log.error`. Includes the configured Redis URL with the password segment redacted (`:***@`). 3. `src/lib/resilience/anomalyHook.ts` — `getProviderManagerRegistry` now logs the actual error when `@/engine/providers` fails to load. Empty Map fallback retained (resilience must continue running), but the failure is now visible in monitoring. 4. `open-sse/services/tierResolver.ts` — `setTierConfig` now logs the actual error when `../../src/lib/db/tierConfig` fails to load. `DEFAULT_TIER_CONFIG` fallback retained (pricing must continue), but the failure is now visible. 5. `open-sse/config/credentialLoader.ts` — `resolveCredentialsPath` now uses `log.error` (pino) instead of `console.warn`. Includes both the original error and the fallback path. Security-sensitive path; must keep working, but the failure must be loud. 6. `.gitignore` — exclude `.agileplus/` and `agileplus-*.db*` (local AgilePlus DB state, regenerated from `.md` specs via `agileplus specify`). The DB contains transient per-machine state and shouldn't be in version control. Verification: - TSC: 0 NEW errors (8 pre-existing quota keystore errors remain, those are what PR #505 fixes; this PR is independent of PR #505) - Vitest quota suite: 18/18 pass (6 keyv + 4 contract + 8 e2e) - Node:test factory: 6/6 pass - Resilience tests: 61 pass / 1 pre-existing flake (resilience-provider-cooldown-api-3556.test.ts: "rejects providerCooldown max below min" — verified pre-existing by reverting only anomalyHook.ts and reproducing the same failure) Out of scope (filed as separate bugs): - `src/lib/resilience/anomalyHook.ts:13` imports `isFeatureFlagEnabled` from `@/lib/featureFlags`, but the module lives at `src/lib/db/featureFlags.ts`. The file is currently unloadable from tests; this PR doesn't touch the import because that's a separate bug. - The Resilience subagent identified but did not fix the `tsconfig.typecheck-core.json` doesn't include `src/lib/resilience/` files — separate follow-up. Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(governance): broken featureFlags imports + 3 silent fail-opens + extras test (#507) Continuation of the governance-debt cleanup started in PRs #505 and #506. Six independent fixes, each addressing a class of silent-failure pattern that the audits surfaced. Changes: 1. **`src/lib/resilience/anomalyHook.ts:12`** — Broken import path. `isFeatureFlagEnabled` was imported from `@/lib/featureFlags`, but the module lives at `@/shared/utils/featureFlags`. This bug was masked because `tsconfig.typecheck-core.json` does not include `src/lib/resilience/` and no test loads the module successfully. After the fix, the module loads and exports the expected surface. 2. **`src/server-init.ts:128`** — Same broken import path. The surrounding try/catch at lines 130-139 silently swallowed the import failure. Fix: correct the path AND upgrade the catch log from `warn` to `error` (matches PR #506 pattern). 3. **`src/lib/versionManager/processManager.ts:155`** — `getProcessInfo` catch returned `{pid, alive: true}` after `ps`/readFile failures, which lies when the process is actually gone. Fix: catch now logs the error and returns `{pid, alive: false}` (honest about not being able to read process state). 4. **`src/server/ws/liveServer.ts:479`** — `loadAuthModule().catch(() => {})` silently swallowed initial auth module load failures, allowing the WS server to come up without auth configured. Fix: catch now logs `log.error`; fallback behavior preserved per the existing comment ("handler retries the import lazily"). 5. **`src/lib/machineToken.ts:1-10`** — Crypto-relevant: empty catch around `require("node-machine-id")` silently fell back to `() => ""`, which collapses HMAC inputs to a constant. Fix: catch now logs `log.error` with security-context message, gated by a `fallbackLogged` flag so the log fires only once per process (avoiding log spam from any downstream reload). 6. **`tests/unit/quota/keyvQuotaStoreExtras.test.ts`** (new) — Closes spec §8.2 reachability test gap. 5 sanity tests for the `recordPlanUsage` / `upsertProviderPlan` / `listProviderPlans` / `setPools` / `getPool` surface on KeyvQuotaStore. Note: this branch is based on `origin/agent/migration-version-collision-fix` (pre-PR-#505), so the methods live directly on KeyvQuotaStore. When PR #505 lands, update the test to import from `keyvQuotaStoreExtras.ts` instead. Verification: - TSC error count: 8 unchanged (all pre-existing quota keystore errors that PR #505 fixes; this PR is independent of #505) - Vitest extras test: 5/5 pass - Node:test combined (processManager + machineToken + WS): 47/47 pass - All success-path behavior preserved; only catch/fallback paths now log Out of scope (separate PRs): - Promote Keyv to "embedded default" driver (spec §10) - Pre-existing e2e failure at `tests/e2e/quota-store.e2e.ts:117` (poolUsageWithDimensions shape mismatch — fixed in PR #505) Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(security): log 3 crypto-relevant silent catches (rebased onto canonical base) (#509) This branch has been surgically rebased onto origin/agent/migration-version-collision-fix to remove accidental contamination from PR #507's branch base. In all three cases, the empty-string return collapses HMAC/HMAC-SHA256 inputs into a constant-key value, so security-relevant operations on the fallback path produce identical tokens regardless of input. Fixes: 1. src/lib/machineToken.ts:44 - getMachineTokenSync catch: log.error + return "" 2. src/lib/machineToken.ts:62 - getLegacyCliTokenSync catch: log.error + return "" 3. src/lib/db/encryption.ts:87-95 - getLegacyDynamicKey catch: added pino logger (createLogger("db:encryption")) + log.error instead of returning null silently 4. (incidental) src/lib/machineToken.ts module-load catch: also gains log.error so the new runtime catches have a 'log' constant to reference. This subsumes PR #507's machineToken.ts hunk. NOTE: PR #507 will need its machineToken.ts hunk resolved when it merges (this branch already provides the 'log' logger constant it tries to add). Verification: - TSC: 8 unchanged (pre-existing quota keystore errors, PR #505 territory) - Targeted machineToken + encryption unit tests pass - All success-path behaviors preserved Co-authored-by: KooshaPari <koosha@example.com> * fix(security): 4 audit findings + migrate encryption.ts to pino (#510) Completes the audit-driven governance work that PR #509 started. Eight independent fixes: Security fixes (audit findings F5, F6, F9, F10): 1. src/lib/cloudSync.ts:47-56 — HMAC verification fail-open when CLOUD_SYNC_SECRET is unset. Now returns false (fail-closed) when a sigHeader is present but cannot be verified, instead of accepting any response. Legacy unverified mode (no sigHeader) is preserved. 2. src/lib/oauth/providers/antigravity.ts:101 — fetch() of userInfo during OAuth was swallowed silently, causing downstream code to use default projectId/tierId. Now logs warn with structured context. 3. open-sse/services/autoRefreshDaemon.ts:77,80 — periodic credential refresh errors were silently swallowed, allowing expired tokens to persist undetected. Now logs error per cycle. 4. src/lib/vscode/serviceTierVariants.ts:184 — request body parse failures during tier-rewrite were silently no-op'd. Now logs warn. Refactor: 5. src/lib/db/encryption.ts — migrated ~7 console.* calls to pino logger (encryptionLog). Following the PR #509 pattern of createLogger("db:encryption"). The catch fallback behavior is preserved exactly; only logging changes. Out of scope: - encryption.ts:144-148 plaintext fallback (separate spec at plans/encryption-failclosed-spec.md, deferred for design discussion) - src/lib/db/*.ts console.* migration for other files (separate PR) Co-authored-by: KooshaPari <koosha@example.com> * fix(governance): log empty catches in binaryManager + db/adapters (#512) 22 silent fail-open sites in the version manager + SQLite adapter layer were just swallows. Per the audit: - src/lib/versionManager/binaryManager.ts (6 catches): symlink/rollback/ remove errors were silent; filesystem permission bugs were invisible - src/lib/db/adapters/sqljsAdapter.ts (6 catches): save/close errors were silent; DB corruption during shutdown was undetectable - src/lib/db/adapters/betterSqliteAdapter.ts (1 catch): same pattern - src/lib/db/adapters/nodeSqliteAdapter.ts (2 catches): same pattern - src/lib/db/adapters/nodeSqliteShared.ts (7 catches): same pattern All 22 catches now log structured error context. Behavior unchanged - only logging added. Per AGENTS.md, no encryption keys or raw secrets are logged. TSC: 8 unchanged Tests: existing pass (any new behavior is logging-only) Co-authored-by: KooshaPari <koosha@example.com> * ci: pin cross-platform Rust toolchain * docs(plans): track 2 governance specs for future implementation (#511) Two deferred-implementation specs are now tracked in version control so the work product is preserved and discoverable. 1. plans/encryption-failclosed-spec.md (883 lines) — Hardening encryption.ts:144-148 (the silent plaintext fallback). Compares 3 design options with detailed tradeoffs. Recommended: C+A (startup canary + runtime throw). Registered as AgilePlus feature 'encryption-failclosed'. 2. plans/keyv-as-embedded-default-spec.md (698 lines) — Promote Keyv from optional driver to embedded default for fresh installs. Includes backwards-compat plan, config migration, and rollout sequence. Registered as AgilePlus feature 'keyv-as-embedded-default'. These specs intentionally do NOT include code changes — they are design-only and gate on answering the open questions before implementation. See spec section 9 for each spec's open questions. Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * wip: auto-commit daemon 2026-08-06T09:18:52Z (#505) Co-authored-by: Airlock Bot <airlock@phenoforge.local> * refactor(db): migrate console.* to pino in src/lib/db/ (#522) Follows the PR #506/#507/#509/#510 pattern of replacing console.* with createLogger("db:<subsystem>") to provide structured logging across the SQLite persistence layer. Files modified (~155 callsites across 17 files): - src/lib/db/adapters/driverFactory.ts - src/lib/db/adapters/sqljsAdapter.ts - src/lib/db/apiKeys.ts - src/lib/db/backup.ts - src/lib/db/cleanup.ts (~30 sites) - src/lib/db/core.ts (~30 sites) - src/lib/db/migrationRunner.ts (~22 sites, removed test-suppressing local console wrapper) - src/lib/db/models.ts - src/lib/db/optimizationSettings.ts - src/lib/db/providers.ts - src/lib/db/quotaPools.ts - src/lib/db/quotaSnapshots.ts - src/lib/db/schemaColumns.ts (~35 sites) - src/lib/db/sessionAccountAffinity.ts - src/lib/db/settings.ts - src/lib/db/settings/cacheMetrics.ts - src/lib/db/stateReset.ts Per AGENTS.md guidance, never log SQLite encryption keys or raw secrets; all logger calls redact sensitive material. Behavior preservation: - All success-path behavior unchanged - Only the logging mechanism changes - Targeted tests pass One console.error preserved in core.ts:migrateFromJson because tests/unit/db-core-migration.test.ts overrides console.error to detect the failure; both console.error and log.error are emitted so the test passes and pino is the canonical sink. Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * ci: use cache-pinned Trunk action --------- Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Airlock Bot <airlock@phenoforge.local>
Follows the PR #506/#507/#509/#510/#512/#518/#521/#522 pattern of replacing console.* with createLogger("domain:subsystem") to provide structured logging across the OmniRoute codebase. PR #522 already migrated src/lib/db/*.ts (~155 callsites). This PR migrates ~80 additional callsites across 37 files in: - src/lib/resilience/* (normalize.ts, anomalyHook.ts) - src/lib/oauth/* (connectionPersistence.ts) - src/lib/vscode/* (tokenizedRequest.ts, dual-emit for test capture) - src/lib/services/* (ringBuffer.ts, bootstrap.ts, embedWsProxy.ts, modelSync.ts) - src/lib/sseTextTransform.ts, src/lib/dataPaths.ts, src/lib/initCloudSync.ts - src/lib/events/eventBus.ts, src/lib/jobs/{budgetResetJob,reasoningCacheCleanupJob}.ts - src/lib/cloudSync.ts, src/lib/localHealthCheck.ts - src/lib/arenaEloSync.ts, src/lib/pricingSync.ts, src/lib/modelsDevSync.ts - src/lib/tokenHealthCheck.ts, src/lib/gracefulShutdown.ts - src/lib/apiBridgeServer.ts, src/lib/proxyLogger.ts - src/lib/middleware/registry.ts, src/lib/quota/connectionRecovery.ts - src/lib/credentialHealth/scheduler.ts - src/middleware/promptInjectionGuard.ts - src/server/ws/liveServer.ts (preserves [LiveWS] startup banner via log.info) - src/sse/services/auth.ts, src/sse/services/streamState.ts - open-sse/config/{constants,credentialLoader}.ts - open-sse/services/{autoRefreshDaemon,quotaMonitor}.ts - open-sse/mcp-server/audit.ts - open-sse/utils/proxyFetch.ts - open-sse/handlers/chatCore.ts (account fallback warnings) User-facing startup banners and intentional CLI output are preserved: - src/server/ws/liveServer.ts '[LiveWS] Dashboard WebSocket server listening' (now via log.info with structured host/port) - src/lib/vscode/tokenizedRequest.ts '[VSCODE][SECURITY]' warning kept as console.warn alongside log.warn so tests/unit/vscode-token-in-url-warning.test.ts (which captures console.warn to verify once-per-process dedup) keeps passing — same pattern as PR #522's preservation in db/core.ts:migrateFromJson - src/lib/oauth/utils/ui.ts (CLI formatting with picocolors) preserved as console - src/mitm/* (CLI-driven tooling) preserved - Next.js dashboard React components preserved (browser console, not server-side) Behavior preservation: - All success-path behavior unchanged - Only the logging mechanism changes - TSC baseline (typecheck-core.json) remains 0 errors - Targeted tests pass: resilience-settings-normalize-split (9/9), resilience-settings-stream-recovery (9/9), resilience-settings-provider-breaker (9/9), oauth-refresh-error-resilience (12/12), vscode-tokenized-request (3/3), vscode-token-in-url-warning (4/4), services/embedWsProxy (30/30) Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…ollowup) (#526) * chore(governance): rebase mergify config request-review fixes onto main * fix(desktop): target fork-owned Electron releases * ci: align workflows with selected action policy * fix(governance): replace silent try/catch with explicit log.error in 5 modules (#506) Builds on PR #505 (quota keystore type-drift fix). The audit of that PR revealed 5 additional silent fail-open catch patterns across `src/` and `open-sse/` that hide the same class of bug: a TypeScript compile error or missing module is silently swallowed at runtime, falling back to a default with no operator-visible signal. This commit replaces those silent catches with explicit `log.error` calls that surface the actual error to monitoring. Fallback behavior is preserved (each fallback is intentional, but it must be LOUD). Changes: 1. `src/lib/quota/storeFactory.ts:67-77` — `readDbSettings` now logs the actual error when `getSettings()` fails or `@/lib/db/settings` import fails. Same root cause as the previously-fixed Keyv/Redis catches. 2. `src/lib/quota/storeFactory.ts:138-147` — Redis driver catch upgraded from `log.warn` to `log.error`. Includes the configured Redis URL with the password segment redacted (`:***@`). 3. `src/lib/resilience/anomalyHook.ts` — `getProviderManagerRegistry` now logs the actual error when `@/engine/providers` fails to load. Empty Map fallback retained (resilience must continue running), but the failure is now visible in monitoring. 4. `open-sse/services/tierResolver.ts` — `setTierConfig` now logs the actual error when `../../src/lib/db/tierConfig` fails to load. `DEFAULT_TIER_CONFIG` fallback retained (pricing must continue), but the failure is now visible. 5. `open-sse/config/credentialLoader.ts` — `resolveCredentialsPath` now uses `log.error` (pino) instead of `console.warn`. Includes both the original error and the fallback path. Security-sensitive path; must keep working, but the failure must be loud. 6. `.gitignore` — exclude `.agileplus/` and `agileplus-*.db*` (local AgilePlus DB state, regenerated from `.md` specs via `agileplus specify`). The DB contains transient per-machine state and shouldn't be in version control. Verification: - TSC: 0 NEW errors (8 pre-existing quota keystore errors remain, those are what PR #505 fixes; this PR is independent of PR #505) - Vitest quota suite: 18/18 pass (6 keyv + 4 contract + 8 e2e) - Node:test factory: 6/6 pass - Resilience tests: 61 pass / 1 pre-existing flake (resilience-provider-cooldown-api-3556.test.ts: "rejects providerCooldown max below min" — verified pre-existing by reverting only anomalyHook.ts and reproducing the same failure) Out of scope (filed as separate bugs): - `src/lib/resilience/anomalyHook.ts:13` imports `isFeatureFlagEnabled` from `@/lib/featureFlags`, but the module lives at `src/lib/db/featureFlags.ts`. The file is currently unloadable from tests; this PR doesn't touch the import because that's a separate bug. - The Resilience subagent identified but did not fix the `tsconfig.typecheck-core.json` doesn't include `src/lib/resilience/` files — separate follow-up. Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(governance): broken featureFlags imports + 3 silent fail-opens + extras test (#507) Continuation of the governance-debt cleanup started in PRs #505 and #506. Six independent fixes, each addressing a class of silent-failure pattern that the audits surfaced. Changes: 1. **`src/lib/resilience/anomalyHook.ts:12`** — Broken import path. `isFeatureFlagEnabled` was imported from `@/lib/featureFlags`, but the module lives at `@/shared/utils/featureFlags`. This bug was masked because `tsconfig.typecheck-core.json` does not include `src/lib/resilience/` and no test loads the module successfully. After the fix, the module loads and exports the expected surface. 2. **`src/server-init.ts:128`** — Same broken import path. The surrounding try/catch at lines 130-139 silently swallowed the import failure. Fix: correct the path AND upgrade the catch log from `warn` to `error` (matches PR #506 pattern). 3. **`src/lib/versionManager/processManager.ts:155`** — `getProcessInfo` catch returned `{pid, alive: true}` after `ps`/readFile failures, which lies when the process is actually gone. Fix: catch now logs the error and returns `{pid, alive: false}` (honest about not being able to read process state). 4. **`src/server/ws/liveServer.ts:479`** — `loadAuthModule().catch(() => {})` silently swallowed initial auth module load failures, allowing the WS server to come up without auth configured. Fix: catch now logs `log.error`; fallback behavior preserved per the existing comment ("handler retries the import lazily"). 5. **`src/lib/machineToken.ts:1-10`** — Crypto-relevant: empty catch around `require("node-machine-id")` silently fell back to `() => ""`, which collapses HMAC inputs to a constant. Fix: catch now logs `log.error` with security-context message, gated by a `fallbackLogged` flag so the log fires only once per process (avoiding log spam from any downstream reload). 6. **`tests/unit/quota/keyvQuotaStoreExtras.test.ts`** (new) — Closes spec §8.2 reachability test gap. 5 sanity tests for the `recordPlanUsage` / `upsertProviderPlan` / `listProviderPlans` / `setPools` / `getPool` surface on KeyvQuotaStore. Note: this branch is based on `origin/agent/migration-version-collision-fix` (pre-PR-#505), so the methods live directly on KeyvQuotaStore. When PR #505 lands, update the test to import from `keyvQuotaStoreExtras.ts` instead. Verification: - TSC error count: 8 unchanged (all pre-existing quota keystore errors that PR #505 fixes; this PR is independent of #505) - Vitest extras test: 5/5 pass - Node:test combined (processManager + machineToken + WS): 47/47 pass - All success-path behavior preserved; only catch/fallback paths now log Out of scope (separate PRs): - Promote Keyv to "embedded default" driver (spec §10) - Pre-existing e2e failure at `tests/e2e/quota-store.e2e.ts:117` (poolUsageWithDimensions shape mismatch — fixed in PR #505) Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(security): log 3 crypto-relevant silent catches (rebased onto canonical base) (#509) This branch has been surgically rebased onto origin/agent/migration-version-collision-fix to remove accidental contamination from PR #507's branch base. In all three cases, the empty-string return collapses HMAC/HMAC-SHA256 inputs into a constant-key value, so security-relevant operations on the fallback path produce identical tokens regardless of input. Fixes: 1. src/lib/machineToken.ts:44 - getMachineTokenSync catch: log.error + return "" 2. src/lib/machineToken.ts:62 - getLegacyCliTokenSync catch: log.error + return "" 3. src/lib/db/encryption.ts:87-95 - getLegacyDynamicKey catch: added pino logger (createLogger("db:encryption")) + log.error instead of returning null silently 4. (incidental) src/lib/machineToken.ts module-load catch: also gains log.error so the new runtime catches have a 'log' constant to reference. This subsumes PR #507's machineToken.ts hunk. NOTE: PR #507 will need its machineToken.ts hunk resolved when it merges (this branch already provides the 'log' logger constant it tries to add). Verification: - TSC: 8 unchanged (pre-existing quota keystore errors, PR #505 territory) - Targeted machineToken + encryption unit tests pass - All success-path behaviors preserved Co-authored-by: KooshaPari <koosha@example.com> * fix(security): 4 audit findings + migrate encryption.ts to pino (#510) Completes the audit-driven governance work that PR #509 started. Eight independent fixes: Security fixes (audit findings F5, F6, F9, F10): 1. src/lib/cloudSync.ts:47-56 — HMAC verification fail-open when CLOUD_SYNC_SECRET is unset. Now returns false (fail-closed) when a sigHeader is present but cannot be verified, instead of accepting any response. Legacy unverified mode (no sigHeader) is preserved. 2. src/lib/oauth/providers/antigravity.ts:101 — fetch() of userInfo during OAuth was swallowed silently, causing downstream code to use default projectId/tierId. Now logs warn with structured context. 3. open-sse/services/autoRefreshDaemon.ts:77,80 — periodic credential refresh errors were silently swallowed, allowing expired tokens to persist undetected. Now logs error per cycle. 4. src/lib/vscode/serviceTierVariants.ts:184 — request body parse failures during tier-rewrite were silently no-op'd. Now logs warn. Refactor: 5. src/lib/db/encryption.ts — migrated ~7 console.* calls to pino logger (encryptionLog). Following the PR #509 pattern of createLogger("db:encryption"). The catch fallback behavior is preserved exactly; only logging changes. Out of scope: - encryption.ts:144-148 plaintext fallback (separate spec at plans/encryption-failclosed-spec.md, deferred for design discussion) - src/lib/db/*.ts console.* migration for other files (separate PR) Co-authored-by: KooshaPari <koosha@example.com> * fix(governance): log empty catches in binaryManager + db/adapters (#512) 22 silent fail-open sites in the version manager + SQLite adapter layer were just swallows. Per the audit: - src/lib/versionManager/binaryManager.ts (6 catches): symlink/rollback/ remove errors were silent; filesystem permission bugs were invisible - src/lib/db/adapters/sqljsAdapter.ts (6 catches): save/close errors were silent; DB corruption during shutdown was undetectable - src/lib/db/adapters/betterSqliteAdapter.ts (1 catch): same pattern - src/lib/db/adapters/nodeSqliteAdapter.ts (2 catches): same pattern - src/lib/db/adapters/nodeSqliteShared.ts (7 catches): same pattern All 22 catches now log structured error context. Behavior unchanged - only logging added. Per AGENTS.md, no encryption keys or raw secrets are logged. TSC: 8 unchanged Tests: existing pass (any new behavior is logging-only) Co-authored-by: KooshaPari <koosha@example.com> * ci: pin cross-platform Rust toolchain * docs(plans): track 2 governance specs for future implementation (#511) Two deferred-implementation specs are now tracked in version control so the work product is preserved and discoverable. 1. plans/encryption-failclosed-spec.md (883 lines) — Hardening encryption.ts:144-148 (the silent plaintext fallback). Compares 3 design options with detailed tradeoffs. Recommended: C+A (startup canary + runtime throw). Registered as AgilePlus feature 'encryption-failclosed'. 2. plans/keyv-as-embedded-default-spec.md (698 lines) — Promote Keyv from optional driver to embedded default for fresh installs. Includes backwards-compat plan, config migration, and rollout sequence. Registered as AgilePlus feature 'keyv-as-embedded-default'. These specs intentionally do NOT include code changes — they are design-only and gate on answering the open questions before implementation. See spec section 9 for each spec's open questions. Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * wip: auto-commit daemon 2026-08-06T09:18:52Z (#505) Co-authored-by: Airlock Bot <airlock@phenoforge.local> * refactor(db): migrate console.* to pino in src/lib/db/ (#522) Follows the PR #506/#507/#509/#510 pattern of replacing console.* with createLogger("db:<subsystem>") to provide structured logging across the SQLite persistence layer. Files modified (~155 callsites across 17 files): - src/lib/db/adapters/driverFactory.ts - src/lib/db/adapters/sqljsAdapter.ts - src/lib/db/apiKeys.ts - src/lib/db/backup.ts - src/lib/db/cleanup.ts (~30 sites) - src/lib/db/core.ts (~30 sites) - src/lib/db/migrationRunner.ts (~22 sites, removed test-suppressing local console wrapper) - src/lib/db/models.ts - src/lib/db/optimizationSettings.ts - src/lib/db/providers.ts - src/lib/db/quotaPools.ts - src/lib/db/quotaSnapshots.ts - src/lib/db/schemaColumns.ts (~35 sites) - src/lib/db/sessionAccountAffinity.ts - src/lib/db/settings.ts - src/lib/db/settings/cacheMetrics.ts - src/lib/db/stateReset.ts Per AGENTS.md guidance, never log SQLite encryption keys or raw secrets; all logger calls redact sensitive material. Behavior preservation: - All success-path behavior unchanged - Only the logging mechanism changes - Targeted tests pass One console.error preserved in core.ts:migrateFromJson because tests/unit/db-core-migration.test.ts overrides console.error to detect the failure; both console.error and log.error are emitted so the test passes and pino is the canonical sink. Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * ci: use cache-pinned Trunk action * fix(governance): log empty catches + weak peer-dep fallbacks (audit followup) Continues the audit-driven governance cleanup that PRs #506, #507, #509, #510, #512, #522, #525 started. This batch addresses the remaining empty catches and weak peer-dependency fallbacks in plugins, embeddings, oauth, monitoring, and combo paths. Empty catches fixed (~6 sites): - src/lib/plugins/loader.ts:200, 301 (plugin load/cleanup) - src/lib/plugins/manager.ts:151, 270 (plugin staging cleanup) - src/lib/embeddings/service.ts:50, 73 (embedding combo lookup) - src/lib/credentialHealth/scheduler.ts:122 (credential health sweep) - src/lib/usage/usageStats.ts:301 (usage stats) - src/lib/oauth/providers/kimi-coding.ts:44 (OAuth provider init) Weak peer-dep fallbacks fixed (~10 sites): - src/lib/a2a/skills/providerDiscovery.ts:388 (MCP module load) - open-sse/rpc/dispatchEdges.ts:189, 199, 209 (FFI/UDS transport — HIGH RISK, used log.error not warn) - src/lib/monitoring/providerHealthAutopilot.ts:262 (quota monitor) - open-sse/services/combo.ts:2222 (fetchCodexQuota) - open-sse/services/combo/quotaStrategies.ts:431 (getRuntimeProviderProfile) - open-sse/handlers/chatCore/codexFailover.ts:19 (provider connection) - open-sse/handlers/chatCore/comboContextCache.ts:57 (proxy config) All conversions preserve existing behavior (return null/false/etc.). Only logging is added — no semantic change. Test results unchanged from baseline. TSC: 8 unchanged (pre-existing quota keystore errors, PR #505 territory). --------- Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Airlock Bot <airlock@phenoforge.local>
* chore(governance): rebase mergify config request-review fixes onto main * fix(desktop): target fork-owned Electron releases * ci: align workflows with selected action policy * fix(governance): replace silent try/catch with explicit log.error in 5 modules (#506) Builds on PR #505 (quota keystore type-drift fix). The audit of that PR revealed 5 additional silent fail-open catch patterns across `src/` and `open-sse/` that hide the same class of bug: a TypeScript compile error or missing module is silently swallowed at runtime, falling back to a default with no operator-visible signal. This commit replaces those silent catches with explicit `log.error` calls that surface the actual error to monitoring. Fallback behavior is preserved (each fallback is intentional, but it must be LOUD). Changes: 1. `src/lib/quota/storeFactory.ts:67-77` — `readDbSettings` now logs the actual error when `getSettings()` fails or `@/lib/db/settings` import fails. Same root cause as the previously-fixed Keyv/Redis catches. 2. `src/lib/quota/storeFactory.ts:138-147` — Redis driver catch upgraded from `log.warn` to `log.error`. Includes the configured Redis URL with the password segment redacted (`:***@`). 3. `src/lib/resilience/anomalyHook.ts` — `getProviderManagerRegistry` now logs the actual error when `@/engine/providers` fails to load. Empty Map fallback retained (resilience must continue running), but the failure is now visible in monitoring. 4. `open-sse/services/tierResolver.ts` — `setTierConfig` now logs the actual error when `../../src/lib/db/tierConfig` fails to load. `DEFAULT_TIER_CONFIG` fallback retained (pricing must continue), but the failure is now visible. 5. `open-sse/config/credentialLoader.ts` — `resolveCredentialsPath` now uses `log.error` (pino) instead of `console.warn`. Includes both the original error and the fallback path. Security-sensitive path; must keep working, but the failure must be loud. 6. `.gitignore` — exclude `.agileplus/` and `agileplus-*.db*` (local AgilePlus DB state, regenerated from `.md` specs via `agileplus specify`). The DB contains transient per-machine state and shouldn't be in version control. Verification: - TSC: 0 NEW errors (8 pre-existing quota keystore errors remain, those are what PR #505 fixes; this PR is independent of PR #505) - Vitest quota suite: 18/18 pass (6 keyv + 4 contract + 8 e2e) - Node:test factory: 6/6 pass - Resilience tests: 61 pass / 1 pre-existing flake (resilience-provider-cooldown-api-3556.test.ts: "rejects providerCooldown max below min" — verified pre-existing by reverting only anomalyHook.ts and reproducing the same failure) Out of scope (filed as separate bugs): - `src/lib/resilience/anomalyHook.ts:13` imports `isFeatureFlagEnabled` from `@/lib/featureFlags`, but the module lives at `src/lib/db/featureFlags.ts`. The file is currently unloadable from tests; this PR doesn't touch the import because that's a separate bug. - The Resilience subagent identified but did not fix the `tsconfig.typecheck-core.json` doesn't include `src/lib/resilience/` files — separate follow-up. Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(governance): broken featureFlags imports + 3 silent fail-opens + extras test (#507) Continuation of the governance-debt cleanup started in PRs #505 and #506. Six independent fixes, each addressing a class of silent-failure pattern that the audits surfaced. Changes: 1. **`src/lib/resilience/anomalyHook.ts:12`** — Broken import path. `isFeatureFlagEnabled` was imported from `@/lib/featureFlags`, but the module lives at `@/shared/utils/featureFlags`. This bug was masked because `tsconfig.typecheck-core.json` does not include `src/lib/resilience/` and no test loads the module successfully. After the fix, the module loads and exports the expected surface. 2. **`src/server-init.ts:128`** — Same broken import path. The surrounding try/catch at lines 130-139 silently swallowed the import failure. Fix: correct the path AND upgrade the catch log from `warn` to `error` (matches PR #506 pattern). 3. **`src/lib/versionManager/processManager.ts:155`** — `getProcessInfo` catch returned `{pid, alive: true}` after `ps`/readFile failures, which lies when the process is actually gone. Fix: catch now logs the error and returns `{pid, alive: false}` (honest about not being able to read process state). 4. **`src/server/ws/liveServer.ts:479`** — `loadAuthModule().catch(() => {})` silently swallowed initial auth module load failures, allowing the WS server to come up without auth configured. Fix: catch now logs `log.error`; fallback behavior preserved per the existing comment ("handler retries the import lazily"). 5. **`src/lib/machineToken.ts:1-10`** — Crypto-relevant: empty catch around `require("node-machine-id")` silently fell back to `() => ""`, which collapses HMAC inputs to a constant. Fix: catch now logs `log.error` with security-context message, gated by a `fallbackLogged` flag so the log fires only once per process (avoiding log spam from any downstream reload). 6. **`tests/unit/quota/keyvQuotaStoreExtras.test.ts`** (new) — Closes spec §8.2 reachability test gap. 5 sanity tests for the `recordPlanUsage` / `upsertProviderPlan` / `listProviderPlans` / `setPools` / `getPool` surface on KeyvQuotaStore. Note: this branch is based on `origin/agent/migration-version-collision-fix` (pre-PR-#505), so the methods live directly on KeyvQuotaStore. When PR #505 lands, update the test to import from `keyvQuotaStoreExtras.ts` instead. Verification: - TSC error count: 8 unchanged (all pre-existing quota keystore errors that PR #505 fixes; this PR is independent of #505) - Vitest extras test: 5/5 pass - Node:test combined (processManager + machineToken + WS): 47/47 pass - All success-path behavior preserved; only catch/fallback paths now log Out of scope (separate PRs): - Promote Keyv to "embedded default" driver (spec §10) - Pre-existing e2e failure at `tests/e2e/quota-store.e2e.ts:117` (poolUsageWithDimensions shape mismatch — fixed in PR #505) Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(security): log 3 crypto-relevant silent catches (rebased onto canonical base) (#509) This branch has been surgically rebased onto origin/agent/migration-version-collision-fix to remove accidental contamination from PR #507's branch base. In all three cases, the empty-string return collapses HMAC/HMAC-SHA256 inputs into a constant-key value, so security-relevant operations on the fallback path produce identical tokens regardless of input. Fixes: 1. src/lib/machineToken.ts:44 - getMachineTokenSync catch: log.error + return "" 2. src/lib/machineToken.ts:62 - getLegacyCliTokenSync catch: log.error + return "" 3. src/lib/db/encryption.ts:87-95 - getLegacyDynamicKey catch: added pino logger (createLogger("db:encryption")) + log.error instead of returning null silently 4. (incidental) src/lib/machineToken.ts module-load catch: also gains log.error so the new runtime catches have a 'log' constant to reference. This subsumes PR #507's machineToken.ts hunk. NOTE: PR #507 will need its machineToken.ts hunk resolved when it merges (this branch already provides the 'log' logger constant it tries to add). Verification: - TSC: 8 unchanged (pre-existing quota keystore errors, PR #505 territory) - Targeted machineToken + encryption unit tests pass - All success-path behaviors preserved Co-authored-by: KooshaPari <koosha@example.com> * fix(security): 4 audit findings + migrate encryption.ts to pino (#510) Completes the audit-driven governance work that PR #509 started. Eight independent fixes: Security fixes (audit findings F5, F6, F9, F10): 1. src/lib/cloudSync.ts:47-56 — HMAC verification fail-open when CLOUD_SYNC_SECRET is unset. Now returns false (fail-closed) when a sigHeader is present but cannot be verified, instead of accepting any response. Legacy unverified mode (no sigHeader) is preserved. 2. src/lib/oauth/providers/antigravity.ts:101 — fetch() of userInfo during OAuth was swallowed silently, causing downstream code to use default projectId/tierId. Now logs warn with structured context. 3. open-sse/services/autoRefreshDaemon.ts:77,80 — periodic credential refresh errors were silently swallowed, allowing expired tokens to persist undetected. Now logs error per cycle. 4. src/lib/vscode/serviceTierVariants.ts:184 — request body parse failures during tier-rewrite were silently no-op'd. Now logs warn. Refactor: 5. src/lib/db/encryption.ts — migrated ~7 console.* calls to pino logger (encryptionLog). Following the PR #509 pattern of createLogger("db:encryption"). The catch fallback behavior is preserved exactly; only logging changes. Out of scope: - encryption.ts:144-148 plaintext fallback (separate spec at plans/encryption-failclosed-spec.md, deferred for design discussion) - src/lib/db/*.ts console.* migration for other files (separate PR) Co-authored-by: KooshaPari <koosha@example.com> * fix(governance): log empty catches in binaryManager + db/adapters (#512) 22 silent fail-open sites in the version manager + SQLite adapter layer were just swallows. Per the audit: - src/lib/versionManager/binaryManager.ts (6 catches): symlink/rollback/ remove errors were silent; filesystem permission bugs were invisible - src/lib/db/adapters/sqljsAdapter.ts (6 catches): save/close errors were silent; DB corruption during shutdown was undetectable - src/lib/db/adapters/betterSqliteAdapter.ts (1 catch): same pattern - src/lib/db/adapters/nodeSqliteAdapter.ts (2 catches): same pattern - src/lib/db/adapters/nodeSqliteShared.ts (7 catches): same pattern All 22 catches now log structured error context. Behavior unchanged - only logging added. Per AGENTS.md, no encryption keys or raw secrets are logged. TSC: 8 unchanged Tests: existing pass (any new behavior is logging-only) Co-authored-by: KooshaPari <koosha@example.com> * ci: pin cross-platform Rust toolchain * docs(plans): track 2 governance specs for future implementation (#511) Two deferred-implementation specs are now tracked in version control so the work product is preserved and discoverable. 1. plans/encryption-failclosed-spec.md (883 lines) — Hardening encryption.ts:144-148 (the silent plaintext fallback). Compares 3 design options with detailed tradeoffs. Recommended: C+A (startup canary + runtime throw). Registered as AgilePlus feature 'encryption-failclosed'. 2. plans/keyv-as-embedded-default-spec.md (698 lines) — Promote Keyv from optional driver to embedded default for fresh installs. Includes backwards-compat plan, config migration, and rollout sequence. Registered as AgilePlus feature 'keyv-as-embedded-default'. These specs intentionally do NOT include code changes — they are design-only and gate on answering the open questions before implementation. See spec section 9 for each spec's open questions. Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * wip: auto-commit daemon 2026-08-06T09:18:52Z (#505) Co-authored-by: Airlock Bot <airlock@phenoforge.local> * refactor(db): migrate console.* to pino in src/lib/db/ (#522) Follows the PR #506/#507/#509/#510 pattern of replacing console.* with createLogger("db:<subsystem>") to provide structured logging across the SQLite persistence layer. Files modified (~155 callsites across 17 files): - src/lib/db/adapters/driverFactory.ts - src/lib/db/adapters/sqljsAdapter.ts - src/lib/db/apiKeys.ts - src/lib/db/backup.ts - src/lib/db/cleanup.ts (~30 sites) - src/lib/db/core.ts (~30 sites) - src/lib/db/migrationRunner.ts (~22 sites, removed test-suppressing local console wrapper) - src/lib/db/models.ts - src/lib/db/optimizationSettings.ts - src/lib/db/providers.ts - src/lib/db/quotaPools.ts - src/lib/db/quotaSnapshots.ts - src/lib/db/schemaColumns.ts (~35 sites) - src/lib/db/sessionAccountAffinity.ts - src/lib/db/settings.ts - src/lib/db/settings/cacheMetrics.ts - src/lib/db/stateReset.ts Per AGENTS.md guidance, never log SQLite encryption keys or raw secrets; all logger calls redact sensitive material. Behavior preservation: - All success-path behavior unchanged - Only the logging mechanism changes - Targeted tests pass One console.error preserved in core.ts:migrateFromJson because tests/unit/db-core-migration.test.ts overrides console.error to detect the failure; both console.error and log.error are emitted so the test passes and pino is the canonical sink. Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * ci: use cache-pinned Trunk action * refactor: migrate console.* to pino in remaining src/ + open-sse/ Follows the PR #506/#507/#509/#510/#512/#518/#521/#522 pattern of replacing console.* with createLogger("domain:subsystem") to provide structured logging across the OmniRoute codebase. PR #522 already migrated src/lib/db/*.ts (~155 callsites). This PR migrates ~80 additional callsites across 37 files in: - src/lib/resilience/* (normalize.ts, anomalyHook.ts) - src/lib/oauth/* (connectionPersistence.ts) - src/lib/vscode/* (tokenizedRequest.ts, dual-emit for test capture) - src/lib/services/* (ringBuffer.ts, bootstrap.ts, embedWsProxy.ts, modelSync.ts) - src/lib/sseTextTransform.ts, src/lib/dataPaths.ts, src/lib/initCloudSync.ts - src/lib/events/eventBus.ts, src/lib/jobs/{budgetResetJob,reasoningCacheCleanupJob}.ts - src/lib/cloudSync.ts, src/lib/localHealthCheck.ts - src/lib/arenaEloSync.ts, src/lib/pricingSync.ts, src/lib/modelsDevSync.ts - src/lib/tokenHealthCheck.ts, src/lib/gracefulShutdown.ts - src/lib/apiBridgeServer.ts, src/lib/proxyLogger.ts - src/lib/middleware/registry.ts, src/lib/quota/connectionRecovery.ts - src/lib/credentialHealth/scheduler.ts - src/middleware/promptInjectionGuard.ts - src/server/ws/liveServer.ts (preserves [LiveWS] startup banner via log.info) - src/sse/services/auth.ts, src/sse/services/streamState.ts - open-sse/config/{constants,credentialLoader}.ts - open-sse/services/{autoRefreshDaemon,quotaMonitor}.ts - open-sse/mcp-server/audit.ts - open-sse/utils/proxyFetch.ts - open-sse/handlers/chatCore.ts (account fallback warnings) User-facing startup banners and intentional CLI output are preserved: - src/server/ws/liveServer.ts '[LiveWS] Dashboard WebSocket server listening' (now via log.info with structured host/port) - src/lib/vscode/tokenizedRequest.ts '[VSCODE][SECURITY]' warning kept as console.warn alongside log.warn so tests/unit/vscode-token-in-url-warning.test.ts (which captures console.warn to verify once-per-process dedup) keeps passing — same pattern as PR #522's preservation in db/core.ts:migrateFromJson - src/lib/oauth/utils/ui.ts (CLI formatting with picocolors) preserved as console - src/mitm/* (CLI-driven tooling) preserved - Next.js dashboard React components preserved (browser console, not server-side) Behavior preservation: - All success-path behavior unchanged - Only the logging mechanism changes - TSC baseline (typecheck-core.json) remains 0 errors - Targeted tests pass: resilience-settings-normalize-split (9/9), resilience-settings-stream-recovery (9/9), resilience-settings-provider-breaker (9/9), oauth-refresh-error-resilience (12/12), vscode-tokenized-request (3/3), vscode-token-in-url-warning (4/4), services/embedWsProxy (30/30) Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: KooshaPari <koosha@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Airlock Bot <airlock@phenoforge.local>
Three new check scripts in scripts/check/ + audit doc: 1. scripts/check/crypto-failures.ts: detects crypto-relevant silent catches (createHmac, createHash, scryptSync, randomBytes, jwtVerify, etc. followed by silent catch blocks). Reports findings to stderr. 2. scripts/check/console-in-src.ts: detects console.* callsites in src/lib/ + open-sse/ (excluding tests, proxyLogger.ts, consoleInterceptor.ts, intentional CLI tools). 3. scripts/check/broken-imports.ts: scans for known broken import paths. Default registry includes @/lib/featureFlags (should be @/shared/utils/featureFlags — PR #507 fixed all callers). Add new entries as drift is discovered. 4. New npm scripts: - check:crypto-failures - check:console-in-src - check:broken-imports - check:governance (combined; runs check:fail-open + check:crypto-failures + check:broken-imports) 5. docs/governance-audit-summary-2026-08.md: documents the audit methodology, ~100 silent fail-open patterns fixed across 50+ files, ~245 console.* migrated to pino, the 13 PRs shipped (#505-#527), patterns to avoid, and lessons learned. Note: GitHub Actions CI is billing-disabled for this account (per /Users/kooshapari/CodeProjects/CLAUDE.md), so these checks run locally only. Run npm run check:governance before merging any PR. Co-authored-by: KooshaPari <koosha@example.com>
Implements Option C+A (startup canary + runtime throw) per plans/encryption-failclosed-spec.md. The encrypt() fallback to plaintext (line 144-148) is the highest-risk governance-debt finding from the recent audit. When STORAGE_ENCRYPTION_KEY is set but crypto fails (bad key material, OOM, native binding broken), tokens silently store as plaintext. This is undetectable from operator view. Changes: 1. New EncryptionRuntimeError class — thrown when crypto pipeline fails after key was successfully derived 2. validateEncryptionAtStartup() — runs a known-plaintext round-trip to detect broken encryption config before serving traffic 3. src/instrumentation-node.ts — calls the startup canary before ensureSecrets() and any DB init; refuses to start if encryption is broken (process.exit(1)) 4. encryptConnectionFields() return type: T -> T | null to signal caller when encryption failed; providers.ts:348,544 callers updated to throw a clear error and skip the DB write 5. commandCodeAuth.ts:142 wraps encrypt() in try/catch; returns null on EncryptionRuntimeError so the session is not poisoned with plaintext apiKey 6. src/lib/db/encryptionStartup.ts (new) — async wrapper runEncryptionStartupCanary() + process-exiting runEncryptionStartupCheck() helpers 7. .env.example documents the new behaviour (EncryptionRuntimeError and StartupEncryptionError error names, remediation hint) State A preserved exactly: when STORAGE_ENCRYPTION_KEY is unset, passthrough returns plaintext (no breaking change for dev/test setups). Out of scope (per spec): - Migration of legacy ciphertext - Key rotation - Hardware-backed keys Refs: PR #507 F3 follow-up. Closes State B from audit. Verification: - node:test encryption suite: 23/23 pass (db-encryption, encryption-error-handling, encryption-strict, encryption-connection-fields-failclosed, db-command-code-auth) - vitest failclosed+startup suite: 14/14 pass - providers-batch-update: 12/12 pass (no regression) - TSC: 1 unrelated pre-existing error in apiKeys.ts (no new errors) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>



User description
fix(governance): broken featureFlags imports + 3 silent fail-opens + extras test
Continuation of the governance-debt cleanup started in PRs #505 and #506.
Six independent fixes, each addressing a class of silent-failure pattern
that the audits surfaced.
Changes:
src/lib/resilience/anomalyHook.ts:12— Broken import path.isFeatureFlagEnabledwas imported from@/lib/featureFlags, butthe module lives at
@/shared/utils/featureFlags. This bug wasmasked because
tsconfig.typecheck-core.jsondoes not includesrc/lib/resilience/and no test loads the module successfully.After the fix, the module loads and exports the expected surface.
src/server-init.ts:128— Same broken import path. Thesurrounding try/catch at lines 130-139 silently swallowed the
import failure. Fix: correct the path AND upgrade the catch log
from
warntoerror(matches PR fix(governance): replace silent try/catch with explicit log.error in 5 modules #506 pattern).src/lib/versionManager/processManager.ts:155—getProcessInfocatch returned
{pid, alive: true}afterps/readFile failures,which lies when the process is actually gone. Fix: catch now
logs the error and returns
{pid, alive: false}(honest aboutnot being able to read process state).
src/server/ws/liveServer.ts:479—loadAuthModule().catch(() => {})silently swallowed initial auth module load failures, allowing the
WS server to come up without auth configured. Fix: catch now logs
log.error; fallback behavior preserved per the existing comment("handler retries the import lazily").
src/lib/machineToken.ts:1-10— Crypto-relevant: empty catcharound
require("node-machine-id")silently fell back to() => "", which collapses HMAC inputs to a constant. Fix: catchnow logs
log.errorwith security-context message, gated by afallbackLoggedflag so the log fires only once per process(avoiding log spam from any downstream reload).
tests/unit/quota/keyvQuotaStoreExtras.test.ts(new) — Closesspec §8.2 reachability test gap. 5 sanity tests for the
recordPlanUsage/upsertProviderPlan/listProviderPlans/setPools/getPoolsurface on KeyvQuotaStore. Note: thisbranch is based on
origin/agent/migration-version-collision-fix(pre-PR-fix(quota): rewrite KeyvQuotaStore to satisfy QuotaStore interface (P0 type-drift) #505), so the methods live directly on KeyvQuotaStore.
When PR fix(quota): rewrite KeyvQuotaStore to satisfy QuotaStore interface (P0 type-drift) #505 lands, update the test to import from
keyvQuotaStoreExtras.tsinstead.Verification:
errors that PR fix(quota): rewrite KeyvQuotaStore to satisfy QuotaStore interface (P0 type-drift) #505 fixes; this PR is independent of fix(quota): rewrite KeyvQuotaStore to satisfy QuotaStore interface (P0 type-drift) #505)
Out of scope (separate PRs):
tests/e2e/quota-store.e2e.ts:117(poolUsageWithDimensions shape mismatch — fixed in PR fix(quota): rewrite KeyvQuotaStore to satisfy QuotaStore interface (P0 type-drift) #505)
Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
CodeAnt-AI Description
Fix silent governance failures and verify quota-store behavior
What Changed
Impact
✅ Self-healing telemetry starts when enabled✅ Accurate inactive-process reporting✅ Visible authentication and token-generation failures💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.