Files
natsdotnet/gaps/auth-and-accounts.md
Joseph Doherty c30e67a69d Fix E2E test gaps and add comprehensive E2E + parity test suites
- Fix pull consumer fetch: send original stream subject in HMSG (not inbox)
  so NATS client distinguishes data messages from control messages
- Fix MaxAge expiry: add background timer in StreamManager for periodic pruning
- Fix JetStream wire format: Go-compatible anonymous objects with string enums,
  proper offset-based pagination for stream/consumer list APIs
- Add 42 E2E black-box tests (core messaging, auth, TLS, accounts, JetStream)
- Add ~1000 parity tests across all subsystems (gaps closure)
- Update gap inventory docs to reflect implementation status
2026-03-12 14:09:23 -04:00

43 KiB

Auth & Accounts — Gap Analysis

This file tracks what has and hasn't been ported from Go to .NET for the Auth & Accounts module. See stillmissing.md for the full LOC comparison across all modules.

LLM Instructions: How to Analyze This Category

Step 1: Read the Go Reference Files

Read each Go source file listed below. For every file:

  1. Extract all exported types (structs, interfaces, type aliases)
  2. Extract all exported methods on those types (receiver functions)
  3. Extract all exported standalone functions
  4. Note key constants, enums, and protocol states
  5. Note important unexported helpers that implement core logic (functions >20 lines)
  6. Pay attention to concurrency patterns (goroutines, mutexes, channels) — these map to different .NET patterns

Step 2: Read the .NET Implementation Files

Read all .cs files in the .NET directories listed below. For each Go symbol found in Step 1:

  1. Search for a matching type, method, or function in .NET
  2. If found, compare the behavior: does it handle the same edge cases? Same error paths?
  3. If partially implemented, note what's missing
  4. If not found, note it as MISSING

Step 3: Cross-Reference Tests

Compare Go test functions against .NET test methods:

  1. For each Go Test* function, check if a corresponding .NET [Fact] or [Theory] exists
  2. Note which test scenarios are covered and which are missing
  3. Check the parity DB (docs/test_parity.db) for existing mappings:
    sqlite3 docs/test_parity.db "SELECT go_test, dotnet_test, confidence FROM test_mappings tm JOIN go_tests gt ON tm.go_test_id=gt.rowid JOIN dotnet_tests dt ON tm.dotnet_test_id=dt.rowid WHERE gt.go_file LIKE '%PATTERN%'"
    

Step 4: Classify Each Item

Use these status values:

Status Meaning
PORTED Equivalent exists in .NET with matching behavior
PARTIAL .NET implementation exists but is incomplete (missing edge cases, error handling, or features)
MISSING No .NET equivalent found — needs to be ported
NOT_APPLICABLE Go-specific pattern that doesn't apply to .NET (build tags, platform-specific goroutine tricks, etc.)
DEFERRED Intentionally skipped for now (document why)

Step 5: Fill In the Gap Inventory

Add rows to the Gap Inventory table below. Group by Go source file. Include the Go file and line number so a porting LLM can jump directly to the reference implementation.

Key Porting Notes for Auth & Accounts

  • accounts.go is the second-largest functional file (~4,100 lines). It manages multi-tenant isolation with per-account Sublists, service latency tracking, and subject import/export mappings.
  • The Go implementation supports 6+ auth mechanisms. Check which are implemented in .NET's Auth/ directory.
  • JWT handling in Go includes account claims, user claims, activation tokens, and revocation lists.
  • Service imports/exports allow cross-account message delivery — check src/NATS.Server/Imports/.

Go Reference Files (Source)

  • golang/nats-server/server/auth.go — Auth mechanisms: username/password, token, NKeys (Ed25519), JWT, external auth callout, LDAP
  • golang/nats-server/server/auth_callout.go — External auth callout service
  • golang/nats-server/server/nkey.go — NKey (Ed25519) validation
  • golang/nats-server/server/jwt.go — JWT claims parsing, account/user claims
  • golang/nats-server/server/accounts.go — Multi-tenant account isolation (~4,100 lines). Each account has its own Sublist, client set, subject namespace. Supports exports/imports.

Go Reference Files (Tests)

  • golang/nats-server/server/auth_test.go
  • golang/nats-server/server/auth_callout_test.go
  • golang/nats-server/server/nkey_test.go
  • golang/nats-server/server/jwt_test.go
  • golang/nats-server/server/accounts_test.go
  • golang/nats-server/server/trust_test.go

.NET Implementation Files (Source)

  • src/NATS.Server/Auth/ (all files including Jwt/ subdirectory)
  • src/NATS.Server/Imports/ (account import/export)

.NET Implementation Files (Tests)

  • tests/NATS.Server.Tests/Auth/
  • tests/NATS.Server.Tests/Accounts/

Gap Inventory

auth.go (1,697 lines)

Go Symbol Go File:Line Status .NET Equivalent Notes
Authentication interface golang/nats-server/server/auth.go:40 PORTED src/NATS.Server/Auth/IAuthenticator.cs:7 Renamed to IAuthenticator; Check(ClientAuthentication) -> Authenticate(ClientAuthContext)
ClientAuthentication interface golang/nats-server/server/auth.go:46 PORTED src/NATS.Server/Auth/IAuthenticator.cs:12 Mapped to ClientAuthContext record
NkeyUser struct golang/nats-server/server/auth.go:62 PORTED src/NATS.Server/Auth/NKeyUser.cs:3 Added parity fields Issued, AllowedConnectionTypes, and ProxyRequired
User struct golang/nats-server/server/auth.go:73 PORTED src/NATS.Server/Auth/User.cs:3 Added parity fields AllowedConnectionTypes and ProxyRequired
User.clone() golang/nats-server/server/auth.go:85 NOT_APPLICABLE .NET uses immutable init-only records; deep clone not needed
NkeyUser.clone() golang/nats-server/server/auth.go:106 NOT_APPLICABLE .NET uses immutable init-only records; deep clone not needed
SubjectPermission struct golang/nats-server/server/auth.go:127 PORTED src/NATS.Server/Auth/Permissions.cs:10
ResponsePermission struct golang/nats-server/server/auth.go:134 PORTED src/NATS.Server/Auth/Permissions.cs:16
Permissions struct golang/nats-server/server/auth.go:141 PORTED src/NATS.Server/Auth/Permissions.cs:3
RoutePermissions struct golang/nats-server/server/auth.go:150 MISSING Route-level permissions for cluster; needed for clustering
SubjectPermission.clone() golang/nats-server/server/auth.go:156 NOT_APPLICABLE .NET uses immutable records
Permissions.clone() golang/nats-server/server/auth.go:174 NOT_APPLICABLE .NET uses immutable records
checkAuthforWarnings() golang/nats-server/server/auth.go:196 MISSING Warns about plaintext passwords at startup
assignGlobalAccountToOrphanUsers() golang/nats-server/server/auth.go:226 PORTED src/NATS.Server/Auth/AuthService.cs:176 AuthService.Build now normalizes orphan users/nkeys onto $G via NormalizeUsers/NormalizeNKeys.
validateResponsePermissions() golang/nats-server/server/auth.go:243 PORTED src/NATS.Server/Auth/AuthService.cs:222 Added response-permission normalization: ensures publish allow-list exists, sets MaxMsgs default to DefaultAllowResponseMaxMsgs, and Expires default to DefaultAllowResponseExpiration when zero.
configureAuthorization() golang/nats-server/server/auth.go:266 PARTIAL src/NATS.Server/Auth/AuthService.cs:30 AuthService.Build covers the priority chain; missing websocket/mqtt auth config, auth callout account validation
buildNkeysAndUsersFromOptions() golang/nats-server/server/auth.go:325 PARTIAL src/NATS.Server/Auth/AuthService.cs:31 User/NKey map building, clone normalization, orphan account assignment, and response-permission defaulting now occur in AuthService.Build; remaining gaps are server-level warnings and broader router/gateway/leaf auth wiring.
checkAuthentication() golang/nats-server/server/auth.go:365 PARTIAL src/NATS.Server/Auth/AuthService.cs:97 Only CLIENT kind is implemented; ROUTER, GATEWAY, LEAF auth missing
isClientAuthorized() golang/nats-server/server/auth.go:382 PORTED src/NATS.Server/Auth/AuthService.cs:97 Core flow matches; missing accountConnectEvent
matchesPinnedCert() golang/nats-server/server/auth.go:405 PORTED src/NATS.Server/Tls/TlsHelper.cs:132 TlsHelper.MatchesPinnedCert(cert, pinned) implements hash-based pinned-certificate validation; covered by targeted tests in TlsHelperTests.
processUserPermissionsTemplate() golang/nats-server/server/auth.go:427 PORTED src/NATS.Server/Auth/Jwt/PermissionTemplates.cs:36 Full template expansion with cartesian product
processClientOrLeafAuthentication() golang/nats-server/server/auth.go:588 PARTIAL src/NATS.Server/Auth/AuthService.cs:97 Core client auth flow ported; missing leaf node auth, proxy check integration, auth callout defer, JWT src/time validation
proxyCheck() golang/nats-server/server/auth.go:1153 PARTIAL src/NATS.Server/Auth/ProxyAuthenticator.cs:3 Basic proxy prefix auth exists; full NKey signature-based proxy verification missing
getTLSAuthDCs() golang/nats-server/server/auth.go:1198 PORTED src/NATS.Server/Auth/TlsMapAuthenticator.cs:68 Added DC extraction helper for TLS auth subject matching (GetTlsAuthDcs).
tlsMapAuthFn type golang/nats-server/server/auth.go:1218 NOT_APPLICABLE Go function type; .NET uses delegate/lambda
checkClientTLSCertSubject() golang/nats-server/server/auth.go:1220 PARTIAL src/NATS.Server/Auth/TlsMapAuthenticator.cs:25 Added DN/CN plus SAN email/DNS/URI matching and DC-augmented RDN matching; LDAP raw-subject DN parsing and full Go callback behavior remain unported.
dnsAltNameLabels() golang/nats-server/server/auth.go:1316 PORTED src/NATS.Server/Auth/TlsMapAuthenticator.cs:85 Added DNS alt-name label splitter with lowercase normalization.
dnsAltNameMatches() golang/nats-server/server/auth.go:1321 PORTED src/NATS.Server/Auth/TlsMapAuthenticator.cs:93 Added RFC6125-style DNS alt-name matching helper (left-most * wildcard only).
isRouterAuthorized() golang/nats-server/server/auth.go:1349 MISSING Cluster route authentication
isGatewayAuthorized() golang/nats-server/server/auth.go:1390 MISSING Gateway authentication
registerLeafWithAccount() golang/nats-server/server/auth.go:1425 MISSING Leaf node account registration
isLeafNodeAuthorized() golang/nats-server/server/auth.go:1443 MISSING Leaf node authentication
isBcrypt() golang/nats-server/server/auth.go:1569 PORTED src/NATS.Server/Auth/UserPasswordAuthenticator.cs:65 Simplified to StartsWith("$2") check
comparePasswords() golang/nats-server/server/auth.go:1577 PORTED src/NATS.Server/Auth/UserPasswordAuthenticator.cs:46 bcrypt + constant-time comparison
validateAuth() golang/nats-server/server/auth.go:1595 MISSING Top-level auth config validation
validateAllowedConnectionTypes() golang/nats-server/server/auth.go:1612 PARTIAL src/NATS.Server/Auth/Jwt/JwtConnectionTypes.cs:18 Validation logic exists in JWT context; not used for config-level validation
validateNoAuthUser() golang/nats-server/server/auth.go:1631 MISSING Validates no_auth_user exists in Users/Nkeys
validateProxies() golang/nats-server/server/auth.go:1657 MISSING Validates proxy trusted keys are valid NKeys
processProxiesTrustedKeys() golang/nats-server/server/auth.go:1672 MISSING Builds NKey keypairs from proxy trusted keys
getAuthErrClosedState() golang/nats-server/server/auth.go:1688 MISSING Maps auth errors to connection close states

auth_callout.go (497 lines)

Go Symbol Go File:Line Status .NET Equivalent Notes
AuthCalloutSubject const golang/nats-server/server/auth_callout.go:30 PORTED src/NATS.Server/Auth/ExternalAuthCalloutAuthenticator.cs:5 Added $SYS.REQ.USER.AUTH constant
AuthRequestSubject const golang/nats-server/server/auth_callout.go:31 PORTED src/NATS.Server/Auth/ExternalAuthCalloutAuthenticator.cs:6 Added nats-authorization-request constant
AuthRequestXKeyHeader const golang/nats-server/server/auth_callout.go:32 PORTED src/NATS.Server/Auth/ExternalAuthCalloutAuthenticator.cs:7 Added Nats-Server-Xkey header constant
processClientOrLeafCallout() golang/nats-server/server/auth_callout.go:36 PARTIAL src/NATS.Server/Auth/ExternalAuthCalloutAuthenticator.cs:3 .NET has a simplified external auth callout via IExternalAuthClient interface; Go implementation uses internal NATS messaging ($SYS subjects), JWT encoding/decoding, XKey encryption, replay prevention — all missing from .NET
fillClientInfo() golang/nats-server/server/auth_callout.go:456 MISSING Fills jwt.ClientInformation for auth callout requests
fillConnectOpts() golang/nats-server/server/auth_callout.go:477 MISSING Fills jwt.ConnectOptions for auth callout requests

nkey.go (47 lines)

Go Symbol Go File:Line Status .NET Equivalent Notes
nonceRawLen const golang/nats-server/server/nkey.go:23 PORTED src/NATS.Server/Auth/AuthService.cs:147 Uses 11-byte raw nonce
nonceLen const golang/nats-server/server/nkey.go:24 NOT_APPLICABLE Derived constant (base64 length)
NonceRequired() golang/nats-server/server/nkey.go:28 PORTED src/NATS.Server/Auth/AuthService.cs:18 Property on AuthService
nonceRequired() golang/nats-server/server/nkey.go:36 PORTED src/NATS.Server/Auth/AuthService.cs:34 Checked during Build based on NKeys/TrustedKeys
generateNonce() golang/nats-server/server/nkey.go:42 PORTED src/NATS.Server/Auth/AuthService.cs:146 GenerateNonce + EncodeNonce use RandomNumberGenerator.Fill

jwt.go (245 lines)

Go Symbol Go File:Line Status .NET Equivalent Notes
jwtPrefix const golang/nats-server/server/jwt.go:29 PORTED src/NATS.Server/Auth/Jwt/NatsJwt.cs:17 "eyJ" constant
ReadOperatorJWT() golang/nats-server/server/jwt.go:32 MISSING Reads operator JWT from file/inline string
readOperatorJWT() golang/nats-server/server/jwt.go:37 MISSING Internal helper for operator JWT parsing
wipeSlice() golang/nats-server/server/jwt.go:61 NOT_APPLICABLE Go-specific memory wiping; .NET has CryptographicOperations.ZeroMemory
validateTrustedOperators() golang/nats-server/server/jwt.go:70 MISSING Validates operator JWT config (keys, resolver, system account, version)
validateSrc() golang/nats-server/server/jwt.go:182 MISSING Validates user JWT source CIDR restrictions
validateTimes() golang/nats-server/server/jwt.go:204 MISSING Validates user JWT time-of-day restrictions

accounts.go (4,774 lines)

Go Symbol Go File:Line Status .NET Equivalent Notes
globalAccountName const golang/nats-server/server/accounts.go:44 PORTED src/NATS.Server/Auth/Account.cs:9 Account.GlobalAccountName = "$G"
Account struct golang/nats-server/server/accounts.go:52 PARTIAL src/NATS.Server/Auth/Account.cs:7 Core fields ported (Name, SubList, limits, clients, revocations, exports, imports). Missing: stats (gw/rt/ln), gwReplyMapping, claimJWT, mappings, hasMapped, lleafs, leafClusters, js/jsLimits, nrgAccount, extAuth, defaultPerms, nameTag, tags, traceDest
limits struct golang/nats-server/server/accounts.go:127 PARTIAL src/NATS.Server/Auth/Account.cs:15-19 MaxConnections, MaxSubscriptions ported; missing MaxPayload, MaxLeafNodeConnections, MaxRemoteConnections
sconns struct golang/nats-server/server/accounts.go:136 MISSING Remote server connection count tracking
streamImport struct golang/nats-server/server/accounts.go:142 PORTED src/NATS.Server/Imports/StreamImport.cs:7
ClientInfoHdr const golang/nats-server/server/accounts.go:157 PORTED src/NATS.Server/Auth/Account.cs:11 Added Account.ClientInfoHdr = "Nats-Request-Info" constant.
serviceImport struct golang/nats-server/server/accounts.go:160 PORTED src/NATS.Server/Imports/ServiceImport.cs:6
serviceRespEntry struct golang/nats-server/server/accounts.go:187 MISSING TTL-tracked response entries
ServiceRespType enum golang/nats-server/server/accounts.go:193 PORTED src/NATS.Server/Imports/ServiceResponseType.cs:3 Singleton, Streamed, Chunked
ServiceRespType.String() golang/nats-server/server/accounts.go:203 NOT_APPLICABLE Go Stringer interface; .NET enum has ToString()
exportAuth struct golang/nats-server/server/accounts.go:217 PORTED src/NATS.Server/Imports/ExportAuth.cs:5 TokenRequired, AccountPosition, ApprovedAccounts, RevokedAccounts
streamExport struct golang/nats-server/server/accounts.go:225 PORTED src/NATS.Server/Imports/StreamExport.cs:3
serviceExport struct golang/nats-server/server/accounts.go:230 PORTED src/NATS.Server/Imports/ServiceExport.cs:5
serviceLatency struct golang/nats-server/server/accounts.go:245 PORTED src/NATS.Server/Imports/ServiceLatency.cs:3
exportMap struct golang/nats-server/server/accounts.go:251 PORTED src/NATS.Server/Imports/ExportMap.cs:3
importMap struct golang/nats-server/server/accounts.go:259 PORTED src/NATS.Server/Imports/ImportMap.cs:5
NewAccount() golang/nats-server/server/accounts.go:266 PORTED src/NATS.Server/Auth/Account.cs:91 Account constructor
Account.String() golang/nats-server/server/accounts.go:275 NOT_APPLICABLE Trivial Go Stringer
Account.setTraceDest() golang/nats-server/server/accounts.go:279 MISSING Message tracing destination
Account.getTraceDestAndSampling() golang/nats-server/server/accounts.go:285 MISSING Message tracing config
Account.shallowCopy() golang/nats-server/server/accounts.go:298 MISSING Shallow copy for account reload
Account.nextEventID() golang/nats-server/server/accounts.go:354 MISSING NUID-based event ID generation
Account.getClientsLocked() golang/nats-server/server/accounts.go:363 MISSING Returns client slice under lock
Account.getClients() golang/nats-server/server/accounts.go:375 MISSING Returns client slice with lock acquisition
Account.getExternalClientsLocked() golang/nats-server/server/accounts.go:384 MISSING Returns only external clients
Account.updateRemoteServer() golang/nats-server/server/accounts.go:399 MISSING Cluster remote server tracking
Account.removeRemoteServer() golang/nats-server/server/accounts.go:446 MISSING Cluster remote server removal
Account.expectedRemoteResponses() golang/nats-server/server/accounts.go:460 MISSING Expected responses from remote servers
Account.clearEventing() golang/nats-server/server/accounts.go:472 MISSING Clears event timers
Account.GetName() golang/nats-server/server/accounts.go:484 PORTED src/NATS.Server/Auth/Account.cs:12 Name property
Account.NumConnections() golang/nats-server/server/accounts.go:519 PORTED src/NATS.Server/Auth/Account.cs:96 ClientCount property
Account.NumRemoteConnections() golang/nats-server/server/accounts.go:528 MISSING Remote connection count (clustering)
Account.NumLocalConnections() golang/nats-server/server/accounts.go:537 PORTED src/NATS.Server/Auth/Account.cs:96 ClientCount is local only
Account.MaxTotalConnectionsReached() golang/nats-server/server/accounts.go:563 PORTED src/NATS.Server/Auth/Account.cs:103 AddClient checks MaxConnections
Account.MaxActiveConnections() golang/nats-server/server/accounts.go:575 PORTED src/NATS.Server/Auth/Account.cs:15 MaxConnections property
Account.MaxTotalLeafNodesReached() golang/nats-server/server/accounts.go:583 MISSING Leaf node connection limits
Account.NumLeafNodes() golang/nats-server/server/accounts.go:599 MISSING Leaf node count
Account.NumRemoteLeafNodes() golang/nats-server/server/accounts.go:608 MISSING Remote leaf count
Account.MaxActiveLeafNodes() golang/nats-server/server/accounts.go:618 MISSING Leaf node limit
Account.RoutedSubs() golang/nats-server/server/accounts.go:627 MISSING Routed subscription count
Account.TotalSubs() golang/nats-server/server/accounts.go:634 PORTED src/NATS.Server/Auth/Account.cs:97 SubscriptionCount
Account.shouldLogMaxSubErr() golang/nats-server/server/accounts.go:643 MISSING Rate-limited logging for max sub errors
MapDest struct golang/nats-server/server/accounts.go:660 MISSING Subject mapping destination with weight
NewMapDest() golang/nats-server/server/accounts.go:666 MISSING MapDest constructor
destination struct golang/nats-server/server/accounts.go:671 MISSING Internal mapping destination
mapping struct golang/nats-server/server/accounts.go:677 MISSING Subject mapping with weighted destinations
Account.AddMapping() golang/nats-server/server/accounts.go:686 MISSING Subject remapping (1:1)
Account.AddWeightedMappings() golang/nats-server/server/accounts.go:691 MISSING Weighted subject mappings
Account.RemoveMapping() golang/nats-server/server/accounts.go:810 MISSING Remove a subject mapping
Account.hasMappings() golang/nats-server/server/accounts.go:839 MISSING Check for subject mappings
Account.selectMappedSubject() golang/nats-server/server/accounts.go:848 MISSING Select destination via weighted mapping
Account.SubscriptionInterest() golang/nats-server/server/accounts.go:929 PORTED src/NATS.Server/Auth/Account.cs:797 Added direct parity API: returns Interest(subject) > 0.
Account.Interest() golang/nats-server/server/accounts.go:934 PORTED src/NATS.Server/Auth/Account.cs:803 Added matcher-count API backed by SubList.NumInterest(subject) (plain + queue).
Account.addClient() golang/nats-server/server/accounts.go:947 PORTED src/NATS.Server/Auth/Account.cs:103 AddClient checks MaxConnections
Account.registerLeafNodeCluster() golang/nats-server/server/accounts.go:986 MISSING Leaf node cluster registration
Account.hasLeafNodeCluster() golang/nats-server/server/accounts.go:996 MISSING Check for leaf node cluster
Account.isLeafNodeClusterIsolated() golang/nats-server/server/accounts.go:1004 MISSING Leaf cluster isolation check
Account.removeLeafNode() golang/nats-server/server/accounts.go:1018 MISSING Remove leaf node from account
Account.removeClient() golang/nats-server/server/accounts.go:1038 PORTED src/NATS.Server/Auth/Account.cs:111 RemoveClient
setExportAuth() golang/nats-server/server/accounts.go:1075 PARTIAL src/NATS.Server/Imports/ExportAuth.cs:5 ExportAuth struct exists; setExportAuth helper logic partially in Account.AddServiceExport
Account.AddServiceExport() golang/nats-server/server/accounts.go:1101 PORTED src/NATS.Server/Auth/Account.cs:309 AddServiceExport
Account.AddServiceExportWithResponse() golang/nats-server/server/accounts.go:1111 PORTED src/NATS.Server/Auth/Account.cs:309 Included in AddServiceExport with responseType param
Account.TrackServiceExport() golang/nats-server/server/accounts.go:1163 PARTIAL src/NATS.Server/Auth/ServiceLatencyTracker.cs:7 Tracker exists but wiring to export subjects via NATS internal pub missing
Account.TrackServiceExportWithSampling() golang/nats-server/server/accounts.go:1169 PARTIAL src/NATS.Server/Imports/ServiceLatency.cs:5 SamplingPercentage field exists; full integration missing
Account.UnTrackServiceExport() golang/nats-server/server/accounts.go:1238 MISSING Remove latency tracking from export
Account.IsExportService() golang/nats-server/server/accounts.go:1281 PORTED src/NATS.Server/Auth/Account.cs:298 HasServiceExport
Account.IsExportServiceTracking() golang/nats-server/server/accounts.go:1298 MISSING Check if latency tracking is enabled for export
ServiceLatency struct golang/nats-server/server/accounts.go:1326 PORTED src/NATS.Server/Imports/LatencyTracker.cs:5 ServiceLatencyMsg
ServiceLatencyType const golang/nats-server/server/accounts.go:1340 PORTED src/NATS.Server/Imports/LatencyTracker.cs:8 Type field default
ServiceLatency.NATSTotalTime() golang/nats-server/server/accounts.go:1343 MISSING Total time computation
ServiceLatency.merge() golang/nats-server/server/accounts.go:1354 MISSING Merge latency metrics
sanitizeLatencyMetric() golang/nats-server/server/accounts.go:1370 MISSING Sanitize negative latencies
remoteLatency struct golang/nats-server/server/accounts.go:1380 MISSING Remote latency for cluster
Account.sendLatencyResult() golang/nats-server/server/accounts.go:1388 MISSING Publish latency result to tracking subject
Account.sendBadRequestTrackingLatency() golang/nats-server/server/accounts.go:1401 MISSING Track bad request latency
Account.sendReplyInterestLostTrackLatency() golang/nats-server/server/accounts.go:1414 MISSING Track lost reply interest
Account.sendBackendErrorTrackingLatency() golang/nats-server/server/accounts.go:1430 MISSING Track backend error latency
Account.sendTrackingLatency() golang/nats-server/server/accounts.go:1458 MISSING Core latency tracking send
updateAllClientsServiceExportResponseTime() golang/nats-server/server/accounts.go:1527 MISSING Update client response times
Account.lowestServiceExportResponseTime() golang/nats-server/server/accounts.go:1542 MISSING Find lowest response time
Account.AddServiceImportWithClaim() golang/nats-server/server/accounts.go:1554 PARTIAL src/NATS.Server/Auth/Account.cs:338 AddServiceImport exists; JWT claim-based import missing
addServiceImportWithClaim() golang/nats-server/server/accounts.go:1560 PARTIAL src/NATS.Server/Auth/Account.cs:338 Core logic ported; missing claim validation, activation token handling
MaxAccountCycleSearchDepth const golang/nats-server/server/accounts.go:1593 MISSING Depth limit for cycle detection
Account.serviceImportFormsCycle() golang/nats-server/server/accounts.go:1595 PORTED src/NATS.Server/Auth/AccountImportExport.cs:18 DetectCycle
Account.checkServiceImportsForCycles() golang/nats-server/server/accounts.go:1599 PORTED src/NATS.Server/Auth/AccountImportExport.cs:18 DFS cycle detection
Account.streamImportFormsCycle() golang/nats-server/server/accounts.go:1627 PORTED src/NATS.Server/Auth/Account.cs:405 StreamImportFormsCycle
Account.hasServiceExportMatching() golang/nats-server/server/accounts.go:1632 PORTED src/NATS.Server/Auth/Account.cs:298 HasServiceExport
Account.hasStreamExportMatching() golang/nats-server/server/accounts.go:1642 MISSING Check if stream export matches subject
Account.checkStreamImportsForCycles() golang/nats-server/server/accounts.go:1651 PORTED src/NATS.Server/Auth/Account.cs:412 DetectStreamImportCycle (private)
Account.SetServiceImportSharing() golang/nats-server/server/accounts.go:1686 MISSING Enable/disable service import sharing
Account.AddServiceImport() golang/nats-server/server/accounts.go:1715 PORTED src/NATS.Server/Auth/Account.cs:338
Account.NumPendingReverseResponses() golang/nats-server/server/accounts.go:1721 PORTED src/NATS.Server/Auth/Account.cs:772 ReverseResponseMapCount
Account.NumPendingAllResponses() golang/nats-server/server/accounts.go:1728 PORTED src/NATS.Server/Auth/Account.cs:813 Added parity API delegating to NumPendingResponses("").
Account.NumPendingResponses() golang/nats-server/server/accounts.go:1736 PORTED src/NATS.Server/Auth/Account.cs:820 Added filtered/aggregate pending-response counter over Exports.Responses, keyed by matched service export.
Account.NumServiceImports() golang/nats-server/server/accounts.go:1756 PORTED src/NATS.Server/Auth/Account.cs:843 Added count of configured service import subject keys (Imports.Services.Count).
rsiReason enum golang/nats-server/server/accounts.go:1763 PORTED src/NATS.Server/Auth/Account.cs:1047 Added ResponseServiceImportRemovalReason enum (Ok, NoDelivery, Timeout).
Account.removeRespServiceImport() golang/nats-server/server/accounts.go:1772 PARTIAL src/NATS.Server/Auth/Account.cs:849 Added RemoveRespServiceImport(..., reason) and reason enum wiring; still missing Go's reverse-entry cleanup and reason-driven latency/metrics side effects.
Account.getServiceImportForAccountLocked() golang/nats-server/server/accounts.go:1795 MISSING Find service import by dest account + subject
Account.removeServiceImport() golang/nats-server/server/accounts.go:1812 PORTED src/NATS.Server/Auth/Account.cs:366 RemoveServiceImport
Account.addReverseRespMapEntry() golang/nats-server/server/accounts.go:1858 PORTED src/NATS.Server/Auth/Account.cs:752 AddReverseRespMapEntry
Account.checkForReverseEntries() golang/nats-server/server/accounts.go:1872 PARTIAL src/NATS.Server/Auth/Account.cs:761 Lookup exists; missing recursive check + interest validation
Account.serviceImportShadowed() golang/nats-server/server/accounts.go:2015 PORTED src/NATS.Server/Auth/Account.cs:786 ServiceImportShadowed
Account.serviceImportExists() golang/nats-server/server/accounts.go:2031 MISSING Check if service import exists by dest account + from
Account.addServiceImport() golang/nats-server/server/accounts.go:2041 PARTIAL src/NATS.Server/Auth/Account.cs:338 Core add logic; missing claim/activation token handling
Account.unsubscribeInternal() golang/nats-server/server/accounts.go:2130 MISSING Internal subscription cleanup
Account.subscribeServiceImportResponse() golang/nats-server/server/accounts.go:2137 MISSING Response subscription for service import
Account.subscribeInternalEx() golang/nats-server/server/accounts.go:2141 MISSING Internal subscription with routing flag
Account.addServiceImportSub() golang/nats-server/server/accounts.go:2156 MISSING Wire up service import subscription
Account.removeAllServiceImportSubs() golang/nats-server/server/accounts.go:2190 MISSING Remove all service import subscriptions
Account.addAllServiceImportSubs() golang/nats-server/server/accounts.go:2215 MISSING Add all service import subscriptions
shouldSample() golang/nats-server/server/accounts.go:2279 PORTED src/NATS.Server/Imports/LatencyTracker.cs:28 LatencyTracker.ShouldSample
Account.processServiceImportResponse() golang/nats-server/server/accounts.go:2358 MISSING Handle incoming response for service import
Account.createRespWildcard() golang/nats-server/server/accounts.go:2380 MISSING Create wildcard reply prefix
isTrackedReply() golang/nats-server/server/accounts.go:2391 MISSING Check if reply is for a tracked service
Account.newServiceReply() golang/nats-server/server/accounts.go:2398 PARTIAL src/NATS.Server/Imports/ResponseRouter.cs:19 GenerateReplyPrefix exists
serviceExport.setResponseThresholdTimer() golang/nats-server/server/accounts.go:2446 MISSING Timer for response threshold
serviceExport.clearResponseThresholdTimer() golang/nats-server/server/accounts.go:2454 MISSING Clear response threshold timer
serviceExport.checkExpiredResponses() golang/nats-server/server/accounts.go:2465 MISSING Clean up expired responses
Account.ServiceExportResponseThreshold() golang/nats-server/server/accounts.go:2510 PORTED src/NATS.Server/Auth/Account.cs:468 GetServiceResponseThreshold
Account.SetServiceExportResponseThreshold() golang/nats-server/server/accounts.go:2522 PORTED src/NATS.Server/Auth/Account.cs:461 SetServiceResponseThreshold
Account.SetServiceExportAllowTrace() golang/nats-server/server/accounts.go:2549 MISSING Enable tracing on service export
Account.addRespServiceImport() golang/nats-server/server/accounts.go:2562 PORTED src/NATS.Server/Imports/ResponseRouter.cs:33 CreateResponseImport
Account.AddStreamImportWithClaim() golang/nats-server/server/accounts.go:2598 PARTIAL src/NATS.Server/Auth/Account.cs:371 AddStreamImport exists; claim validation missing
Account.AddMappedStreamImport() golang/nats-server/server/accounts.go:2629 PORTED src/NATS.Server/Auth/Account.cs:371 AddStreamImport with 'to' parameter
Account.isStreamImportDuplicate() golang/nats-server/server/accounts.go:2694 MISSING Duplicate stream import detection
Account.AddStreamImport() golang/nats-server/server/accounts.go:2704 PORTED src/NATS.Server/Auth/Account.cs:371
IsPublicExport var golang/nats-server/server/accounts.go:2709 MISSING Sentinel for public export
Account.AddStreamExport() golang/nats-server/server/accounts.go:2713 PORTED src/NATS.Server/Auth/Account.cs:323 AddStreamExport
Account.checkStreamImportAuthorized() golang/nats-server/server/accounts.go:2746 PARTIAL src/NATS.Server/Imports/ExportAuth.cs:12 IsAuthorized checks approved accounts; missing token/claim validation
Account.checkAuth() golang/nats-server/server/accounts.go:2761 PARTIAL src/NATS.Server/Imports/ExportAuth.cs:12 Basic approval; missing token validation and wildcard matching
Account.checkStreamExportApproved() golang/nats-server/server/accounts.go:2782 PARTIAL src/NATS.Server/Imports/ExportAuth.cs:12 Via IsAuthorized; missing wildcard subject matching
Account.checkServiceExportApproved() golang/nats-server/server/accounts.go:2809 PARTIAL src/NATS.Server/Imports/ExportAuth.cs:12 Via IsAuthorized; missing wildcard subject matching
Account.getServiceExport() golang/nats-server/server/accounts.go:2837 PORTED src/NATS.Server/Auth/Account.cs:267 GetExactServiceExport
Account.getWildcardServiceExport() golang/nats-server/server/accounts.go:2849 PORTED src/NATS.Server/Auth/Account.cs:279 GetWildcardServiceExport
Account.streamActivationExpired() golang/nats-server/server/accounts.go:2860 PARTIAL src/NATS.Server/Auth/Account.cs:613 IsActivationExpired exists; missing auto-removal and re-check logic
Account.serviceActivationExpired() golang/nats-server/server/accounts.go:2895 PARTIAL src/NATS.Server/Auth/Account.cs:613 IsActivationExpired exists; missing auto-removal
Account.activationExpired() golang/nats-server/server/accounts.go:2920 PARTIAL src/NATS.Server/Auth/Account.cs:620 GetExpiredActivations + RemoveExpiredActivations
isRevoked() golang/nats-server/server/accounts.go:2929 PORTED src/NATS.Server/Auth/Account.cs:52 IsUserRevoked
Account.checkActivation() golang/nats-server/server/accounts.go:2943 PARTIAL src/NATS.Server/Auth/Account.cs:598 CheckActivationExpiry exists; missing issuer trust chain validation
Account.isIssuerClaimTrusted() golang/nats-server/server/accounts.go:2988 MISSING Validates issuer against account signing keys
Account.checkStreamImportsEqual() golang/nats-server/server/accounts.go:3011 MISSING Equality check for reload
Account.checkStreamExportsEqual() golang/nats-server/server/accounts.go:3036 MISSING Equality check for reload
isStreamExportEqual() golang/nats-server/server/accounts.go:3054 MISSING Stream export comparison
Account.checkServiceExportsEqual() golang/nats-server/server/accounts.go:3067 MISSING Equality check for reload
isServiceExportEqual() golang/nats-server/server/accounts.go:3085 MISSING Service export comparison
isExportAuthEqual() golang/nats-server/server/accounts.go:3121 MISSING Export auth comparison
Account.checkServiceImportAuthorized() golang/nats-server/server/accounts.go:3148 PARTIAL src/NATS.Server/Imports/ExportAuth.cs:12 Via IsAuthorized; missing token validation
Account.IsExpired() golang/nats-server/server/accounts.go:3165 PORTED src/NATS.Server/Auth/Account.cs:523 IsExpired property
Account.expiredTimeout() golang/nats-server/server/accounts.go:3170 MISSING Timer callback for expired accounts
Account.setExpirationTimer() golang/nats-server/server/accounts.go:3184 PARTIAL src/NATS.Server/Auth/Account.cs:553 SetExpiration exists; actual Timer not created
Account.clearExpirationTimer() golang/nats-server/server/accounts.go:3189 PARTIAL src/NATS.Server/Auth/Account.cs:557 ClearExpiration exists; no Timer to clear
Account.checkUserRevoked() golang/nats-server/server/accounts.go:3199 PORTED src/NATS.Server/Auth/Account.cs:52 IsUserRevoked
Account.failBearer() golang/nats-server/server/accounts.go:3206 MISSING Check if account disallows bearer tokens
Account.checkExpiration() golang/nats-server/server/accounts.go:3213 PARTIAL src/NATS.Server/Auth/Account.cs:523 IsExpired check exists; missing timer setup
Account.hasIssuer() golang/nats-server/server/accounts.go:3235 MISSING Check signing keys with scope
Account.getLDSubject() golang/nats-server/server/accounts.go:3249 MISSING Leaf node deny subject
SetAccountResolver() golang/nats-server/server/accounts.go:3267 MISSING Server-level resolver assignment
AccountResolver() golang/nats-server/server/accounts.go:3274 MISSING Server-level resolver getter
Account.isClaimAccount() golang/nats-server/server/accounts.go:3283 MISSING Check if account backed by JWT
UpdateAccountClaims() golang/nats-server/server/accounts.go:3290 PARTIAL src/NATS.Server/Auth/Account.cs:684 UpdateAccountClaims exists; missing full claim application (exports/imports rebuild, signing keys, external auth, mappings)
updateAccountClaimsWithRefresh() golang/nats-server/server/accounts.go:3374 PARTIAL src/NATS.Server/Auth/Account.cs:684 Diff-based update exists; missing export/import refresh, dependent account refresh
buildInternalAccount() golang/nats-server/server/accounts.go:3957 MISSING Build account from JWT claims
buildPermissionsFromJwt() golang/nats-server/server/accounts.go:3979 PORTED src/NATS.Server/Auth/JwtAuthenticator.cs:117 Inline in JwtAuthenticator.Authenticate
buildInternalNkeyUser() golang/nats-server/server/accounts.go:4012 MISSING Build NkeyUser from JWT user claims
fetchAccount() golang/nats-server/server/accounts.go:4027 MISSING Fetch account JWT with NKey validation
AccountResolver interface golang/nats-server/server/accounts.go:4035 PARTIAL src/NATS.Server/Auth/Jwt/AccountResolver.cs:14 IAccountResolver has Fetch/Store/IsReadOnly; missing Start, IsTrackingUpdate, Reload, Close
MemAccResolver struct golang/nats-server/server/accounts.go:4073 PORTED src/NATS.Server/Auth/Jwt/AccountResolver.cs:44 MemAccountResolver
MemAccResolver.Fetch() golang/nats-server/server/accounts.go:4079 PORTED src/NATS.Server/Auth/Jwt/AccountResolver.cs:53 FetchAsync
MemAccResolver.Store() golang/nats-server/server/accounts.go:4087 PORTED src/NATS.Server/Auth/Jwt/AccountResolver.cs:60 StoreAsync
URLAccResolver struct golang/nats-server/server/accounts.go:4097 MISSING HTTP-based account resolver
NewURLAccResolver() golang/nats-server/server/accounts.go:4104 MISSING URL resolver constructor
URLAccResolver.Fetch() golang/nats-server/server/accounts.go:4123 MISSING HTTP GET for account JWT
DirAccResolver struct golang/nats-server/server/accounts.go:4143 MISSING Directory-based resolver with NATS sync
DirAccResolver.Start() golang/nats-server/server/accounts.go:4352 MISSING Start directory resolver with NATS subscriptions
DirAccResolver.Fetch() golang/nats-server/server/accounts.go:4533 MISSING Fetch from directory store
DirAccResolver.Store() golang/nats-server/server/accounts.go:4548 MISSING Store to directory
NewDirAccResolver() golang/nats-server/server/accounts.go:4574 MISSING Dir resolver constructor
CacheDirAccResolver struct golang/nats-server/server/accounts.go:4594 MISSING Caching directory resolver
Server.fetch() golang/nats-server/server/accounts.go:4599 MISSING Server-level account fetch via NATS
NewCacheDirAccResolver() golang/nats-server/server/accounts.go:4664 MISSING Cache dir resolver constructor
CacheDirAccResolver.Start() golang/nats-server/server/accounts.go:4679 MISSING Start cache resolver with NATS sync

Keeping This File Updated

After porting work is completed:

  1. Update status: Change MISSING → PORTED or PARTIAL → PORTED for each item completed
  2. Add .NET path: Fill in the ".NET Equivalent" column with the actual file:line
  3. Re-count LOC: Update the LOC numbers in stillmissing.md:
    # Re-count .NET source LOC for this module
    find src/NATS.Server/Auth/ src/NATS.Server/Imports/ -name '*.cs' -type f -exec cat {} + | wc -l
    # Re-count .NET test LOC for this module
    find tests/NATS.Server.Tests/Auth/ tests/NATS.Server.Tests/Accounts/ -name '*.cs' -type f -exec cat {} + | wc -l
    
  4. Add a changelog entry below with date and summary of what was ported
  5. Update the parity DB if new test mappings were created:
    sqlite3 docs/test_parity.db "INSERT INTO test_mappings (go_test_id, dotnet_test_id, confidence, notes) VALUES (?, ?, 'manual', 'ported in YYYY-MM-DD session')"
    

Change Log

Date Change By
2026-02-26 Executed auth-and-accounts batch 4: added auth-option normalization in AuthService.Build for orphan account assignment ($G) and response-permission defaults (MaxMsgs/Expires + publish allow-list initialization), with targeted tests (AuthServiceParityBatch4Tests). Reclassified assignGlobalAccountToOrphanUsers and validateResponsePermissions to PORTED and updated buildNkeysAndUsersFromOptions residual notes. codex
2026-02-25 File created with LLM analysis instructions auto
2026-02-25 Gap inventory populated: 5 Go files analyzed (7,260 LOC), 239 symbols classified across auth.go, auth_callout.go, nkey.go, jwt.go, accounts.go. Summary: 64 PORTED, 38 PARTIAL, 128 MISSING, 9 NOT_APPLICABLE, 0 DEFERRED auto
2026-02-25 Executed auth-and-accounts batch 1: added parity fields to NKeyUser and User, added auth callout constants to ExternalAuthCalloutAuthenticator, added targeted tests (AuthModelAndCalloutConstantsParityTests), and reclassified 5 rows (3 MISSING + 2 PARTIAL) to PORTED codex
2026-02-25 Executed auth-and-accounts batch 2: added account parity APIs/constants for interest and response/service-import accounting (ClientInfoHdr, SubscriptionInterest, Interest, NumPendingAllResponses, NumPendingResponses, NumServiceImports), introduced ResponseServiceImportRemovalReason, added RemoveRespServiceImport(..., reason), and added targeted tests (AccountResponseAndInterestParityBatch1Tests). Reclassified 7 rows to PORTED and updated removeRespServiceImport notes. codex
2026-02-25 Executed auth-and-accounts batch 3: added TLS auth parity helpers (GetTlsAuthDcs, DnsAltNameLabels, DnsAltNameMatches), extended TLS-map auth matching for SAN email/DNS/URI + DC-augmented RDN, validated pinned-cert helper parity (TlsHelper.MatchesPinnedCert), and added targeted tests (TlsMapAuthParityBatch1Tests). Reclassified 4 rows to PORTED and updated checkClientTLSCertSubject notes. codex