From 200224e5d6bda0ddb06466077bc6775b4413548f Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 29 Sep 2026 17:50:05 +0000 Subject: [PATCH] test(proxy): cover fail-closed team budget without membership Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../coverage_registry/quota_management.yaml | 1 + .../quota_management/budgets/budget_client.py | 3 ++ .../budgets/test_team_member_budget_e2e.py | 33 +++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/tests/e2e/coverage_registry/quota_management.yaml b/tests/e2e/coverage_registry/quota_management.yaml index 1051bf0bda9..93c493fa7b0 100644 --- a/tests/e2e/coverage_registry/quota_management.yaml +++ b/tests/e2e/coverage_registry/quota_management.yaml @@ -21,6 +21,7 @@ - {id: quota_management.budget.organization.blocks_over_limit, module: quota_management, tier: P1, behavior: budget, variant: organization, assertions: [blocks_over_limit], exercised_on: [chat_completions], source: "proxy/auth/auth_checks.py", rationale: "An organization's max_budget blocks keys under its teams"} - {id: quota_management.budget.team_member.blocks_over_limit, module: quota_management, tier: P1, behavior: budget, variant: team_member, assertions: [blocks_over_limit], exercised_on: [chat_completions], source: "proxy/auth/auth_checks.py", rationale: "A member's per-team budget blocks independently of the team budget"} - {id: quota_management.budget.team_member.isolates_per_member, module: quota_management, tier: P1, behavior: budget, variant: team_member, assertions: [isolates_per_member], exercised_on: [chat_completions], source: "proxy/auth/auth_checks.py", rationale: "One team member's exhausted per-team budget does not block a different member on the same team"} +- {id: quota_management.budget.team_member.missing_membership_counts_as_verified_zero_spend, module: quota_management, tier: P1, behavior: budget, variant: team_member, assertions: [missing_membership_counts_as_verified_zero_spend], exercised_on: [chat_completions], source: "proxy/auth/auth_checks.py + proxy_server.py:get_current_spend", rationale: "A key scoped to a team with a default member budget but no membership row treats the absent row as verified zero spend and admits the request"} - {id: quota_management.budget.model_access_group.blocks_over_limit, module: quota_management, tier: P1, behavior: budget, variant: model_access_group, assertions: [blocks_over_limit], exercised_on: [chat_completions], source: "proxy/auth/auth_checks.py", rationale: "A model access group's shared max_budget blocks further calls to deployments in the group once the pool is spent"} - {id: quota_management.budget.model_access_group.enforced_across_keys, module: quota_management, tier: P1, behavior: budget, variant: model_access_group, assertions: [enforced_across_keys], exercised_on: [chat_completions], source: "proxy/auth/auth_checks.py", rationale: "The pool is shared, so a key that spent nothing of its own is blocked once another key granted the same group drained it"} - {id: quota_management.budget.model_access_group.isolates_per_group, module: quota_management, tier: P1, behavior: budget, variant: model_access_group, assertions: [isolates_per_group], exercised_on: [chat_completions], source: "proxy/db/db_spend_update_writer.py", rationale: "A request is charged only to the granted groups that serve the model it called, so an exhausted group never blocks a sibling group"} diff --git a/tests/e2e/quota_management/budgets/budget_client.py b/tests/e2e/quota_management/budgets/budget_client.py index 087dc8ca522..78729bc8e5c 100644 --- a/tests/e2e/quota_management/budgets/budget_client.py +++ b/tests/e2e/quota_management/budgets/budget_client.py @@ -97,6 +97,7 @@ class TeamNewBody(BaseModel): max_budget: float | None = None budget_duration: str | None = None organization_id: str | None = None + team_member_budget: float | None = None budget_limits: list[BudgetWindow] | None = None @@ -416,6 +417,7 @@ class BudgetClient: max_budget: float | None = None, budget_duration: str | None = None, organization_id: str | None = None, + team_member_budget: float | None = None, budget_limits: list[BudgetWindow] | None = None, ) -> str: team_id = unwrap( @@ -427,6 +429,7 @@ class BudgetClient: max_budget=max_budget, budget_duration=budget_duration, organization_id=organization_id, + team_member_budget=team_member_budget, budget_limits=budget_limits, ), response_type=TeamNewResponse, diff --git a/tests/e2e/quota_management/budgets/test_team_member_budget_e2e.py b/tests/e2e/quota_management/budgets/test_team_member_budget_e2e.py index 0fd0a545660..aeba96a9509 100644 --- a/tests/e2e/quota_management/budgets/test_team_member_budget_e2e.py +++ b/tests/e2e/quota_management/budgets/test_team_member_budget_e2e.py @@ -61,6 +61,25 @@ def member(client: BudgetClient) -> Iterator[_Member]: resources.teardown() +@pytest.fixture(scope="class") +def member_without_membership(client: BudgetClient) -> Iterator[_Member]: + resources = ResourceManager(client=client.proxy) + try: + marker = unique_marker() + team_id = client.create_team( + alias=f"e2e-team-member-no-membership-{marker}", + team_member_budget=TEAM_BUDGET, + ) + resources.defer(lambda: client.delete_team(team_id)) + user_id = client.create_user(max_budget=TEAM_BUDGET) + resources.defer(lambda: client.delete_user(user_id)) + key = client.generate_key(team_id=team_id, user_id=user_id) + resources.defer(lambda: client.delete_key(key)) + yield _Member(team_id=team_id, user_id=user_id, key=key) + finally: + resources.teardown() + + def _send(client: BudgetClient, key: str) -> str | None: """One member call; its response id (== the spend-log request_id) if it went through, else None.""" @@ -106,3 +125,17 @@ class TestTeamMemberBudget: require_successful_call(result) time.sleep(2) pytest.fail("per-member budget never enforced within the call budget") + + +class TestFailClosedTeamMemberBudgetWithoutMembership: + @pytest.mark.covers("quota_management.budget.team_member.missing_membership_counts_as_verified_zero_spend") + def test_missing_membership_counts_as_verified_zero_spend( + self, client: BudgetClient, member_without_membership: _Member + ) -> None: + result = client.chat( + member_without_membership.key, + MODEL, + f"missing membership {unique_marker()}", + max_tokens=16, + ) + assert result.status_code == 200, result.body