Fix cross-host outbox delivery + High-severity NuGet vulns (3.1.1)#170
Merged
Conversation
JasonMWebb
commented
Jul 14, 2026
Collaborator
- Cross-host outbox fix: adds OutboxOptions.ImmediateDispatch (default true, back-compat). When false, commit persists but skips Phase-3 in-process dispatch/mark, so a separate poller is the sole dispatcher — fixes silent cross-host delivery loss. Plus defense-in-depth (no mark-processed when no in-process producer matched).
- EFCore fix: DeleteProcessedAsync/DeleteDeadLetteredAsync DateTimeOffset comparison now SQLite-translatable.
- Security: Microsoft.OpenApi → 2.7.5 (CVE-2026-49451); SQLitePCLRaw.lib.e_sqlite3 → 3.53.3 (CVE-2025-6965).
- Docs/CI: Outbox topology guide, docs version 3.1.1, 3.1.1 changelog; CI publishes production only on version-tag push (no more pre-releases). Website npm vulns deferred to a follow-up spec.
- Verified: test suites pass; dotnet list --vulnerable clean; docs build OK.
In a producer-host / separate-poller-host topology, the unit of work's best-effort post-commit dispatch (Phase 3) marked outbox rows processed on the producing host even when no subscriber consumed the event. The poller on the other host only claims rows where ProcessedAtUtc IS NULL, so it never saw them and cross-host delivery was silently lost. Add OutboxOptions.ImmediateDispatch (default true, fully back-compat). When false, OutboxEventRouter.RouteEventsAsync skips Phase 3 entirely (no in-process dispatch, no MarkProcessedAsync), leaving the durable poller as the sole dispatcher/marker. Producer-only hosts set it false. As defense-in-depth, RouteEventsAsync no longer marks a row processed when no in-process producer matched the event. This is intentionally narrow: an in-memory producer that no-ops on no subscriber still counts as dispatched, so ImmediateDispatch remains the cross-host fix. Also fix EFCoreOutboxStore.DeleteProcessedAsync/DeleteDeadLetteredAsync, whose DateTimeOffset comparison could not be translated by the SQLite provider; the comparison is now evaluated client-side (mirroring ClaimAsync) while the null-check stays in the query. Docs: add the "Outbox Producer/Processor Topology" conceptual guide covering the three-phase commit, the cross-host invariant, and when/by whom rows are marked processed; cut Docusaurus docs version 3.1.1. Add a future-enhancement spec proposing a first-class producer/processor topology API.
Resolve two High-severity advisories flagged by dotnet list --vulnerable: - Microsoft.OpenApi 2.4.1 (CVE-2026-49451, GHSA-v5pm-xwqc-g5wc), pulled transitively via Swashbuckle 10.x on the net10 target of RCommon.Authorization.Web. Pin the patched 2.x (2.7.5) directly; net8/net9 use Swashbuckle 8/9 -> OpenApi 1.x and are unaffected. - SQLitePCLRaw.lib.e_sqlite3 2.1.11 (CVE-2025-6965, GHSA-2m69-gcr7-jv3q), the native SQLite shipped transitively into the SQLite-backed test projects. Override the native binary to 3.53.3 (SQLite >= 3.50.2); the managed core is untouched (SQLite's C ABI is backward-compatible). Website (Docusaurus) npm advisories are deferred: the fix requires a 3.4->3.10 upgrade that breaks 69 swizzled theme components. Tracked in a follow-up spec. These are build-time-only tooling for a static site (no code ships to visitors). Add a 3.1.1 changelog entry (current docs + 3.1.1 snapshot; 2.4.1 preserved) covering the outbox fix, the EFCore SQLite cleanup fix, and these security fixes.
The publish job previously ran only on pushes to main, and the package version comes from MinVer. On an untagged main commit MinVer resolves to a pre-release (currently 3.1.0-alpha.3.N), so merging a PR could never produce a clean production release — MinVer only emits a production version when HEAD sits exactly on a release tag. Trigger the workflow on version-tag pushes (NNN.NNN.NNN) and allow the publish job to run for tag refs. Pushing tag 3.1.1 now builds and publishes the exact production version. Rolling pre-release publishing on main pushes is unchanged.
Gate the publish job to version-tag pushes only. Pushes to main now run build-and-test for validation but no longer publish, so MinVer's pre-release versions (e.g. 3.1.0-alpha.3.N from untagged main commits) are never pushed to NuGet. Production releases are cut solely by pushing a version tag (e.g. 3.1.1).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.