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
| allocation policy be applied at the top level of the db_query process | ||
| """ | ||
|
|
||
| allocation_policies = _get_allocation_policies(clickhouse_query) | ||
| allocation_policies = _get_allocation_policies(clickhouse_query, attribution_info.tenant_ids) | ||
| query_id = uuid.uuid4().hex | ||
| result = None | ||
| error = None |
There was a problem hiding this comment.
Bug: The finally block in db_query accesses allocation_policies[0] without checking if the list is empty, which can cause an IndexError for queries without tables.
Severity: MEDIUM
Suggested Fix
Add a conditional check in the finally block to ensure allocation_policies is not empty before attempting to access its first element, allocation_policies[0]. The call to _record_bytes_scanned should only proceed if the list contains at least one policy.
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/web/db_query.py#L691-L697
Potential issue: In the `db_query` function, `_get_allocation_policies` can return an
empty list if the processed query contains no `Table` data sources. A `finally` block is
guaranteed to execute and calls `_record_bytes_scanned`, which unconditionally accesses
`allocation_policies[0]`. If `allocation_policies` is an empty list, this will raise an
`IndexError`, causing the request to crash. While queries without tables are considered
uncommon, they are a valid input to the query pipeline, making this a potential
production issue.
Also affects:
snuba/query/allocation_policies/__init__.py:616~689

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