Reconcile the unknown-exception inventory with the shipped webhook, ProposalTools, and CLI boundaries - #2483
Conversation
OutboundWebhookDeliveryWorker.cs now persists the generic constant for unknown exceptions (#2474), so it joins PERSISTED_STATE_FILES. The real-tree scan stays at zero findings with no new allowlist entry.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Fresh-context independent review at exact head 425ec9d. Verdict: no CRITICAL or HIGH finding. Merge-blocking: none. Checked at the checkout: every rewritten R1, R2, and R7 row states a property that is true in the tree (the webhook unknown-exception arm persists the generic constant and logs the redacted summary once; ProposalTools routes every code through SanitizeLlmFailureMessage; the CLI top-level catch delegates to CliUnexpectedFailure with only PreMigrationBackupException keeping redacted authored text); every cited test name exists at the cited line in UnknownExceptionBoundaryProofTests, OutboundWebhookDeliveryWorkerTests, ProposalToolsErrorSafetyTests, and CliUnexpectedErrorSafetyTests; adding the webhook worker to PERSISTED_STATE_FILES creates no finding because no catch in that file touches .Message, .StackTrace, or .ToString() on the exception. Worker-run proof: guard tests 25/25, real tree 0 findings, docs governance and diff check clean. LOW, declined: the doc now carries two pin coordinate systems (some rows keep a1ed795 line numbers); stated honestly in the header, no false claim. Remaining gate: exact-head hosted ci-required green and the three-minute aging floor, then a merge commit. Part of #2351; the umbrella stays open. |
|
Session checkpoint: reviewed clean, no fix pending; merge under the normal gate once the Windows API Integration job at head 425ec9d is green and the aging floor has passed. Merge-tree against main is clean. |
|
Review gate (Codex credits exhausted, SC-9): one fresh-context reviewer audited every file:line and test-name citation in the changed inventory rows against the head — all MATCH except one cosmetic off-by-one (webhook catch is at OutboundWebhookDeliveryWorker.cs:233, not :232); the guard change is additive (adds the worker file to PERSISTED_STATE_FILES, no allowlist or rule relaxation). Verdict SHIP. LOWs declined as non-blocking: the :232/:233 nit; the new list-membership test cannot detect a rule-2 regression (the tree-clean test carries that); the CLI row wording attributes DomainException/usage message preservation to the boundary rather than the command layer. Merging once main's in-progress run completes. |
Summary
docs/security/UNKNOWN_EXCEPTION_SURFACE_INVENTORY.md(merged in #2470) was written againsta1ed795a7and still described R1, R2 and R7 as open. All three have since shipped. This PRreconciles the inventory with the tree and extends the guard to cover the newly-hardened surface.
Docs plus one list entry and one test — no production code changes.
8dbeb81cf).OutboundWebhookDeliveryWorker.cs:253-255persistsSensitiveDataRedactor.GenericUnexpectedFailureMessageinstead ofRedact($"...{ex.Message}"), and logs the exception exactly once against the delivery id viaSummarizeException(:248-252). Row and residual rewritten with those lines and the threepinning cases in
OutboundWebhookDeliveryWorkerTests(generalization-during-processing, HTTP 500,timeout).
ProposalTools.Error(Result)(ProposalTools.cs:191-193) now routesthrough
SanitizeLlmFailureMessage, matchingReadTools/WriteTools. CitesProposalToolsErrorSafetyTests.GetProposalStatus_KnownDomainFailureWithRedactablePattern_IsRedacted.57df469e2).Program.cs:20,125-127plusCommands/CliUnexpectedFailure.cs:27,46, pinned byCliUnexpectedErrorSafetyTests(11 cases). Aone-line note under the closure records that [CLI][Security] Give the standalone CLI a bounded always-on diagnostic sink for unexpected failures #2468 tracks the always-on diagnostic sink; the
companion failure file shipped harness-only.
UnknownExceptionBoundaryProofTests(Prove the correlated unknown-exception boundary end to end #2471) as the end-to-end pin for boththe unhandled-exception boundary and the
Resultmapper.a1ed795a7to5b2a3c742, and states honestly that only therows touched by these fixes plus the HTTP rows were re-read at that commit.
backend/src/Taskdeck.Api/Workers/OutboundWebhookDeliveryWorker.csadded toPERSISTED_STATE_FILESinscripts/check-unknown-exception-boundary.mjs, with no new allowlistentry — the fixed arm assigns the generic constant directly and references only
ex.GetType().Name/SummarizeException(ex)on the log path, neither of which rule 2 matches.One new test asserts the file is in the list. The inventory's guard section is updated for the new
list membership and for the fact that the reviewed guarded-ternary allowance in rule 1 is now
generic and no longer exercised by any shipped file.
Part of #2351. This PR intentionally does not close the umbrella issue.
Verification
Run at head in an isolated worktree detached from
origin/main5b2a3c742:node --test scripts/check-unknown-exception-boundary.test.mjs— 25 tests, 25 pass, 0 fail(24 before, plus the new persisted-state membership test).
node scripts/check-unknown-exception-boundary.mjs— "Unknown-exception boundary check passed.",exit 0, 0 findings on the real tree with the worker in
PERSISTED_STATE_FILES.node scripts/check-docs-governance.mjs— "Docs governance check passed.", exit 0.git diff --check— exit 0, no whitespace errors.5b2a3c742, nottaken from the PR descriptions: the webhook catch arm,
ProposalTools.Error(Result),Program.cs's top-level catch,CliUnexpectedFailure.cs, and the four test files' member names.The three merges cited (
8dbeb81cf,57df469e2,ca3f3e6b4) were confirmed ancestors of HEADwith
git merge-base --is-ancestor.UnhandledExceptionMiddleware.cs:60-63,65-69,ResultExtensions.cs:34-56,41-48,49-54,PipelineConfiguration.cs:116) were re-read and stillresolve correctly at
5b2a3c742.Not verified
test names cited in the doc were verified to exist by reading the test sources, not by running
them.
a1ed795a7line numbers, which may have drifted; the doc now says so explicitly rather thanimplying a whole-file re-pin.
unchanged apart from the one added file.