Skip to content

Releases: JasperFx/marten

Marten 9.15.0

Choose a tag to compare

@jeremydmiller jeremydmiller released this 12 Jul 17:11

Closed issues

  • #4942 — sharded tenancy: auto-assign never repaired half-provisioned tenants (PR #4945). findOrAssignTenantDatabaseAsync returned early on an existing assignment row, skipping createPartitionsForTenant + per-tenant event-sequence provisioning — so a tenant whose provisioning was interrupted (assignment committed, partitions missing) failed every write with 23514 forever. Both early-return paths (including a second race-window hole under the advisory lock) now run the same idempotent repair the explicit AddTenantToShardAsync(tenantId, databaseId) overload always ran, guarded to once per process per tenant via the resolution cache.
  • #4941 — two-day silent projection outage (closed with full mapping). Root cause was #4942; the invisibility was JasperFx/jasperfx#506/#507, fixed in JasperFx 2.27.0 which this release consumes.

Also in this release

  • Bundles the fixed JasperFx.Events.SourceGenerator analyzer (JasperFx/jasperfx#505) — CS1061 compile break for no-parameterless-ctor aggregates with instance Apply returning the aggregate.
  • Follow-up enhancement filed as #4944 (database-driven partition sweep via pg_inherits) for the #4943 provisioning-tool scenario.

Verified against Wolverine (full solution + CoreTests/MartenTests/distribution/Http suites, zero failures) and CritterWatch before publishing. Thanks to @erdtsieck for the dump-verified root-cause analysis.

Marten 9.14.1

Choose a tag to compare

@jeremydmiller jeremydmiller released this 10 Jul 18:13
881d5cf

Marten 9.14.1 is a patch release focused on a substantial round of LINQ query-translation improvements, plus event-store partitioning, high-water, and AoT fixes, and refreshed Weasel/JasperFx dependencies.

LINQ query translation

This release significantly expands what the LINQ provider can push down to PostgreSQL instead of falling back to slower strategies or throwing:

  • Collection Any(predicate) filters now translate to JSONPath and OR-of-containment strategies, and the old explode/ctid fallback has been replaced by a correlated EXISTS strategy. All() shapes and duplicated array fields moved onto the same EXISTS strategy. The net effect is correct, index-friendlier SQL for nested-collection predicates.
  • Indexing into complex child collections inside Where() clauses is now supported (e.g. x.Children[0].Name == "...").
  • Aggregates over collectionsSum/Min/Max/Average — can now be used inside Where() clauses.
  • Regex.IsMatch() is translated in Where() clauses.
  • IComparable.CompareTo() now works for non-string comparables such as Guid (#4920), alongside broader CompareTo() coverage, string IsOneOf via the ?| operator, and CollectionIsEmpty via ICollectionAware.
  • GinIndexJsonDataMember() was added for member-scoped expression GIN indexes.

#4916 — subclass queries now use duplicated fields and the base id

Querying a document subclass and filtering on a Duplicate()'d field or the base-class id previously emitted a JSONB filter (CAST(d.data ->> 'FarmId' as uuid)) instead of the real column, missing the duplicated column and the primary-key index:

o.Schema.For<Animal>().AddSubClass<Cow>().Duplicate(x => x.FarmId);

Query<Cow>().Where(x => x.FarmId == id)  // now: d.farm_id = :p0     (was: CAST(d.data ->> 'FarmId' ...))
Query<Cow>().Where(x => x.Id == id)      // now: d.id = :p0          (was: CAST(d.data ->> 'Id' ...))

A subclass shares its parent's table, so the parent's column-backed members (duplicated fields, the id, the soft-delete flag) are now inherited by the subclass's query member resolution. Querying the parent type was already correct and is unchanged.

Event store, partitioning & daemon

  • #4924 — hyphenated / GUID tenant ids under UseTenantPartitionedEvents. Registering a tenant whose partition suffix contains a - (so every GUID tenant id) made ApplyAllConfiguredChangesToDatabaseAsync() throw 42601 because the per-tenant CREATE SEQUENCE / DROP SEQUENCE DDL emitted the identifier unquoted. The schema-apply statements are now quoted (matching the quick-append function and the imperative provisioning path), so hyphenated tenants migrate cleanly. Quote — not sanitize — so the append function can still resolve the sequence by its raw suffix.
  • #4915 — projection coordinator shutdown. The projection coordinator now drains on disposal, and via the Weasel 9.16.3 bump the advisory-lock ObjectDisposedException path latches-and-rethrows so a HotCold cold node's leadership loop terminates instead of re-polling a disposed data source during shutdown.
  • #4913 — high-water scan under partitioning (JasperFx 2.26.0). Under UseTenantPartitionedEvents the store-global high-water agent was continuously running select max(seq_id) from mt_events, an unfiltered scan that fans out across every tenant partition on every poll. That store-global mark is not used to advance tenant projections (they advance per-tenant), so the recurring scan is now skipped under partitioning; tenant high water is driven by the per-tenant coordinator and poll timer.
  • #502 (#4922)GetProjectionStatusesAsync now resolves the correct named database.

AoT / trimming

  • #4917 — corrected AoT annotations in the event graph.
  • The AddEventType / QueryRawEventDataOnly generic-constraint tightening was reversed, and event-mapping construction now routes through the cached GenericFactoryCache while preserving the trimming root (#4930).

Dependencies

  • Weasel 9.16.3 (#4932) — advisory-lock disposed-pool fix (marten#4915).
  • JasperFx 2.26.0 — the #4913 high-water fix, plus 2.25.0's ShardState.DatabaseIdentifier (#501).

Closed issues

#4913, #4915, #4916, #4917, #4924, and #502.

Marten 9.14.0

Choose a tag to compare

@jeremydmiller jeremydmiller released this 08 Jul 18:26

Marten 9.14.0 is the recommended upgrade for all 9.x users. It combines the LINQ SQL-injection security fix (first shipped in 9.13.0) with the fix for the projection-coordinator shutdown race in #4874 and the accompanying dependency updates.

Beyond the LINQ updates, this made the new Per-Tenant Event Partitioning much more robust as we're testing that in conjunction with a JasperFx client for ludicrous scalability.

🔒 Security — SQL injection in the LINQ provider (GHSA-rfx3-98h7-v3xp)

Several LINQ / tenant-management code paths interpolated a runtime, potentially attacker-influenced value into generated SQL as a single-quoted literal without escaping or parameterization. A value containing a single quote could break out of the literal and inject SQL. The primary vector — a Dictionary<,> indexer key in a Where filter (a common "filter by attribute name" / EAV pattern) — was reported privately with an executed proof-of-concept and enabled filter / multi-tenant authorization bypass and blind data exfiltration.

Fixed sinks (#4911):

  • DictionaryItemMember — dictionary indexer key, e.g. Where(x => x.Attributes[key] == v)
  • DictionaryContainsKeyFilterDictionary.ContainsKey(key) (Newtonsoft serializer + the Enum branch, which bypass System.Text.Json's quote escaping)
  • SelectParser — a constant string projected through Select(x => new { L = runtimeString })
  • DeleteAllForTenant — tenant id reaching per-tenant projection teardown (now parameterized)
  • DatabaseScopedTenantPartitions — tenant id inlined into partition DDL
  • EventLoader — per-tenant partition-pruning literal (defense-in-depth)

Each sink now escapes embedded single quotes or binds the value as a parameter; regression tests lock down every vector, and a follow-up LINQ-wide audit cleared the rest of the query hot path (full-text search, string-method translations, comparisons, IsOneOf/Contains/subset operators, and patching paths). Affected versions: 7.0.0 – 9.12.0. Also patched in 8.37.4 (8.x line) and 9.13.0.

Reported responsibly by @svenclaesson — thank you. See advisory GHSA-rfx3-98h7-v3xp (CVE pending assignment).

🛠️ Reliability — projection-coordinator shutdown drain race (#4874)

On host shutdown, the native HotCold projection coordinator could abort with ObjectDisposedException: 'Npgsql.PoolingDataSource' — the coordinator's leadership poll issued an OpenAsync against an already-disposed data source while tenancy was tearing down. This is the "case B" ordering storm reported against #4874 (distinct from the async-tenancy foundation laid in #4907, which did not resolve it).

The fix ships through the dependency updates below, with a Marten-side regression test (Bug_4874_coordinator_drain_ordering, #4912):

  • JasperFx 2.24.1 (#499/#500) — ProjectionCoordinatorBase terminates the leadership loop on a disposed data source / wrapped cancellation instead of re-polling.
  • Weasel 9.16.2 (weasel#349/#350) — AdvisoryLock guards against a disposed NpgsqlDataSource during shutdown (short-circuits while disposing and treats a disposed-pool ObjectDisposedException as a non-acquire rather than propagating).

⬆️ Dependency updates

  • JasperFx 2.24.0 → 2.24.1
  • Weasel 9.16.1 → 9.16.2
  • Weasel.EntityFrameworkCore 9.2.1 → 9.16.2 (released from its prior version hold now that the Weasel line is published)

Full changelog since 9.13.0

  • #4911 — SQL injection fix in the LINQ provider (carried into this release)
  • #4912 — regression test for the #4874 case-B coordinator-drain ordering storm
  • JasperFx 2.24.1 / Weasel 9.16.2 / EFCore 9.16.2 bump (#4874 shutdown-race fix)

Marten 9.13.0

Choose a tag to compare

@jeremydmiller jeremydmiller released this 08 Jul 15:46

Security release. Fixes SQL injection in the LINQ provider via unescaped string literals (#4911).

Several LINQ / tenant-management code paths interpolated a runtime, potentially attacker-influenced value into generated SQL as a single-quoted literal without escaping or parameterization; a value containing a single quote could break out and inject SQL. The primary vector — a Dictionary<,> indexer key in a Where filter — was reported privately with an executed proof-of-concept (filter / multi-tenant authorization bypass, blind exfiltration).

Fixed sinks:

  • DictionaryItemMember — dictionary indexer key
  • DictionaryContainsKeyFilterContainsKey key (Newtonsoft serializer + Enum branch)
  • SelectParser — constant string projected via Select(...)
  • DeleteAllForTenant — tenant id in per-tenant projection teardown (now parameterized)
  • DatabaseScopedTenantPartitions — tenant id in partition DDL
  • EventLoader — per-tenant partition-pruning literal (defense-in-depth)

All 9.x users should upgrade. The 8.x line is fixed in 8.37.4. See advisory GHSA-rfx3-98h7-v3xp.

Marten 8.37.4

Choose a tag to compare

@jeremydmiller jeremydmiller released this 08 Jul 15:01

Security release. Fixes SQL injection in the LINQ provider via unescaped string literals.

Several LINQ code paths interpolated a runtime, potentially attacker-influenced value into generated SQL as a single-quoted literal without escaping or parameterization; a value containing a single quote could break out and inject SQL. The primary vector — a Dictionary<,> indexer key in a Where filter — was reported privately with an executed proof-of-concept (filter / multi-tenant authorization bypass, blind exfiltration).

Fixed sinks (this 8.x line):

  • DictionaryItemMember — dictionary indexer key
  • DictionaryContainsKeyFilterContainsKey key (Newtonsoft serializer + Enum branch)
  • SelectParser — constant string projected via Select(...)

All users on 8.x should upgrade. A GitHub Security Advisory (with CVE) is being coordinated.

Back-port of #4911 (9.x).

V9.12.0

Choose a tag to compare

@jeremydmiller jeremydmiller released this 29 Jun 11:03
19fdabe

A couple significant bug fixes, and yet more support for CritterWatch

What's Changed

Full Changelog: V9.11.0...V9.12.0

V9.11.0

Choose a tag to compare

@jeremydmiller jeremydmiller released this 26 Jun 00:07
6de47ea

What's Changed

Full Changelog: V9.10.0...V9.11.0

V9.10.0

Choose a tag to compare

@jeremydmiller jeremydmiller released this 22 Jun 23:59
e08ad06

The new option might help the async daemon perform better in the face of concurrency exceptions on event appending with the QuickAppend option. It's opt in to avoid folks needing to do schema migrations

What's Changed

New Contributors

Full Changelog: V9.9.1...V9.10.0

Marten 8.37.3

Choose a tag to compare

@jeremydmiller jeremydmiller released this 18 Jun 17:52

Maintenance release on the 8.0 line.

Fixes

  • #4718projections rebuild must skip subscriptions. When an event subscription was registered (e.g. Wolverine's PublishEventsToWolverine(...) with SubscribeFromPresent()), dotnet run -- projections rebuild threw No registered projection matches the name '...'. A subscription is Async, so its name was fed into the rebuild path → RebuildProjectionAsyncTryFindProjection (which only searches projections). The rebuild path now skips event subscriptions and Live-lifecycle projections. Subscriptions still run continuously and still appear in projections list; only rebuild skips them, and a subscription name passed explicitly to rebuild is a clean no-op.

    Backported to the JasperFx 1.x line in JasperFx.Events 1.36.2 (JasperFx/jasperfx#460, tracked by JasperFx/jasperfx#459).

Dependencies

  • JasperFx.Events 1.35.01.36.2
  • JasperFx 1.29.11.31.0

V9.9.1

Choose a tag to compare

@jeremydmiller jeremydmiller released this 18 Jun 22:41
d33f0f3

This will be a valuable upgrade for anyone who experiences a high degree of optimistic concurrency failures while using QuickAppend options, which is the default behavior in V9. This will help stop gaps in the event sequence, which in turn will make the Async Daemon healthier.

Also though, see Wolverine for help in preventing concurrent access in the first place

What's Changed

Full Changelog: V9.9.0...V9.9.1