Feature(Go): issue-token subcommand for minting customer JWTs
This commit is contained in:
@@ -138,7 +138,7 @@ func TestLocalSignerDeterministic(t *testing.T) {
|
||||
func TestRemoteSignerCacheHit(t *testing.T) {
|
||||
priv := testKey(t)
|
||||
master := mustLocal(t, "real-hmac-key-for-test-xx")
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{})
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{}, "")
|
||||
ts := httptest.NewServer(ls.Handler())
|
||||
defer ts.Close()
|
||||
|
||||
@@ -180,7 +180,7 @@ func TestRemoteSignerCacheHit(t *testing.T) {
|
||||
func TestRemoteSignerStaleFallback(t *testing.T) {
|
||||
priv := testKey(t)
|
||||
master := mustLocal(t, "master-fallback-test-xxx")
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{})
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{}, "")
|
||||
ts := httptest.NewServer(ls.Handler())
|
||||
|
||||
tok, err := Issue(priv, "cust-fallback", TierPaid, 5, time.Hour)
|
||||
@@ -214,7 +214,7 @@ func TestRemoteSignerStaleFallback(t *testing.T) {
|
||||
func TestQuotaEnforcement(t *testing.T) {
|
||||
priv := testKey(t)
|
||||
master := mustLocal(t, "master-quota-test-xxxxxx")
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{})
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{}, "")
|
||||
ts := httptest.NewServer(ls.Handler())
|
||||
defer ts.Close()
|
||||
|
||||
@@ -260,7 +260,7 @@ func TestQuotaEnforcement(t *testing.T) {
|
||||
func TestAnonymousTrialSignsAndCaps(t *testing.T) {
|
||||
priv := testKey(t)
|
||||
master := mustLocal(t, "master-trial-test-xxxxxx")
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{})
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{}, "")
|
||||
ts := httptest.NewServer(ls.Handler())
|
||||
defer ts.Close()
|
||||
|
||||
@@ -303,7 +303,7 @@ func TestAnonymousTrialSignsAndCaps(t *testing.T) {
|
||||
func TestAnonymousTrialIPRateLimit(t *testing.T) {
|
||||
priv := testKey(t)
|
||||
master := mustLocal(t, "master-rate-test-xxxxxxx")
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{})
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{}, "")
|
||||
ts := httptest.NewServer(ls.Handler())
|
||||
defer ts.Close()
|
||||
|
||||
@@ -335,7 +335,7 @@ func TestAnonymousTrialIPRateLimit(t *testing.T) {
|
||||
func TestAuthRejectsBadBearer(t *testing.T) {
|
||||
priv := testKey(t)
|
||||
master := mustLocal(t, "master-bad-bearer-xxxxxx")
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{})
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{}, "")
|
||||
ts := httptest.NewServer(ls.Handler())
|
||||
defer ts.Close()
|
||||
|
||||
@@ -378,7 +378,7 @@ func TestRemoteSignerHardFailNoCacheReturnsError(t *testing.T) {
|
||||
func TestHeartbeatRefreshOnly(t *testing.T) {
|
||||
priv := testKey(t)
|
||||
master := mustLocal(t, "master-hb-test-xxxxxxxxxx")
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{})
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{}, "")
|
||||
ts := httptest.NewServer(ls.Handler())
|
||||
defer ts.Close()
|
||||
|
||||
@@ -461,7 +461,7 @@ func TestHeartbeatRefreshOnly(t *testing.T) {
|
||||
func TestQuotaRejectionDoesNotConsumeSlot(t *testing.T) {
|
||||
priv := testKey(t)
|
||||
master := mustLocal(t, "master-no-leak-xxxxxxxxxxxx")
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{})
|
||||
ls := NewLicenseServer(master, &priv.PublicKey, time.Minute, silentLogger{}, "")
|
||||
ts := httptest.NewServer(ls.Handler())
|
||||
defer ts.Close()
|
||||
|
||||
@@ -597,3 +597,36 @@ func TestJWTAlgLockedToRS256(t *testing.T) {
|
||||
t.Error("VerifyJWT accepted RS384; alg should be locked to RS256")
|
||||
}
|
||||
}
|
||||
|
||||
// TestQuotaTrackerPersistence: after a simulated restart (new tracker loaded
|
||||
// from the file written by the first), previously-admitted devices re-occupy
|
||||
// their slots and a new over-quota device is still rejected.
|
||||
func TestQuotaTrackerPersistence(t *testing.T) {
|
||||
path := t.TempDir() + "/quota.json"
|
||||
|
||||
// First "run": admit dev-1 and dev-2 up to cap=2.
|
||||
q1 := newQuotaTracker(5 * time.Minute)
|
||||
q1.statePath = path
|
||||
if _, ok := q1.Reserve("sub", "dev-1", 2); !ok {
|
||||
t.Fatal("dev-1 should be admitted")
|
||||
}
|
||||
if _, ok := q1.Reserve("sub", "dev-2", 2); !ok {
|
||||
t.Fatal("dev-2 should be admitted")
|
||||
}
|
||||
|
||||
// Simulate restart: new tracker loads the persisted file.
|
||||
q2 := newQuotaTracker(5 * time.Minute)
|
||||
q2.statePath = path
|
||||
if err := q2.Load(); err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
|
||||
// Restored tracker knows about dev-1 and dev-2: quota full.
|
||||
if count, ok := q2.Reserve("sub", "dev-3", 2); ok {
|
||||
t.Errorf("dev-3 should be rejected after restore, count=%d", count)
|
||||
}
|
||||
// Existing devices re-sign successfully (idempotent refresh).
|
||||
if _, ok := q2.Reserve("sub", "dev-1", 2); !ok {
|
||||
t.Error("dev-1 re-sign should succeed after restore")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user