wave11: weaviate-0001 UNDF-1300 (87x-1735x RBAC filter) + 2 clean-scan additions
Flagship: weaviate authorization filter slices.Contains per item (O(N*K)). Multi-tenant deployments with hundreds-thousands of permitted resources pay this on every authorized read. Set hoist: 1735x speedup at N=50k K=5k. Wave 11 honor roll: bash, coreutils. Cumulative: 49 projects.
This commit is contained in:
parent
f0e5d71181
commit
272ced7fa6
7 changed files with 359 additions and 29 deletions
55
docs/tickets/weaviate-0001-rbac-filter-allowedlist-set.md
Normal file
55
docs/tickets/weaviate-0001-rbac-filter-allowedlist-set.md
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# weaviate-0001: RBAC list-filter — O(N×K) allowedList scan per item
|
||||
|
||||
**Target:** weaviate/weaviate
|
||||
**Severity:** HIGH
|
||||
**CWE:** CWE-407 (Inefficient Algorithmic Complexity)
|
||||
**MOAD:** MOAD-0001 (A Sedimentary Defect)
|
||||
**File:** `usecases/auth/authorization/filter/filter.go:115-119`
|
||||
**Language:** Go
|
||||
**Status:** open
|
||||
|
||||
## Description
|
||||
|
||||
Weaviate's per-request RBAC filter walks every result item and calls `slices.Contains(allowedList, resourceFn(item))` to check if the user has permission. `slices.Contains` is O(K) linear scan over `allowedList`. Total per-listing cost: **O(N × K)** where N = items returned to user, K = user's permitted-resource count.
|
||||
|
||||
For tenants with many collections (1000+) and listings of many objects (10k+), per-request cost reaches 10M membership checks. Authorization sits on every read path; this is a hot bottleneck.
|
||||
|
||||
## Root Cause
|
||||
|
||||
```go
|
||||
// usecases/auth/authorization/filter/filter.go:115
|
||||
for _, item := range items {
|
||||
if slices.Contains(allowedList, resourceFn(item)) { // O(K) per call
|
||||
filtered = append(filtered, item)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`slices.Contains` is a linear scan. Across N items: O(N × K).
|
||||
|
||||
## Fix
|
||||
|
||||
Hoist `allowedList` into a `map[string]struct{}{}` once before iterating items. Per-iter cost drops to O(1).
|
||||
|
||||
```go
|
||||
allowedSet := make(map[string]struct{}, len(allowedList))
|
||||
for _, r := range allowedList {
|
||||
allowedSet[r] = struct{}{}
|
||||
}
|
||||
for _, item := range items {
|
||||
if _, ok := allowedSet[resourceFn(item)]; ok {
|
||||
filtered = append(filtered, item)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Total cost drops from O(N × K) to O(N + K). The set-build cost (O(K)) amortizes over the N-item walk.
|
||||
|
||||
## Severity Note
|
||||
|
||||
Hot path on every authorized list/search request. Multi-tenant Weaviate deployments with hundreds-to-thousands of collections per principal pay this on every read. Bench (defects/weaviate/bench/) confirms 87× speedup at N=1000 K=200 and 1735× at N=50k K=5k.
|
||||
|
||||
## Complexity Gate
|
||||
|
||||
- N=10,000 items × K=1000 allowed: fixed must complete in <50ms
|
||||
- k-scaling 5×: time ratio must be <17.5×
|
||||
Loading…
Add table
Add a link
Reference in a new issue