feat(allocation_policies): per-tenant attachment via match blocks - #8393
Conversation
| def _block_matches(match: Mapping[str, Any], tenant_ids: Mapping[str, str | int]) -> bool: | ||
| return all(key in tenant_ids and tenant_ids[key] in expected for key, expected in match.items()) |
There was a problem hiding this comment.
Bug: The function _block_matches assumes match values are iterable. A scalar value (e.g., an integer) will cause an uncaught TypeError, crashing the request handler.
Severity: HIGH
Suggested Fix
Add a type check in _block_matches to ensure the expected value from the match dictionary is a list or other iterable. If it's not, either wrap it in a list to handle the scalar case gracefully or log a warning and skip the invalid policy, similar to how other malformed configuration entries are handled.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: snuba/query/allocation_policies/__init__.py#L585-L586
Potential issue: The `_block_matches` function assumes that values for keys in the
`match` dictionary of an allocation policy are always iterable. However, if a policy is
misconfigured with a scalar value (e.g., `{"organization_id": 123}`) instead of a list
(`{"organization_id": [123]}`), the expression `tenant_ids[key] in expected` will raise
a `TypeError`. This exception is not caught within the call stack
(`_resolve_policy_specs` -> `get_active_allocation_policies` ->
`_get_allocation_policies`). Since `_get_allocation_policies` is called outside the main
`try/except` block in `db_query`, this error will crash the request handler for any
query using that resource until the configuration is corrected.
Did we get this right? 👍 / 👎 to inform future reviews.
d2e969e to
c109434
Compare
0b17c2c to
4d85c49
Compare
4d85c49 to
fa4a193
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit fa4a193. Configure here.
fa4a193 to
b283a5d
Compare
b283a5d to
c23cb58
Compare
aa36ffe to
c66fdaa
Compare
| tenant_ids or {}, | ||
| resource, | ||
| ) | ||
| return _construct_policies(specs_by_name, resource) or [_default_passthough_policy(resource)] |
There was a problem hiding this comment.
Nit: get_active_allocation_policies + its four helpers (_resolve_policy_specs, _block_matches, _apply_block, _construct_policies) are a self-contained unit. What if we put them in a class or even a module, e.g. allocation_policies/resolver.py,AllocationPolicyResolver ). This init is already pretty crowded. Non-blocking ofc.
| """ | ||
|
|
||
| allocation_policies = _get_allocation_policies(clickhouse_query) | ||
| allocation_policies = _get_allocation_policies(clickhouse_query, attribution_info.tenant_ids) |
There was a problem hiding this comment.
What's the downside in just passing the attribution_info around for maximal context?
tryangul
left a comment
There was a problem hiding this comment.
Logic seems good to me 🚢
Left a nit on adding some structure. I think it's worth exploring as a follow up, esp if we want to build on this thing / swap it out later.

Stacked on #8387. Linear: EAP-726.
Summary
allocation_policyis a per-resource list of{match, policies, remove}blocks.organization_id,project_id,referrer) are always lists; AND across keys, OR within a key;match: {}always matches.removenames, then add/replace policies byname.db_querypass requesttenant_idsintoget_active_allocation_policies.required_tenant_types. Stop baking policies ontoTable; attach at quota time fromstorage_key.Testing
SNUBA_SETTINGS=test uv run pytest -q tests/query/allocation_policies/test_attachment.py tests/web/test__get_allocation_policy.py