feat(assets): 去掉企业资产范围 256 条规则上限
逐个 IP / 域名录范围的企业很容易撞上这个上限,撞上之后只能拆成多个企业, 而范围本身并不因为条数多就更慢。 - db:删掉 MaxCompanyScopeRules 常量、请求条数校验与 ensureCompanyScopeCapacityTx(每企业持久化总数的事务内校验) - 前端:去掉 MAX_COMPANY_SCOPE_RULES 与「剩余额度」计算,追加范围弹窗不再 按剩余条数报错;demo mock 的两处上限一并移除 - 单条规则仍限 1024 字符;请求正文 2 MiB(maxCompanyMutationBodyBytes)保留 作兜底,约合四五万条规则 测试:原先断言「超容量被拒」的两个用例翻转为「超过旧上限也能写入」—— db 侧批量写 300 条 + 追加 1 条,server 侧一次创建带 300 条范围的企业。 新用例先注册清理再断言,避免断言失败把企业留在共享开发库里。
This commit is contained in:
1 parent
48e14e8cf2
commit
acd1ac29d7
7 files changed
+41
-64
No files matched your search
+4
-27
@@ -52,9 +52,9 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
// MaxCompanyScopeRules bounds both request processing and the total number
|
||||
// of persisted rules for one company.
|
||||
MaxCompanyScopeRules = 256
|
||||
// 企业范围不限制规则条数:逐个 IP / 域名录入的范围动辄上千条,封顶只会逼用户
|
||||
// 拆成多个企业。请求体大小(server 侧 maxCompanyMutationBodyBytes)仍然兜底。
|
||||
//
|
||||
// Raw and normalized textual scope payloads are bounded by Unicode rune
|
||||
// count so multi-byte input is treated consistently by the API and DB layer.
|
||||
MaxCompanyScopeRawRunes = 1024
|
||||
@@ -69,12 +69,8 @@ func (e *CompanyScopeValidationError) Error() string { return e.Message }
|
||||
|
||||
// ValidateCompanyScopeInputBounds applies request-wide limits before parsing.
|
||||
// Store methods call it again so non-HTTP callers cannot bypass the limits.
|
||||
// 只约束单条规则的长度,不限制条数。
|
||||
func ValidateCompanyScopeInputBounds(inputs []ScopeInput) error {
|
||||
if len(inputs) > MaxCompanyScopeRules {
|
||||
return &CompanyScopeValidationError{Message: fmt.Sprintf(
|
||||
"企业范围规则过多: 最多 %d 条", MaxCompanyScopeRules,
|
||||
)}
|
||||
}
|
||||
for i, input := range inputs {
|
||||
if utf8.RuneCountInString(input.Value) > MaxCompanyScopeRawRunes {
|
||||
return &CompanyScopeValidationError{Message: fmt.Sprintf(
|
||||
@@ -373,9 +369,6 @@ func (s *CompanyStore) AddScopeInputsChecked(companyID int64, inputs []ScopeInpu
|
||||
if err != nil {
|
||||
return 0, 0, invalid, errors, err
|
||||
}
|
||||
if err := ensureCompanyScopeCapacityTx(tx, companyID); err != nil {
|
||||
return 0, 0, invalid, errors, err
|
||||
}
|
||||
if needsAttribution {
|
||||
warning, err := recomputeAttributionTx(tx)
|
||||
if err != nil {
|
||||
@@ -430,19 +423,6 @@ func ensureCompanyExistsTx(tx *sql.Tx, companyID int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureCompanyScopeCapacityTx(tx *sql.Tx, companyID int64) error {
|
||||
var count int
|
||||
if err := tx.QueryRow(`SELECT count(*) FROM company_scope WHERE company_id = $1`, companyID).Scan(&count); err != nil {
|
||||
return err
|
||||
}
|
||||
if count > MaxCompanyScopeRules {
|
||||
return &CompanyScopeValidationError{Message: fmt.Sprintf(
|
||||
"企业范围规则过多: 每个企业最多 %d 条", MaxCompanyScopeRules,
|
||||
)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func lockCompanyScopeMutation(tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`SELECT pg_advisory_xact_lock($1)`, companyScopeMutationLock)
|
||||
return err
|
||||
@@ -714,9 +694,6 @@ func (s *CompanyStore) UpdateScopeInputsChecked(companyID int64, inputs []ScopeI
|
||||
if err != nil {
|
||||
return 0, invalid, errs, err
|
||||
}
|
||||
if err := ensureCompanyScopeCapacityTx(tx, companyID); err != nil {
|
||||
return 0, invalid, errs, err
|
||||
}
|
||||
// Rebuild even for an empty replacement because removing the old rules may
|
||||
// detach scope-derived assets or expose a lower-precedence company match.
|
||||
warning, err := recomputeAttributionTx(tx)
|
||||
|
||||
@@ -180,9 +180,9 @@ func TestCompanyScopeLimitsAndCheckedErrors(t *testing.T) {
|
||||
if err := ValidateCompanyScopeInputBounds([]ScopeInput{{Kind: "keyword", Value: boundary + "界"}}); !errors.As(err, &validationErr) {
|
||||
t.Fatalf("oversized raw value error=%v want CompanyScopeValidationError", err)
|
||||
}
|
||||
tooMany := make([]ScopeInput, MaxCompanyScopeRules+1)
|
||||
if err := ValidateCompanyScopeInputBounds(tooMany); !errors.As(err, &validationErr) {
|
||||
t.Fatalf("too many rules error=%v want CompanyScopeValidationError", err)
|
||||
// 条数不再设上限,只校验单条长度。
|
||||
if err := ValidateCompanyScopeInputBounds(make([]ScopeInput, 1000)); err != nil {
|
||||
t.Fatalf("rule count should be unbounded, got %v", err)
|
||||
}
|
||||
|
||||
d, _, companies := testSetup(t)
|
||||
@@ -193,24 +193,26 @@ func TestCompanyScopeLimitsAndCheckedErrors(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cleanupCompany(d, companyID)
|
||||
rules := make([]ScopeInput, MaxCompanyScopeRules)
|
||||
// 曾经封顶 256 条,逐个 IP / 域名录范围的企业很容易撞上;现在不限条数。
|
||||
const bulk = 300
|
||||
rules := make([]ScopeInput, bulk)
|
||||
for i := range rules {
|
||||
rules[i] = ScopeInput{Kind: "keyword", Value: fmt.Sprintf("limit-%d-%d", stamp, i)}
|
||||
}
|
||||
if added, _, _, _, err := companies.AddScopeInputsChecked(companyID, rules, "test"); err != nil || added != MaxCompanyScopeRules {
|
||||
t.Fatalf("fill scope capacity: added=%d err=%v", added, err)
|
||||
if added, _, _, _, err := companies.AddScopeInputsChecked(companyID, rules, "test"); err != nil || added != bulk {
|
||||
t.Fatalf("bulk scope insert: added=%d want=%d err=%v", added, bulk, err)
|
||||
}
|
||||
if added, _, _, _, err := companies.AddScopeInputsChecked(companyID, []ScopeInput{
|
||||
{Kind: "keyword", Value: fmt.Sprintf("limit-%d-overflow", stamp)},
|
||||
}, "test"); added != 0 || !errors.As(err, &validationErr) {
|
||||
t.Fatalf("scope overflow: added=%d err=%v", added, err)
|
||||
{Kind: "keyword", Value: fmt.Sprintf("limit-%d-extra", stamp)},
|
||||
}, "test"); added != 1 || err != nil {
|
||||
t.Fatalf("append past the old cap: added=%d err=%v", added, err)
|
||||
}
|
||||
var count int
|
||||
if err := d.QueryRow(`SELECT count(*) FROM company_scope WHERE company_id=$1`, companyID).Scan(&count); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if count != MaxCompanyScopeRules {
|
||||
t.Fatalf("failed capacity mutation changed scope count=%d want=%d", count, MaxCompanyScopeRules)
|
||||
if count != bulk+1 {
|
||||
t.Fatalf("scope count=%d want=%d", count, bulk+1)
|
||||
}
|
||||
|
||||
missingID := companyID + 1_000_000_000
|
||||
|
||||
Reference in new issue
Block a user