feat: enforce account jetstream limits and jwt tiers

This commit is contained in:
Joseph Doherty
2026-02-23 06:21:51 -05:00
parent ccbcf759a9
commit 2aa7265db1
8 changed files with 91 additions and 3 deletions

View File

@@ -1,4 +1,6 @@
using System.Text;
using System.Text.Json;
using NATS.Server.Auth;
using NATS.Server.JetStream;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Consumers;
@@ -18,9 +20,9 @@ internal sealed class JetStreamApiFixture : IAsyncDisposable
private readonly JetStreamApiRouter _router;
private readonly JetStreamPublisher _publisher;
private JetStreamApiFixture()
private JetStreamApiFixture(Account? account = null)
{
_streamManager = new StreamManager();
_streamManager = new StreamManager(account: account);
_consumerManager = new ConsumerManager();
_router = new JetStreamApiRouter(_streamManager, _consumerManager);
_publisher = new JetStreamPublisher(_streamManager);
@@ -73,6 +75,17 @@ internal sealed class JetStreamApiFixture : IAsyncDisposable
return fixture;
}
public static Task<JetStreamApiFixture> StartJwtLimitedAccountAsync(int maxStreams)
{
var account = new Account("JWT-LIMITED")
{
MaxJetStreamStreams = maxStreams,
JetStreamTier = "jwt-tier",
};
return Task.FromResult(new JetStreamApiFixture(account));
}
public Task<PubAck> PublishAndGetAckAsync(string subject, string payload, string? msgId = null, bool expectError = false)
{
if (_publisher.TryCapture(subject, Encoding.UTF8.GetBytes(payload), msgId, out var ack))
@@ -103,6 +116,16 @@ internal sealed class JetStreamApiFixture : IAsyncDisposable
return Task.FromResult(_router.Route(subject, Encoding.UTF8.GetBytes(payload)));
}
public Task<JetStreamApiResponse> CreateStreamAsync(string streamName, IReadOnlyList<string> subjects)
{
var payload = JsonSerializer.Serialize(new
{
name = streamName,
subjects,
});
return RequestLocalAsync($"$JS.API.STREAM.CREATE.{streamName}", payload);
}
public Task<StreamState> GetStreamStateAsync(string streamName)
{
return _streamManager.GetStateAsync(streamName, default).AsTask();

View File

@@ -0,0 +1,16 @@
namespace NATS.Server.Tests;
public class JetStreamJwtLimitTests
{
[Fact]
public async Task Account_limit_rejects_stream_create_when_max_streams_reached()
{
await using var fixture = await JetStreamApiFixture.StartJwtLimitedAccountAsync(maxStreams: 1);
(await fixture.CreateStreamAsync("S1", subjects: ["s1.*"])) .Error.ShouldBeNull();
var second = await fixture.CreateStreamAsync("S2", subjects: ["s2.*"]);
second.Error.ShouldNotBeNull();
second.Error!.Code.ShouldBe(10027);
}
}