Skip to content

fix nine defects found auditing 3.0.0 - #65

Merged
arnelirobles merged 1 commit into
masterfrom
fix/3.0.1
Sep 29, 2026
Merged

arnelirobles merged 1 commit into
masterfrom
fix/3.0.1

Conversation

@arnelirobles

@arnelirobles arnelirobles commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Fixes nine defects found auditing 3.0.0 and bumps the version to 3.0.1.

  • A MultiResult failure printed [CODE] message for every error and ignored IncludeErrorMessage, IncludeErrorCode and IncludeExceptionDetails, so exception messages reached the response. It now follows the same rules as a single error, and returns 500 when any error carries an exception. New overload CreateFromMultiResult(result, options).
  • A success mapped to 204 or 304 wrote the value as a body, which Kestrel rejects. ToHttpResult and ToActionResult now send no body for those codes.
  • The ValueTask fast path threw delegate exceptions out of the call, while the pending path put them in the task. Both now fault the task. An already cancelled token gives a canceled task.
  • Message neutralising missed C1 controls, NEL, U+2028 and U+2029.
  • Truncation could split a surrogate pair.
  • ErrorStatusCodeMapper.GetStatusCode(default) threw on the null code. It now returns 400, or 500 with an exception.
  • MultiResult.Value after DisposeErrors threw ObjectDisposedException instead of InvalidOperationException.
  • ResultLogger awaits with ConfigureAwait(false).

Behaviour changes: MultiResult.Failure with no errors now throws ArgumentException. Combinators still forward a default(MultiResult) failure as before.

Proof: full suite green on net8.0 and net10.0, allocation gate included, 0 warnings. The new tests were run against master's source and fail there, apart from two that call the new overload and one guard that should pass on both.

Summary by CodeRabbit

  • Bug Fixes
    • Successful HTTP responses with status codes that forbid response bodies no longer include one.
    • Multi-error responses now use status 500 when they contain exceptions, while keeping exception details hidden by default.
    • Failure results without errors now report an argument error. Accessing errors after they have been released provides a clearer message.
    • Error messages handle a wider range of control characters and avoid splitting emoji during truncation.
    • Exceptions and cancellation in asynchronous result operations are consistently returned through the task.
  • Release
    • Updated the version to 3.0.1.

Multi-error responses honour the leak options, 204 and 304 send no body, the ValueTask fast path faults the task instead of throwing, message neutralising covers C1 and the Unicode line separators, and an empty MultiResult failure is refused. Each fix has a test that fails on 3.0.0.
@arnelirobles arnelirobles changed the title fix the ten defects found auditing 3.0.0 fix nine defects found auditing 3.0.0 Sep 29, 2026
@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 195ffbfd-6973-4755-b2fc-6d0a040841af

📥 Commits

Reviewing files that changed from the base of the PR and between 2284c14 and 5b3e2d7.

📒 Files selected for processing (17)
  • CHANGELOG.md
  • Directory.Build.props
  • src/Verdict.AspNetCore/ErrorStatusCodeMapper.cs
  • src/Verdict.AspNetCore/ProblemDetailsFactory.cs
  • src/Verdict.AspNetCore/ResultExtensions.cs
  • src/Verdict.Async/ValueTaskResultExtensions.cs
  • src/Verdict.Extensions/ErrorCollection.cs
  • src/Verdict.Extensions/MultiResult.cs
  • src/Verdict.Extensions/MultiResultCombinators.cs
  • src/Verdict.Logging/ResultLogger.cs
  • src/Verdict/Error.cs
  • tests/Verdict.ApiApproval.Tests/ApprovedApi/Verdict.AspNetCore.approved.txt
  • tests/Verdict.AspNetCore.Tests/BodylessStatusTests.cs
  • tests/Verdict.AspNetCore.Tests/SecureDefaultsTests.cs
  • tests/Verdict.Async.Tests/ValueTaskResultExtensionsTests.cs
  • tests/Verdict.Extensions.Tests/ProductionReadinessTests.cs
  • tests/Verdict.Tests/ErrorMessageBoundsTests.cs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The 3.0.1 update changes ASP.NET Core response mapping, ValueTask fast-path behavior, MultiResult failure handling, error-message normalization, and ResultLogger awaits. It also updates the shared version and changelog.

Changes

Verdict 3.0.1 fixes

Layer / File(s) Summary
Multi-result problem responses
src/Verdict.AspNetCore/ErrorStatusCodeMapper.cs, src/Verdict.AspNetCore/ProblemDetailsFactory.cs, tests/Verdict.AspNetCore.Tests/SecureDefaultsTests.cs, tests/Verdict.ApiApproval.Tests/ApprovedApi/Verdict.AspNetCore.approved.txt
The multi-result response factory accepts options and applies message, code, and exception-detail settings. Responses use status 500 when an error carries an exception. Null or empty error codes map to 400 or 500 based on whether an exception is present.
Bodyless success responses
src/Verdict.AspNetCore/ResultExtensions.cs, tests/Verdict.AspNetCore.Tests/BodylessStatusTests.cs
HTTP and MVC conversions return status-only results for success statuses 204, 304, and 100–199. Tests also cover context conversions, location handling, and the JSON response for status 200.
ValueTask fast-path exception behavior
src/Verdict.Async/ValueTaskResultExtensions.cs, tests/Verdict.Async.Tests/ValueTaskResultExtensionsTests.cs
Completed-source operations return faulted ValueTasks when delegates throw. The cancellation-token MapAsync overload returns a canceled task when cancellation is already requested.
MultiResult failure validation and forwarding
src/Verdict.Extensions/ErrorCollection.cs, src/Verdict.Extensions/MultiResult.cs, src/Verdict.Extensions/MultiResultCombinators.cs, tests/Verdict.Extensions.Tests/ProductionReadinessTests.cs
Failure factories require errors for undisposed empty collections. Combinators forward detached errors without that validation. Failed Value access reports when errors have been released.
Error message character handling
src/Verdict/Error.cs, tests/Verdict.Tests/ErrorMessageBoundsTests.cs
Error normalization replaces additional control and separator characters and avoids truncating between surrogate halves. Tests cover the expanded character set and an emoji truncation boundary.
ResultLogger awaits
src/Verdict.Logging/ResultLogger.cs
Both CreateAsync overloads await operations with ConfigureAwait(false).
3.0.1 release metadata
Directory.Build.props, CHANGELOG.md
The shared version changes to 3.0.1. The changelog records the release fixes and changed MultiResult behavior.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 5b3e2

No actionable issue remains identified in the 3.0.1 changes; the PR is mergeable after normal checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 5b3e2

The changed defaults reduce exposure of exception messages in multi-error responses, and no new security failure was established. Risk is not minimal because how applications use the public response factory is not fully visible.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The response-policy change can affect applications that call the public multi-error factory and serialize its result. The inspected repository HTTP conversions use the single-error path; application endpoints and their exposure are not shown.

Security Findings and Attack Paths

  • observed — The raw FromException overload can place an exception message in an Error. Compared with the previous unconditional multi-error formatting, the changed default response path withholds that message when the exception remains attached. The exception message’s origin at a real application boundary is unresolved; this is not an established introduced vulnerability.

Trust Boundaries and Controls

  • observed — Exception details are disabled by default. A library caller may explicitly enable them through options, but an existing single-error overload already grants that caller-controlled option authority; no request-derived options path was identified.

Resilience and Maintainability Implications

  • inferred — The single- and multi-error factories currently apply matching exception-message controls in separate implementations. That leaves future policy drift possible, but the inspected head behavior does not establish a present disclosure discrepancy.

Hardening Proposals

  • proposed — Consider sharing the exception-message and code-selection policy between the single- and multi-error factories to limit future confidentiality-control drift.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.56% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 63 functions across 14 files. (3 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the defect-fix purpose and the 3.0.0 audit context. The defect count appears inconsistent with the objective, which states ten defects, but the title remains related and s…
Full details: Docstring Coverage

Explanation

Docstring coverage is 55.56% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 63 functions across 14 files. (3 skipped: 3 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@arnelirobles
arnelirobles merged commit 29de11d into master Sep 29, 2026
2 checks passed
@arnelirobles
arnelirobles deleted the fix/3.0.1 branch September 29, 2026 09:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant