test(mcp): align JWT registry ids with the MCP grammar and add a cold inactive-user case
Some checks failed
LiteLLM Rust / rust-lint (push) Has been cancelled
LiteLLM Rust / rust-test (push) Has been cancelled
LiteLLM Rust / rust-wheel (push) Has been cancelled
Terraform Modules / fmt, validate, test (aws) (push) Has been cancelled
Terraform Modules / fmt, validate, test (gcp) (push) Has been cancelled
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled

Co-Authored-By: bot_apk <apk@cognition.ai>
This commit is contained in:
Devin AI 2026-09-24 06:59:21 +00:00
parent e8e4b09fae
commit 1c92361284
3 changed files with 60 additions and 37 deletions

View file

@ -182,6 +182,8 @@ mcp.<operation>.<auth_family>.<assertion>
operation : list_tools | call_tool | list_resources | read_resource | list_prompts | get_prompt
auth_family : none | api_key | bearer | oauth
assertion : succeeds | denied_without_permission | persists_across_processes
| access_group_scoped | toolset_scoped | scoped | denied_invalid_signature
| denied_expired | denied_inactive_user | explicit_header_precedence
e.g. mcp.call_tool.oauth.succeeds
```

View file

@ -136,92 +136,92 @@
source: "user_api_key_auth_mcp.py:2137"
rationale: "A key granted a toolset lists exactly the toolset's tools: the rest of the server's catalog stays hidden and every stored name resolves"
- id: mcp.list_tools.bearer.jwt_valid_scoped
- id: mcp.list_tools.bearer.scoped
module: mcp
tier: P0
operation: list_tools
auth_family: bearer
assertions: [valid_scoped]
source: "test_mcp_jwt_auth_e2e.py"
assertions: [scoped]
source: "user_api_key_auth.py"
rationale: "LIT-4506 preserves scoped gateway JWT admission independently of upstream credentials"
- id: mcp.call_tool.bearer.jwt_valid_scoped
- id: mcp.call_tool.bearer.scoped
module: mcp
tier: P0
operation: call_tool
auth_family: bearer
assertions: [valid_scoped]
source: "test_mcp_jwt_auth_e2e.py"
assertions: [scoped]
source: "user_api_key_auth.py"
rationale: "LIT-4506 preserves scoped gateway JWT admission independently of upstream credentials"
- id: mcp.list_tools.bearer.jwt_invalid_signature_denied
- id: mcp.list_tools.bearer.denied_invalid_signature
module: mcp
tier: P0
operation: list_tools
auth_family: bearer
assertions: [invalid_signature_denied]
source: "test_mcp_jwt_auth_e2e.py"
assertions: [denied_invalid_signature]
source: "user_api_key_auth.py"
rationale: "LIT-4506 preserves scoped gateway JWT admission independently of upstream credentials"
- id: mcp.call_tool.bearer.jwt_invalid_signature_denied
- id: mcp.call_tool.bearer.denied_invalid_signature
module: mcp
tier: P0
operation: call_tool
auth_family: bearer
assertions: [invalid_signature_denied]
source: "test_mcp_jwt_auth_e2e.py"
assertions: [denied_invalid_signature]
source: "user_api_key_auth.py"
rationale: "LIT-4506 preserves scoped gateway JWT admission independently of upstream credentials"
- id: mcp.list_tools.bearer.jwt_expired_denied
- id: mcp.list_tools.bearer.denied_expired
module: mcp
tier: P0
operation: list_tools
auth_family: bearer
assertions: [expired_denied]
source: "test_mcp_jwt_auth_e2e.py"
assertions: [denied_expired]
source: "user_api_key_auth.py"
rationale: "LIT-4506 preserves scoped gateway JWT admission independently of upstream credentials"
- id: mcp.call_tool.bearer.jwt_expired_denied
- id: mcp.call_tool.bearer.denied_expired
module: mcp
tier: P0
operation: call_tool
auth_family: bearer
assertions: [expired_denied]
source: "test_mcp_jwt_auth_e2e.py"
assertions: [denied_expired]
source: "user_api_key_auth.py"
rationale: "LIT-4506 preserves scoped gateway JWT admission independently of upstream credentials"
- id: mcp.list_tools.bearer.jwt_inactive_user_denied
- id: mcp.list_tools.bearer.denied_inactive_user
module: mcp
tier: P0
operation: list_tools
auth_family: bearer
assertions: [inactive_user_denied]
source: "test_mcp_jwt_auth_e2e.py"
assertions: [denied_inactive_user]
source: "user_api_key_auth.py:1722"
rationale: "LIT-4506 preserves scoped gateway JWT admission independently of upstream credentials"
- id: mcp.call_tool.bearer.jwt_inactive_user_denied
- id: mcp.call_tool.bearer.denied_inactive_user
module: mcp
tier: P0
operation: call_tool
auth_family: bearer
assertions: [inactive_user_denied]
source: "test_mcp_jwt_auth_e2e.py"
assertions: [denied_inactive_user]
source: "user_api_key_auth.py:1722"
rationale: "LIT-4506 preserves scoped gateway JWT admission independently of upstream credentials"
- id: mcp.list_tools.bearer.jwt_header_precedence
- id: mcp.list_tools.bearer.explicit_header_precedence
module: mcp
tier: P0
operation: list_tools
auth_family: bearer
assertions: [header_precedence]
source: "test_mcp_jwt_auth_e2e.py"
assertions: [explicit_header_precedence]
source: "user_api_key_auth.py"
rationale: "LIT-4506 preserves scoped gateway JWT admission independently of upstream credentials"
- id: mcp.call_tool.bearer.jwt_header_precedence
- id: mcp.call_tool.bearer.explicit_header_precedence
module: mcp
tier: P0
operation: call_tool
auth_family: bearer
assertions: [header_precedence]
source: "test_mcp_jwt_auth_e2e.py"
assertions: [explicit_header_precedence]
source: "user_api_key_auth.py"
rationale: "LIT-4506 preserves scoped gateway JWT admission independently of upstream credentials"

View file

@ -86,7 +86,7 @@ def granted_mcp(client: McpClient, resources: ResourceManager, jwt_identity: Ide
class TestMcpGatewayJwt:
@pytest.mark.covers("mcp.list_tools.bearer.jwt_valid_scoped", "mcp.call_tool.bearer.jwt_valid_scoped")
@pytest.mark.covers("mcp.list_tools.bearer.scoped", "mcp.call_tool.bearer.scoped")
@pytest.mark.parametrize("header", ("authorization", "x_litellm_api_key"))
def test_valid_scoped_jwt_lists_and_calls(
self, client: McpClient, granted_mcp: GrantedMcp, header: Literal["authorization", "x_litellm_api_key"]
@ -99,7 +99,7 @@ class TestMcpGatewayJwt:
_allowed(client, granted_mcp, headers)
@pytest.mark.covers(
"mcp.list_tools.bearer.jwt_invalid_signature_denied", "mcp.call_tool.bearer.jwt_invalid_signature_denied"
"mcp.list_tools.bearer.denied_invalid_signature", "mcp.call_tool.bearer.denied_invalid_signature"
)
def test_tampered_signature_denies_both_operations(self, client: McpClient, granted_mcp: GrantedMcp) -> None:
valid: Final = AuthHeaders(authorization=f"Bearer {granted_mcp.token}")
@ -110,7 +110,7 @@ class TestMcpGatewayJwt:
_denied(client, granted_mcp, AuthHeaders(authorization=f"Bearer {tampered}"), "signature")
_allowed(client, granted_mcp, valid)
@pytest.mark.covers("mcp.list_tools.bearer.jwt_expired_denied", "mcp.call_tool.bearer.jwt_expired_denied")
@pytest.mark.covers("mcp.list_tools.bearer.denied_expired", "mcp.call_tool.bearer.denied_expired")
def test_expired_signed_jwt_denies_both_operations(
self, client: McpClient, granted_mcp: GrantedMcp, jwt_identity: Identity, idp: Keycloak
) -> None:
@ -125,9 +125,7 @@ class TestMcpGatewayJwt:
_denied(client, granted_mcp, AuthHeaders(authorization=f"Bearer {expiring}"), "expired")
_allowed(client, granted_mcp, valid)
@pytest.mark.covers(
"mcp.list_tools.bearer.jwt_inactive_user_denied", "mcp.call_tool.bearer.jwt_inactive_user_denied"
)
@pytest.mark.covers("mcp.list_tools.bearer.denied_inactive_user", "mcp.call_tool.bearer.denied_inactive_user")
def test_deactivated_user_cannot_reuse_warm_jwt(
self, client: McpClient, granted_mcp: GrantedMcp, jwt_identity: Identity
) -> None:
@ -149,7 +147,30 @@ class TestMcpGatewayJwt:
)
_allowed(client, granted_mcp, headers)
@pytest.mark.covers("mcp.list_tools.bearer.jwt_header_precedence", "mcp.call_tool.bearer.jwt_header_precedence")
@pytest.mark.covers("mcp.list_tools.bearer.denied_inactive_user", "mcp.call_tool.bearer.denied_inactive_user")
def test_deactivated_user_is_denied_on_a_cold_jwt(
self, client: McpClient, granted_mcp: GrantedMcp, jwt_identity: Identity, idp: Keycloak
) -> None:
management: Final = build_management_client(client.proxy)
management.update_user(
UserUpdateBody(
user_id=jwt_identity.user_id, user_role="internal_user", metadata=UserScimMetadata(scim_active=False)
)
)
cold: Final = idp.access_token(jwt_identity)
assert cold != granted_mcp.token
access: Final = GrantedMcp(granted_mcp.server_id, granted_mcp.other_server_id, granted_mcp.tool, cold)
_denied(client, access, AuthHeaders(authorization=f"Bearer {cold}"), "deactivated")
management.update_user(
UserUpdateBody(
user_id=jwt_identity.user_id, user_role="internal_user", metadata=UserScimMetadata(scim_active=True)
)
)
_allowed(client, access, AuthHeaders(authorization=f"Bearer {cold}"))
@pytest.mark.covers(
"mcp.list_tools.bearer.explicit_header_precedence", "mcp.call_tool.bearer.explicit_header_precedence"
)
def test_explicit_gateway_header_wins_without_fallback(
self, client: McpClient, granted_mcp: GrantedMcp, resources: ResourceManager
) -> None: