Repository: nats-io/nsc
Pull request #527 (2022-12-06 21:56:39)

[fix] Tiered limits validation from blocking legitimate updates
The new tiered limits feature added in #517 causes a validation failure
when a tier is set and a non-limits based flag is passed to update an
account.

This was discovered when trying to add a signing key to a fresh NGS
account.



Patch:
diff --git a/cmd/editaccount.go b/cmd/editaccount.go
index e6b13c1..92d8c4d 100644
--- a/cmd/editaccount.go
+++ b/cmd/editaccount.go
@@ -139,6 +139,7 @@ type JetStreamLimitParams struct {
 	DiskMaxStreamBytes NumberParams
 	MaxBytesRequired   bool
 	MaxAckPending      NumberParams
+	hasJSSetParams     bool
 }
 
 type EditAccountParams struct {
@@ -172,7 +173,7 @@ func (p *EditAccountParams) SetDefaults(ctx ActionCtx) error {
 	p.SignerParams.SetDefaults(nkeys.PrefixByteOperator, true, ctx)
 
 	hasDeleteTier := ctx.AnySet("rm-js-tier")
-	hasJsSetFlags := ctx.AnySet("js-tier", "js-mem-storage",
+	p.hasJSSetParams = ctx.AnySet("js-tier", "js-mem-storage",
 		"js-disk-storage",
 		"js-streams",
 		"js-consumer",
@@ -181,7 +182,7 @@ func (p *EditAccountParams) SetDefaults(ctx ActionCtx) error {
 		"js-max-bytes-required",
 		"js-max-ack-pending")
 
-	if hasDeleteTier && hasJsSetFlags {
+	if hasDeleteTier && p.hasJSSetParams {
 		return fmt.Errorf("rm-js-tier is exclusive of all other js options")
 	}
 
@@ -305,12 +306,12 @@ func (p *EditAccountParams) validJsLimitConfig() error {
 	if tiered > 0 && globalIsSet {
 		return fmt.Errorf("configuration cannot contain both global and tiered limits '%s' - please use the --rm-js-tier to remove undesired tier(s)", strings.Join(keys, ","))
 	}
-	// trying to add global to tiered
-	if tiered > 0 && p.Tier == 0 {
+	// trying to add global to tiered (only if js set params have been passed)
+	if tiered > 0 && p.Tier == 0 && p.hasJSSetParams {
 		return fmt.Errorf("cannot set a jetstream global limit when a configuration has tiered limits '%s'", strings.Join(keys, ","))
 	}
 	// trying to add tiered to global
-	if globalIsSet && p.Tier > 0 {
+	if globalIsSet && p.Tier > 0 && p.hasJSSetParams {
 		return errors.New("cannot set a jetstream tier limit when a configuration has a global limit")
 	}
 	return nil


Test patch:
diff --git a/cmd/editaccount_test.go b/cmd/editaccount_test.go
index 609f5c6..8b1c2a9 100644
--- a/cmd/editaccount_test.go
+++ b/cmd/editaccount_test.go
@@ -205,6 +205,24 @@ func Test_TieredPreventsGlobal(t *testing.T) {
 	require.Equal(t, "cannot set a jetstream global limit when a configuration has tiered limits 'R2'", err.Error())
 }
 
+func Test_TieredDoesntPreventOtherClaims(t *testing.T) {
+	ts := NewTestStore(t, "edit account")
+	defer ts.Done(t)
+
+	ts.AddAccount(t, "A")
+	_, _, err := ExecuteCmd(createEditAccount(),
+		"--js-tier", "2", "--js-streams", "5", "--js-disk-storage", "10")
+	require.NoError(t, err)
+
+	ac, err := ts.Store.ReadAccountClaim("A")
+	require.NoError(t, err)
+	require.Equal(t, int64(5), ac.Limits.JetStreamTieredLimits["R2"].Streams)
+
+	_, _, err = ExecuteCmd(createEditAccount(),
+		"--sk", "generate")
+	require.NoError(t, err)
+}
+
 func Test_EditAccountSigningKeys(t *testing.T) {
 	ts := NewTestStore(t, "edit account")
 	defer ts.Done(t)