refactor: deprecate int32 (#7025)

* refactor: deprecate int32

* fix(db): reject legacy user quota schemas at startup

* fix(quota): enforce wallet bounds and saturating billing conversions

* fix(rate-limit): keep count*duration from wrapping int64

* fix: error message
This commit is contained in:
Seefs
2026-08-26 20:57:54 +08:00
committed by GitHub
parent 2d8e50bf36
commit a073f74b38
35 changed files with 445 additions and 116 deletions
+3 -2
View File
@@ -4,6 +4,7 @@ import (
"math"
"testing"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/pkg/billingexpr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -344,9 +345,9 @@ func TestQuotaRound(t *testing.T) {
{999.4999, 999},
{999.5, 1000},
{1e9 + 0.5, 1e9 + 1},
// Oversized expression results saturate at int32 (delegated to
// Oversized expression results saturate at the single-request limit (delegated to
// common.QuotaRound); full saturation coverage lives in common.
{3.6893488147419103e19, math.MaxInt32},
{3.6893488147419103e19, common.MaxQuota},
}
for _, tt := range tests {
got := billingexpr.QuotaRound(tt.in)
+6 -7
View File
@@ -1,7 +1,6 @@
package billingexpr_test
import (
"math"
"testing"
"github.com/QuantumNous/new-api/common"
@@ -11,13 +10,13 @@ import (
)
// TestComputeTieredQuota_ClampOnOverflow guards the billing-safety invariant
// that an oversized tiered settlement clamps to the int32 max instead of
// that an oversized tiered settlement clamps to the single-request max instead of
// wrapping into a credit, and that the saturation event is surfaced on the
// result so callers can record it for admin auditing.
func TestComputeTieredQuota_ClampOnOverflow(t *testing.T) {
// exprOutput = p * 1e9 = 1e18; quotaBeforeGroup = 1e18 / 1e6 * 5e5 = 5e17,
// which far exceeds MaxInt32 and must saturate.
exprStr := `tier("base", p * 1000000000)`
// exprOutput = p * 1e12 = 1e21; quotaBeforeGroup = 1e21 / 1e6 * 5e5 = 5e20,
// which far exceeds the supported single-request range and must saturate.
exprStr := `tier("base", p * 1000000000000)`
snap := &billingexpr.BillingSnapshot{
BillingMode: "tiered_expr",
ExprString: exprStr,
@@ -29,10 +28,10 @@ func TestComputeTieredQuota_ClampOnOverflow(t *testing.T) {
result, err := billingexpr.ComputeTieredQuota(snap, billingexpr.TokenParams{P: 1_000_000_000})
require.NoError(t, err)
assert.Equal(t, math.MaxInt32, result.ActualQuotaAfterGroup, "oversized quota must clamp to int32 max, never wrap negative")
assert.Equal(t, common.MaxQuota, result.ActualQuotaAfterGroup, "oversized quota must clamp, never wrap negative")
require.NotNil(t, result.Clamp, "clamp event must be surfaced so it can be audited")
assert.Equal(t, common.QuotaClampOverflow, result.Clamp.Kind)
assert.Equal(t, math.MaxInt32, result.Clamp.Clamped)
assert.Equal(t, common.MaxQuota, result.Clamp.Clamped)
}
// TestComputeTieredQuota_NoClampInRange confirms an in-range settlement leaves
+1 -1
View File
@@ -68,7 +68,7 @@ type TieredResult struct {
MatchedTier string `json:"matched_tier"`
RequestRules []RequestRuleTrace `json:"request_rules,omitempty"`
CrossedTier bool `json:"crossed_tier"`
// Clamp records an int32 saturation event during quota conversion so the
// Clamp records a single-request saturation event during quota conversion so the
// caller can surface it on the consume log for admin auditing. Nil when no
// clamping occurred. Not serialized: the marker is attached separately via
// the shared quota-saturation audit path.