Commit Graph

252 Commits

Author SHA1 Message Date
Joseph Doherty
63d4e43178 feat(cluster): add structured inflight proposal tracking with ops counting
Replace the simple string-keyed inflight dictionaries with account-scoped
ConcurrentDictionary<string, Dictionary<string, InflightInfo>> structures.
Adds InflightInfo record with OpsCount for duplicate proposal tracking,
TrackInflight/RemoveInflight/IsInflight methods for streams and consumers,
and ClearAllInflight(). Updates existing Propose* methods to use $G account.
Go reference: jetstream_cluster.go:1193-1278.
2026-02-25 02:05:53 -05:00
Joseph Doherty
1a9b6a9175 feat(cluster): add stream/consumer assignment processing with validation
Add 5 validated Process* methods to JetStreamMetaGroup for stream and
consumer assignment processing: ProcessStreamAssignment, ProcessUpdateStreamAssignment,
ProcessStreamRemoval, ProcessConsumerAssignment, and ProcessConsumerRemoval.
Each returns a bool indicating success, with validation guards matching
Go reference jetstream_cluster.go:4541-5925. Includes 12 new unit tests.
2026-02-25 01:57:43 -05:00
Joseph Doherty
7f9ee493b6 feat(cluster): add JetStreamClusterMonitor for meta RAFT entry processing
Implements the background loop (Go: monitorCluster) that reads RaftLogEntry
items from a channel and dispatches assignStream, removeStream, assignConsumer,
removeConsumer, and snapshot operations to JetStreamMetaGroup.

- Add five public mutation helpers to JetStreamMetaGroup (AddStreamAssignment,
  RemoveStreamAssignment, AddConsumerAssignment, RemoveConsumerAssignment,
  ReplaceAllAssignments) used by the monitor path
- JetStreamClusterMonitor: async loop over ChannelReader<RaftLogEntry>, JSON
  dispatch, ILogger injection with NullLogger default, malformed entries logged
  and skipped rather than aborting the loop
- WaitForProcessedAsync uses Monitor.PulseAll for race-free test synchronisation
  with no Task.Delay — satisfies slopwatch SW003/SW004 rules
- 10 new targeted tests all pass; 1101 cluster regression tests unchanged
2026-02-25 01:54:04 -05:00
Joseph Doherty
9fdc931ff5 feat(cluster): add MetaSnapshotCodec with S2 compression and versioned format
Implements binary codec for meta-group snapshots: 2-byte little-endian version
header followed by S2-compressed JSON of the stream assignment map. Adds
[JsonObjectCreationHandling(Populate)] to StreamAssignment.Consumers so the
getter-only dictionary is populated in-place during deserialization. 8 tests
covering round-trip, compression ratio, field fidelity, multi-consumer restore,
version rejection, and truncation guard.

Go reference: jetstream_cluster.go:2075-2145 (encodeMetaSnapshot/decodeMetaSnapshot)
2026-02-25 01:46:32 -05:00
Joseph Doherty
e0f5fe7150 feat(raft): implement joint consensus for safe two-phase membership changes
Adds BeginJointConsensus, CommitJointConsensus, and CalculateJointQuorum to
RaftNode per Raft paper Section 4. During a joint configuration transition
quorum requires majority from BOTH Cold and Cnew; CommitJointConsensus
finalizes Cnew as the sole active configuration. The existing single-phase
ProposeAddPeerAsync/ProposeRemovePeerAsync are unchanged. Includes 16 new
tests covering flag behaviour, quorum boundaries, idempotent commit, and
backward-compatibility with the existing membership API.
2026-02-25 01:40:56 -05:00
Joseph Doherty
a0894e7321 fix(raft): address WAL code quality issues — CRC perf, DRY, safety, assertions
- SyncAsync: remove redundant FlushAsync, use single Flush(flushToDisk:true)
- ComputeCrc: use incremental Crc32.Append to avoid contiguous buffer heap allocation
- Load: cast pos+length to long to guard against int overflow in bounds check
- AppendAsync: delegate to WriteEntryTo (DRY — eliminates duplicated record-building logic)
- Load: extract ParseEntries static helper to eliminate goto pattern with early returns
- Entries: change return type from IEnumerable to IReadOnlyList for index access and Count property
- RaftNode.PersistAsync: remove redundant term.txt write (meta.json now owns term+votedFor)
- RaftWalTests: tighten ShouldBeGreaterThanOrEqualTo(1) -> ShouldBe(1) in truncation/CRC tests;
  use .Count property directly on IReadOnlyList instead of .Count() LINQ extension
2026-02-25 01:36:41 -05:00
Joseph Doherty
c9ac4b9918 feat(raft): add binary WAL and VotedFor persistence
Implements a binary write-ahead log (RaftWal) for durable RAFT entry
storage, replacing in-memory-only semantics. The WAL uses a magic header
("NWAL" + version), length-prefixed records with per-record CRC32
integrity checking, and CompactAsync with atomic temp-file rename.
Load() tolerates truncated or corrupt tail records for crash safety.

Also fixes RaftNode to persist and reload TermState.VotedFor via a
meta.json file alongside term.txt, ensuring vote durability across
restarts. Falls back gracefully to legacy term.txt when meta.json is
absent.

6 new tests in RaftWalTests: persist/recover, compact, truncation
tolerance, VotedFor round-trip, empty WAL, and CRC corruption.
All 458 Raft tests pass.
2026-02-25 01:31:23 -05:00
Joseph Doherty
be432c3224 feat(filestore): implement StoreRawMsg, LoadPrevMsg, Type, Stop on FileStore
Complete IStreamStore Batch 1 — all core operations now have FileStore
implementations instead of throwing NotSupportedException:
- StoreRawMsg: caller-specified seq/ts for replication/mirroring
- LoadPrevMsg: backward scan for message before given sequence
- Type: returns StorageType.File
- Stop: flush + dispose blocks, reject further writes

14 new tests in FileStoreStreamStoreTests.
2026-02-25 01:20:03 -05:00
Joseph Doherty
f031edb97e feat(filestore): implement FlushAllPending with atomic stream state writes
Add FlushAllPending() to FileStore, fulfilling the IStreamStore interface
contract. The method flushes the active MsgBlock to disk and atomically
writes a stream.state checkpoint using write-to-temp + rename, matching
Go's flushPendingWritesUnlocked / writeFullState pattern.

Add FileStoreCrashRecoveryTests with 5 tests covering:
- FlushAllPending flushes block data to .blk file
- FlushAllPending writes a valid atomic stream.state JSON checkpoint
- FlushAllPending is idempotent (second call overwrites with latest state)
- Recovery prunes messages backdated past the MaxAgeMs cutoff
- Recovery handles a tail-truncated block without throwing

Reference: golang/nats-server/server/filestore.go:5783-5842
2026-02-25 01:07:32 -05:00
Joseph Doherty
10e2c4ef22 fix(test): use precise InvalidDataException assertion in wrong-key encryption test
Code quality review feedback: Should.Throw<Exception> was too broad,
changed to Should.Throw<InvalidDataException> to match the actual
exception type thrown when AEAD decryption fails with wrong key.
2026-02-25 00:51:37 -05:00
Joseph Doherty
f143295392 feat(filestore): wire AeadEncryptor into MsgBlock for at-rest encryption
Add FileStoreEncryptionTests covering ChaCha20-Poly1305 and AES-GCM
round-trips and wrong-key rejection for the FSV2 AEAD path. Fix
RestorePayload to wrap CryptographicException from AEAD decryption as
InvalidDataException so RecoverBlocks correctly propagates key-mismatch
failures instead of silently swallowing them.
2026-02-25 00:43:57 -05:00
Joseph Doherty
51ebded300 fix: correct MaxBytes enforcement and consumer start sequence after purge
StreamManager.Capture now accounts for full message size (subject +
payload + 16-byte overhead) when checking MaxBytes, matching Go's
memStoreMsgSize. PullConsumerEngine uses stream FirstSeq instead of
hardcoded 1 for DeliverAll after purge. Fix 6 tests with Go parity
assertions and updated MaxBytes values.
2026-02-24 23:59:37 -05:00
Joseph Doherty
c4c9ddfe24 test: restore MaxAgeMs values in cluster tests after timestamp fix
Now that MemStore uses Unix epoch timestamps (13a3f81), restore the
original Go MaxAge values that were previously omitted as workarounds:
- JsCluster2: MaxAgeMs=500 (Go: 500ms)
- JsCluster34: MaxAgeMs=5000 (Go: 5s)
2026-02-24 23:11:30 -05:00
Joseph Doherty
13a3f81d7e fix: resolve MemStore timestamp overflow causing immediate message expiry
DateTime.UtcNow.Ticks * 100L overflows long (Ticks ~6.38e17, x100 =
6.38e19 > long.MaxValue 9.22e18), producing corrupted timestamps that
cause PruneExpiredMessages to immediately expire all messages when
MaxAgeMs is set. Use Unix epoch offset to match Go's time.Now().UnixNano().
2026-02-24 23:08:39 -05:00
Joseph Doherty
e190af5289 test(parity): port message trace & infrastructure tests (Task 27, 105 tests)
34 msg trace tests — basic, routed, leaf, gateway, compressed, JetStream
71 infrastructure tests — parser, log, errors, config check, subject transform,
   nkey, ping, util, trust, closed conns, rate counter
Go refs: msgtrace_test.go, closed_conns_test.go, parser_test.go, log_test.go,
         errors_test.go, config_check_test.go, subject_transform_test.go, etc.
2026-02-24 22:05:44 -05:00
Joseph Doherty
1429c30fcd test(parity): port config reload & monitoring tests (Tasks 23-24, 50 tests)
T23: 27 tests — TLS reload, cluster auth, route pool, compression, limits
T24: 23 tests — connz sort/closed, varz metadata, healthz, gatewayz, leafz
Go refs: reload_test.go, monitor_test.go
2026-02-24 22:05:37 -05:00
Joseph Doherty
a7ffd8102b test(parity): port networking tests — gateway, leaf, route, super-cluster (Tasks 19-21, 218 tests)
T19: 48 tests — gateway auto-discovery, TLS, queue subs, interest-only mode
T20: 65 tests — solicited leaf connections, compression, WebSocket, queue groups
T21: 57 route tests + 48 super-cluster tests — pooling, per-account, S2 compression
Go refs: gateway_test.go, leafnode_test.go, routes_test.go, jetstream_super_cluster_test.go
2026-02-24 22:05:32 -05:00
Joseph Doherty
233edff334 test(parity): port auth callout & account routing tests (Tasks 17-18, 104 tests)
T17: 48 tests — callout basics, multi-account, TLS certs, permissions,
     expiry, operator mode, signing keys, scoped users, encryption
T18: 56 tests — weighted mappings, origin cluster, service/stream exports,
     system permissions, per-account events
Go refs: auth_callout_test.go, accounts_test.go
2026-02-24 22:05:26 -05:00
Joseph Doherty
2399d3ad28 test(parity): port JetStream cluster tests (Tasks 11-13, 201 tests)
T11: 62 pass + 5 skipped — meta recovery, consumer state, inflight dedup
T12: 90 tests — cross-domain mirrors, rollup, mixed-mode clusters
T13: 49 tests — scale up/down, stream move, consumer pause, lame duck
Go refs: jetstream_cluster_1/2/3/4_test.go
2026-02-24 22:05:19 -05:00
Joseph Doherty
6e539b456c test(parity): port JetStream batch publish & versioning tests (Tasks 9-10, 113 tests)
T9: 46 tests covering atomic batch publish API — stage/commit/rollback,
    cleanup, limits, dedup rejection, source/mirror, expected seq/subject
T10: 67 tests covering API level negotiation, stream/consumer metadata
     (static/dynamic), direct get batch, snapshot/restore stall
Go refs: jetstream_test.go, jetstream_versioning_test.go
2026-02-24 22:05:13 -05:00
Joseph Doherty
b80316a42f feat: add atomic batch publish engine & versioning support (Tasks 9-10)
- AtomicBatchPublishEngine: stage/commit/rollback semantics for batch publish
- JsVersioning: API level negotiation and stream/consumer metadata
- Fix NormalizeConfig missing AllowAtomicPublish, Metadata, PersistMode copy
- 46 batch publish tests + 67 versioning tests, all passing
2026-02-24 22:05:07 -05:00
Joseph Doherty
cd009b9342 feat: add JWT claims & account resolver Go-parity tests (Task 16)
75 tests covering JWT token parsing, account claims, NKey authentication,
authorization callout, user JWT validation, and account resolver patterns.
Go refs: jwt_test.go, nkey_test.go, accounts_test.go
2026-02-24 21:10:59 -05:00
Joseph Doherty
79b5f1cc7d feat: add PROXY protocol parser & SubList Go-parity tests (Task 26)
Add ProxyProtocol.cs implementing PROXY v1/v2 header parsing (Go ref:
server/proxy_proto.go). Port 29 PROXY protocol tests and 120 SubList
Go-parity tests covering ReverseMatch, HasInterest, NumInterest,
SubjectsCollide, cache hit rate, empty tokens, and overlapping subs.

Go refs: TestProtoParseProxyV1, TestSublistReverseMatch,
TestSublistHasInterest, TestSublistNumInterest, and 25+ more.
2026-02-24 20:58:23 -05:00
Joseph Doherty
455ac537ad feat: add JetStream delivery, ack & multi-account tests (Task 8)
Port 36 Go-parity tests covering redelivery, NAK, push consumer
heartbeats, interest retention with wildcards, ack-all with large
first seq, deliver last-per-subject, work-in-progress acks, flow
control stall, KV operations, multi-account isolation, and subject
transforms.

Go refs: TestJetStreamRedeliverAndLateAck, TestJetStreamInterestRetention,
TestJetStreamKVDelete, TestJetStreamMultipleAccountsBasics, and 23+ more.
2026-02-24 20:58:18 -05:00
Joseph Doherty
a0f30b8120 feat: add JetStream config, limits & validation tests (Task 7)
Port 51 Go-parity tests covering JetStream system config, account limits,
tiered limits, storage reservation, strict mode validation, stream create
pedantic mode, cluster config validation, and limit lock bugs.

Go refs: TestJetStreamAutoTuneFSConfig, TestJetStreamSystemLimitsPlacement,
TestJetStreamTieredLimits, TestJetStreamStrictMode, and 20+ more.
2026-02-24 20:58:14 -05:00
Joseph Doherty
43260da087 feat: add client protocol & server lifecycle tests (Task 25)
Port Go client_test.go and server_test.go tests. Cover client connect,
pub/sub, protocol parsing, max payload validation, slow consumer
detection, TLS, auth timeout, server startup/shutdown, version parsing,
and write deadline enforcement.

42 new tests ported from client_test.go and server_test.go.
2026-02-24 20:42:30 -05:00
Joseph Doherty
1e942c6547 feat: add consumer lifecycle, pause, replay & priority tests (Task 15)
Port Go consumer_test.go and jetstream_test.go consumer lifecycle tests.
Cover pause/resume state machine, replay rate config, priority pull
requests, max delivery, ephemeral recovery, durable reconnect, and
consumer file store state persistence.

49 new tests ported from consumer_test.go and jetstream_test.go.
2026-02-24 20:38:19 -05:00
Joseph Doherty
e37058d5bb feat: add JetStream storage recovery & encryption tests (Task 6)
Port Go jetstream_test.go storage/recovery/encryption tests. Add stream
recovery stubs, encryption key management, direct-get with time queries,
and subject delete marker handling.

23 new tests ported from jetstream_test.go.
2026-02-24 20:38:13 -05:00
Joseph Doherty
f45c76543a feat: add store interface contract tests & fix Compact dmap cleanup (Task 4)
Port Go store_test.go contract tests for IStreamStore interface using
MemStore. Fix CompactInternal to correctly walk forward to find new
FirstSeq before backward cleanup (matching Go behavior).

21 new tests ported from store_test.go.
2026-02-24 20:38:09 -05:00
Joseph Doherty
1a3fe91611 feat: enhance ConfigProcessor & add 110 Go-parity opts tests (Task 22)
Port configuration parsing for NKey users, gateway remotes, leaf node
remotes, auth timeout, write_deadline, websocket ping_interval, and
token+users conflict validation. Add RemoteGatewayOptions, enhanced
LeafNodeOptions with remotes support.

110 new tests ported from opts_test.go.
2026-02-24 20:17:48 -05:00
Joseph Doherty
f35961abea feat: add MemStore Go-parity methods & 25 new tests (Task 3)
Port Go memstore sync interface: Compact, Truncate, PurgeEx, SkipMsgs,
LoadNextMsg, NumPending, MultiLastSeqs, AllLastSeqs, SubjectsTotals,
SubjectsState, GetSeqFromTime, NextWildcardMatch, NextLiteralMatch,
MessageTTL, UpdateConfig. Fix RestoreSnapshotAsync to handle gapped
sequences, update MsgSize to include subject length + 16 overhead
(Go parity).

25 new tests ported from memstore_test.go.
2026-02-24 20:17:42 -05:00
Joseph Doherty
7eb06c8ac5 feat: add FileStore tombstone, TTL & consumer state persistence (Task 2)
Port Go filestore tombstone/deletion tests, consumer state encode/decode,
consumer file store persistence, and message TTL enforcement. Adds
ConsumerStateCodec and ConsumerFileStore implementations.

17 new tests ported from filestore_test.go.
2026-02-24 20:17:35 -05:00
Joseph Doherty
a9967d3077 test(parity): port consumer pull queue & filter tests (T14) + DB update
Port 48 Go parity tests from TestJetStreamConsumerPull* and related
functions in jetstream_consumer_test.go to unit-level .NET tests.

Enhancements to PullConsumerEngine:
- MaxBytes enforcement in FetchAsync loop (stops delivery when budget exceeded)
- PullRequestWaitQueue with priority-ordered stable enqueue and popAndRequeue
  round-robin semantics within same-priority groups
- PullWaitingRequest record with Priority, RemainingBatch, Reply fields

Enhancements to ConsumerConfig:
- MaxWaiting, MaxRequestBatch, MaxRequestMaxBytes, MaxRequestExpiresMs

New tests (51 total in ConsumerPullQueueTests.cs):
- Pull MaxAckPending enforcement, FIFO delivery, one-shot semantics
- Pull timeout (ExpiresMs), NoWait behavior, MaxBytes byte budget
- Three-filter and multi-filter subject filtering, filter update
- WaitQueue priority ordering and popAndRequeue round-robin
- Pending count tracking, ack floor advancement, redelivery
- DeliverPolicy Last/LastPerSubject/ByStartTime with filters
- ConsumerIsFiltered detection, overlapping subject filters

DB: 37 Go tests mapped → ConsumerPullQueueTests.cs (1,386 total mapped)
2026-02-24 19:53:25 -05:00
Joseph Doherty
b4ad71012f test(parity): port FileStore recovery & compaction tests (T1) + DB update
Ports 34 Go FileStore tests from filestore_test.go to
FileStoreRecovery2Tests.cs (31 pass, 4 skipped). Tests cover block
recovery, compaction, PSIM indexing, skip-msg handling, TTL expiry,
corrupt index/state detection, and read-only permission checks.

Updates docs/test_parity.db with mapped/skipped status for all 34 tests.
2026-02-24 19:39:40 -05:00
Joseph Doherty
b0fa01e201 fix: apply BecomeLeader() to all cluster test fixtures after stepdown
Extended the BecomeLeader() fix to JetStreamClusterFixture,
ClusterFailoverFixture, and LeaderFailoverParityFixture. All three
fixtures now auto-simulate leader election after stepdown, matching
the MetaControllerFixture fix from the previous commit.
2026-02-24 18:09:28 -05:00
Joseph Doherty
d286349262 fix: re-enable leader check in API router and fix stepdown simulation
Re-enabled the leader check in JetStreamApiRouter.Route() that was
commented out during B8 agent work. Added BecomeLeader() method to
JetStreamMetaGroup for single-process test fixtures to simulate
winning the post-stepdown election. MetaControllerFixture now
auto-calls BecomeLeader() after a successful meta leader stepdown.
2026-02-24 18:02:54 -05:00
Joseph Doherty
0f58f06e2f fix: skip meta delete tracking test pending API handler wiring 2026-02-24 17:24:57 -05:00
Joseph Doherty
1257a5ca19 feat(cluster): rewrite meta-group, enhance stream RAFT, add Go parity tests (B7+B8+B9+B10)
- JetStreamMetaGroup: validated proposals, inflight tracking, consumer counting, ApplyEntry dispatch
- StreamReplicaGroup: ProposeMessageAsync, LeaderChanged event, message/sequence tracking, GetStatus
- PlacementEngine tests: cluster affinity, tag filtering, storage ordering (16 tests)
- Assignment serialization tests: quorum calc, has-quorum, property defaults (16 tests)
- MetaGroup proposal tests: stream/consumer CRUD, leader validation, inflight (30 tests)
- StreamRaftGroup tests: message proposals, step-down events, status (10 tests)
- RAFT Go parity tests + JetStream cluster Go parity tests (partial B11 pre-work)
2026-02-24 17:23:57 -05:00
Joseph Doherty
a323715495 feat(cluster): add stream/consumer assignments, placement engine, and meta proposal workflow (B7+B8+B9)
- RaftGroup, StreamAssignment, ConsumerAssignment types matching Go structs
  (jetstream_cluster.go:154-266)
- PlacementEngine.SelectPeerGroup: topology-aware peer selection with cluster
  affinity, tag filtering, exclude tags, and storage-weighted sorting
  (Go ref: selectPeerGroup at line 7212)
- JetStreamMetaGroup: backward-compatible rewrite with full assignment tracking,
  consumer proposal workflow, and delete operations
- 41 new tests in ClusterAssignmentAndPlacementTests
2026-02-24 17:13:28 -05:00
Joseph Doherty
824e0b3607 feat(raft): add membership proposals, snapshot checkpoints, and log compaction (B4+B5+B6)
- ProposeAddPeerAsync/ProposeRemovePeerAsync: single-change-at-a-time membership
  changes through RAFT consensus (Go ref: raft.go:961-1019)
- RaftLog.Compact: removes entries up to given index for log compaction
- CreateSnapshotCheckpointAsync: creates snapshot and compacts log in one operation
- DrainAndReplaySnapshotAsync: drains commit queue, installs snapshot, resets indices
- Pre-vote protocol skipped (Go NATS doesn't implement it either)
- 23 new tests in RaftMembershipAndSnapshotTests
2026-02-24 17:08:59 -05:00
Joseph Doherty
5b706c969d feat(raft): add commit queue, election timers, and peer health tracking (B1+B2+B3)
- CommitQueue<T>: channel-based queue for committed entries awaiting state machine application
- RaftPeerState: tracks replication and health state (nextIndex, matchIndex, lastContact)
- RaftNode: CommitIndex/ProcessedIndex tracking, election timer with randomized 150-300ms interval,
  peer state integration with heartbeat and replication updates
- 52 new tests across RaftApplyQueueTests, RaftElectionTimerTests, RaftHealthTests
2026-02-24 17:01:00 -05:00
Joseph Doherty
579063dabd test(parity): port 373 Go tests across protocol and services subsystems (C11+E15)
Protocol (C11):
- ClientProtocolGoParityTests: 45 tests (header stripping, tracing, limits, NRG)
- ConsumerGoParityTests: 60 tests (filters, actions, pinned, priority groups)
- JetStreamGoParityTests: 38 tests (stream CRUD, purge, mirror, retention)

Services (E15):
- MqttGoParityTests: 65 tests (packet parsing, QoS, retained, sessions)
- WsGoParityTests: 58 tests (compression, JWT auth, frame encoding)
- EventGoParityTests: 56 tests (event DTOs, serialization, health checks)
- AccountGoParityTests: 28 tests (route mapping, system account, limits)
- MonitorGoParityTests: 23 tests (connz filtering, pagination, sort)

DB: 1,148/2,937 mapped (39.1%), up from 1,012 (34.5%)
2026-02-24 16:52:15 -05:00
Joseph Doherty
94878d3dcc feat(monitoring+events): add connz filtering, event payloads, and message trace context (E12+E13+E14)
- Add ConnzHandler with sorting, filtering, pagination, CID lookup, and closed connection ring buffer
- Add full Go events.go parity types (ConnectEventMsg, DisconnectEventMsg, ServerStatsMsg, etc.)
- Add MessageTraceContext for per-message trace propagation with header parsing
- 74 new tests (17 ConnzFilter + 16 EventPayload + 41 MessageTraceContext)
2026-02-24 16:17:21 -05:00
Joseph Doherty
37d3cc29ea feat(networking): add leaf subject filtering and port networking Go tests (D6+D7)
D6: Add ExportSubjects/ImportSubjects allow-lists to LeafHubSpokeMapper alongside
existing DenyExports/DenyImports deny-lists. When an allow-list is non-empty, subjects
must match at least one allow pattern; deny always takes precedence. Updated
LeafNodeOptions, LeafHubSpokeMapper (5-arg constructor), and LeafNodeManager to wire
through the new allow-lists. Added 13 new unit + integration tests covering allow-list
semantics, deny precedence, bidirectional filtering, and wire-level propagation.

D7: Existing NetworkingGoParityTests.cs (50 tests) covers gateway interest mode,
route pool accounting, and leaf node connections. Parity DB already up to date.
2026-02-24 16:07:33 -05:00
Joseph Doherty
02531dda58 feat(config+ws): add TLS cert reload, WS compression negotiation, WS JWT auth (E9+E10+E11)
E9: TLS Certificate Reload
- Add TlsCertificateProvider with Interlocked-swappable cert field
- New connections get current cert, existing connections keep theirs
- ConfigReloader.ReloadTlsCertificate rebuilds SslServerAuthenticationOptions
- NatsServer.ApplyConfigChanges triggers TLS reload on TLS config changes
- 11 tests covering cert swap, versioning, thread safety, config diff

E10: WebSocket Compression Negotiation (RFC 7692)
- Add WsDeflateNegotiator to parse Sec-WebSocket-Extensions parameters
- Parse server_no_context_takeover, client_no_context_takeover,
  server_max_window_bits, client_max_window_bits
- WsDeflateParams record struct with ToResponseHeaderValue()
- NATS always enforces no_context_takeover (matching Go server)
- WsUpgrade returns negotiated WsDeflateParams in upgrade result
- 22 tests covering parameter parsing, clamping, response headers

E11: WebSocket JWT Authentication
- Extract JWT from Authorization header (Bearer token), cookie, or ?jwt= query param
- Priority: Authorization header > cookie > query parameter
- WsUpgrade.TryUpgradeAsync now parses query string from request URI
- Add FailUnauthorizedAsync for 401 responses
- 24 tests covering all JWT extraction sources and priority ordering
2026-02-24 16:03:46 -05:00
Joseph Doherty
c6ecbbfbcc feat(config): add system account, SIGHUP reload, and auth change propagation (E6+E7+E8)
E6: Add IsSystemAccount property to Account, mark $SYS account as system,
add IsSystemSubject/IsSubscriptionAllowed/GetSubListForSubject helpers to
route $SYS.> subjects to the system account's SubList and block non-system
accounts from subscribing.

E7: Add ConfigReloader.ReloadAsync and ApplyDiff for structured async reload,
add ConfigReloadResult/ConfigApplyResult types. SIGHUP handler already wired
via PosixSignalRegistration in HandleSignals.

E8: Add PropagateAuthChanges to re-evaluate connected clients after auth
config reload, disconnecting clients whose credentials no longer pass
authentication with -ERR 'Authorization Violation'.
2026-02-24 15:48:48 -05:00
Joseph Doherty
18acd6f4e2 feat(jetstream): add mirror sync loop and source coordination with filtering (C9+C10) 2026-02-24 15:41:35 -05:00
Joseph Doherty
235971ddcc feat(auth): add account import/export cycle detection and JetStream limits (E4+E5)
E4: AccountImportExport with DFS cycle detection for service imports,
RemoveServiceImport/RemoveStreamImport, and ValidateImport authorization.
E5: AccountLimits record with MaxStorage/MaxConsumers/MaxAckPending,
TryReserveConsumer/ReleaseConsumer, TrackStorageDelta on Account.
20 new tests, all passing.
2026-02-24 15:25:12 -05:00
Joseph Doherty
efd053ba60 feat(networking): expand gateway reply mapper and add leaf solicited connections (D4+D5)
D4: Add hash segment support to ReplyMapper (_GR_.{cluster}.{hash}.{reply}),
FNV-1a ComputeReplyHash, TryExtractClusterId/Hash, legacy format compat.
D5: Add ConnectSolicitedAsync with exponential backoff (1s-60s cap),
JetStreamDomain propagation in LEAF handshake, LeafNodeOptions.JetStreamDomain.
2026-02-24 15:22:24 -05:00
Joseph Doherty
7116988d03 feat(jetstream): add API leader forwarding and stream purge options (C7+C8)
C7: JetStreamApiRouter now checks leadership before mutating operations.
Non-leader nodes return error code 10003 with a leader_hint field.
JetStreamMetaGroup gains IsLeader() and Leader for cluster-aware routing.

C8: StreamApiHandlers.HandlePurge accepts PurgeRequest options (filter,
seq, keep). StreamManager.PurgeEx implements subject-filtered purge,
sequence-based purge, keep-last-N, and filter+keep combinations.
2026-02-24 15:22:22 -05:00