Skip to content

Commit b4f5bfb

Browse files
committed
Trim comments and docstrings to the essentials
Cut the comment and docstring volume of the new tests by half: docstring first lines are single short sentences, narration and restating-the-code comments are gone, and surviving comments carry only what the code cannot say - provenance labels, the divergence re-pin instructions, and the non-obvious traps (coverage branch quirks, opaque-state shape). No code or assertion changes: every file parses identically with docstrings stripped.
1 parent 011bbd5 commit b4f5bfb

25 files changed

Lines changed: 399 additions & 1151 deletions

tests/interaction/auth/_harness.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -133,22 +133,16 @@ class HeadlessOAuth:
133133
request does not re-enter the locked auth flow), parses `code` and `state` from the 302
134134
`Location`, and stashes them; `callback_handler` returns the stashed pair. Tests inspect
135135
`authorize_url` to assert what the SDK put on the authorize request, and `iss`/`error` to
136-
assert what the redirect carried — both record the redirect regardless of the
137-
callback-boundary levers below.
136+
assert what the redirect carried.
138137
139138
`state_override`: when set, `callback_handler` returns this value as the state instead of
140139
the one parsed from the redirect, so tests can drive the state-mismatch path.
141140
142141
`iss_override`: when set, `callback_handler` returns this value as the RFC 9207 issuer
143142
instead of the one parsed from the redirect, so tests can drive the iss-mismatch path.
144143
145-
`code_override`: when set, `callback_handler` returns this value as the authorization code
146-
instead of the one parsed from the redirect, so tests can drive the token-endpoint
147-
rejection path.
148-
149-
`omit_iss`: when set, `callback_handler` returns no iss regardless of what the redirect
150-
carried or what `iss_override` supplies (omission wins when both are set), so tests can
151-
drive the missing-iss paths (the `iss_override` sentinel cannot express absence).
144+
`code_override`: when set, returned as the code instead of the parsed one (token-endpoint rejection path).
145+
`omit_iss`: when set, no iss is returned, overriding everything (`iss_override` cannot express absence).
152146
"""
153147

154148
def __init__(
@@ -341,9 +335,7 @@ def step_up_shim(www_authenticate: str, *, on_nth_authenticated_post: int = 2, p
341335
after the 401 branch, where the generator ends without inspecting the response), so a 403
342336
there would not reach the step-up handler.
343337
344-
`persist`: when set, every authenticated POST from the Nth onward receives the 403 challenge
345-
instead of only the Nth, so tests can drive a further `insufficient_scope` challenge on the
346-
request retried after a step-up.
338+
`persist`: when set, 403s every authenticated POST from the Nth onward, re-challenging the step-up retry.
347339
"""
348340
seen = 0
349341
fired = False

tests/interaction/auth/_provider.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,8 @@ class InMemoryAuthorizationServerProvider(
4949
`fail_next_refresh`: the next refresh-token exchange raises `invalid_grant` once.
5050
`reject_all_tokens`: `load_access_token` returns None for every token, so the bearer
5151
middleware 401s every authenticated request.
52-
`rotate_refresh_tokens`: when False, the refresh exchange issues only a new access
53-
token (the response carries no `refresh_token` and the presented one stays valid),
54-
modelling an RFC 6749 §6 non-rotating authorization server.
52+
`rotate_refresh_tokens`: when False, the refresh response carries no `refresh_token` and
53+
the presented one stays valid (an RFC 6749 §6 non-rotating server).
5554
"""
5655

5756
def __init__(
@@ -183,11 +182,7 @@ async def load_refresh_token(self, client: OAuthClientInformationFull, refresh_t
183182
async def exchange_refresh_token(
184183
self, client: OAuthClientInformationFull, refresh_token: RefreshToken, scopes: list[str]
185184
) -> OAuthToken:
186-
"""Mint a new access token and rotate the refresh token, consuming the old one.
187-
188-
Unless `rotate_refresh_tokens` is off: then only a new access token is minted, the
189-
response carries no `refresh_token`, and the presented one stays valid.
190-
"""
185+
"""Mint a new access token, and rotate the refresh token unless rotation is disabled."""
191186
assert client.client_id is not None
192187
if self._fail_next_refresh:
193188
self._fail_next_refresh = False

tests/interaction/auth/test_as_handlers.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -307,14 +307,7 @@ async def test_register_echoes_native_for_a_client_that_registered_application_t
307307
) -> None:
308308
"""A client registering `application_type: "web"` is told `"native"` in the registration echo.
309309
310-
Pins the known gap recorded on the requirement (divergence): the registration handler's
311-
field-by-field passthrough omits `application_type`, so the model default fills the echo
312-
where RFC 7591 §3.2.1 requires the registered value -- and the SDK OAuth client adopts the
313-
echo into persisted storage, so the corruption is client-visible end to end. When the
314-
one-line passthrough fix lands this test fails: re-pin the echo to `"web"`, delete the
315-
Divergence, and add the echo assertion to
316-
`test_dcr_sends_a_consumer_set_application_type_verbatim` (test_flow.py) per the
317-
requirement's note.
310+
When the passthrough fix lands: re-pin the echo to `"web"` and delete the Divergence.
318311
"""
319312
http, _ = as_app
320313
metadata = OAuthClientMetadata(
@@ -323,10 +316,8 @@ async def test_register_echoes_native_for_a_client_that_registered_application_t
323316

324317
response = await http.post("/register", content=metadata.model_dump_json())
325318

326-
# Registration itself succeeds: the divergence is in the echo, not in acceptance.
327319
assert response.status_code == 201
328320
body = response.json()
329-
# The request carried "web" (the metadata above); the echo says "native" -- the pinned gap.
330321
assert body["application_type"] == "native"
331322
# The omission is specific to application_type, not a generally lossy echo.
332323
assert body["client_name"] == "interaction-suite"

tests/interaction/auth/test_authorize_token.py

Lines changed: 18 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,8 @@ async def test_a_mismatched_iss_on_the_callback_aborts_the_flow() -> None:
193193
"""A callback whose RFC 9207 iss does not match the authorization server issuer aborts the flow.
194194
195195
`iss_override` makes the headless callback return an issuer the AS never advertised; the SDK
196-
compares it to `oauth_metadata.issuer` and raises `OAuthFlowError` before the token exchange --
197-
the recorded traffic shows no /token POST, so the tainted authorization code is never exchanged.
198-
Also pins the mismatch arm of `client-auth:iss:unadvertised-present-validated`: the served AS
199-
metadata never advertises `authorization_response_iss_parameter_supported`, so this rejection is
200-
RFC 9207 validation table row 3 -- a present iss is validated regardless of advertisement.
196+
compares it to `oauth_metadata.issuer` and raises `OAuthFlowError` before the token exchange.
197+
Also the row-3 mismatch arm: a present iss is validated even though the AS never advertises iss support.
201198
"""
202199
recorded, on_request = record_requests()
203200
provider = InMemoryAuthorizationServerProvider()
@@ -431,13 +428,8 @@ async def test_an_authorize_error_on_the_callback_aborts_the_flow_before_the_tok
431428
async def test_a_token_endpoint_error_response_aborts_the_flow_without_a_bearer_request() -> None:
432429
"""A token-endpoint error response aborts the flow as `OAuthTokenError`, and no bearer is ever sent.
433430
434-
SDK-defined surfacing (no spec mandate governs client-side token-error handling):
435-
`code_override` forges the authorization code at the callback boundary, so the SDK's own
436-
token handler produces a genuine RFC 6749 `invalid_grant` 400 -- no shim anywhere. The
437-
matched message pins only the SDK-authored prefix naming the HTTP status; the tail is the
438-
server handler's JSON, and the absent machine-readable code is the deferred
439-
`client-auth:token-error:machine-readable-code`. The recorded traffic proves the failed
440-
exchange was not retried and no request ever carried a bearer token.
431+
SDK-defined behaviour. The match pins only the SDK-authored status prefix; the missing
432+
machine-readable error code is the deferred `client-auth:token-error:machine-readable-code`.
441433
"""
442434
recorded, on_request = record_requests()
443435
provider = InMemoryAuthorizationServerProvider()
@@ -450,21 +442,16 @@ async def test_a_token_endpoint_error_response_aborts_the_flow_without_a_bearer_
450442
):
451443
await connect_with_oauth(server, provider=provider, headless=headless, on_request=on_request).__aenter__()
452444

453-
# The flow genuinely reached the token step via a real authorize round trip...
445+
# Guards that the failure happened at the token step, not earlier in the flow.
454446
assert find(recorded, "GET", "/authorize") != []
455-
# ...the failed exchange was not retried (no loop)...
456447
assert len(find(recorded, "POST", "/token")) == 1
457-
# ...and no request ever carried a bearer: the failure pre-empted token use entirely.
458448
assert all("authorization" not in r.headers for r in find(recorded, "POST", "/mcp"))
459449

460450

461451
def canned_asm(*, iss_advertised: bool | None) -> dict[str, bytes]:
462-
"""Build a `serve=` override: canned AS metadata with a slash-explicit issuer literal.
452+
"""Build a `serve=` override: canned AS metadata pinning the iss-advertisement arm.
463453
464-
The SDK server's `build_metadata` never sets `authorization_response_iss_parameter_supported`,
465-
so the advertising arms of the RFC 9207 validation table need this override; `None` omits the
466-
field (`exclude_none`), keeping the document an unadvertising AS whose issuer bytes are still
467-
harness-pinned.
454+
Needed because the SDK server's `build_metadata` never advertises iss support; `None` omits the field.
468455
"""
469456
override = OAuthMetadata(
470457
issuer=AnyHttpUrl(f"{BASE_URL}/"),
@@ -483,13 +470,8 @@ def canned_asm(*, iss_advertised: bool | None) -> dict[str, bytes]:
483470
async def test_a_matching_iss_lets_the_flow_redeem_the_code_when_the_as_advertises_iss_support() -> None:
484471
"""A callback iss equal to the recorded metadata issuer proceeds to redeem the code (RFC 9207 table row 1).
485472
486-
Spec-mandated: advertised support + present matching iss -> compare and proceed. The shim
487-
serves AS metadata advertising `authorization_response_iss_parameter_supported`; the suite's
488-
provider stamps the matching iss on the success redirect. `headless.iss` proves the callback
489-
really carried the recorded issuer (completion alone could also mean the value was never
490-
looked at -- the rejection arms of the family are the discriminators). Whether the SDK
491-
consulted the advertisement flag is not asserted: rows 1 and 3 share one unconditional
492-
comparison branch, so the flag's effect is only observable on the absent-iss arms.
473+
Spec-mandated. `headless.iss` proves the callback really carried the issuer; whether the SDK
474+
consulted the advertisement flag is only observable on the absent-iss arms, so it is not asserted.
493475
"""
494476
recorded, on_request = record_requests()
495477
provider = InMemoryAuthorizationServerProvider()
@@ -509,7 +491,6 @@ async def test_a_matching_iss_lets_the_flow_redeem_the_code_when_the_as_advertis
509491
assert result.tools[0].name == "echo"
510492
assert storage.tokens is not None
511493
assert headless.iss == f"{BASE_URL}/"
512-
# One authorize and one token exchange: the flow proceeded directly, no rejection/retry loop.
513494
assert len(find(recorded, "GET", "/authorize")) == 1
514495
assert len(find(recorded, "POST", "/token")) == 1
515496

@@ -518,14 +499,8 @@ async def test_a_matching_iss_lets_the_flow_redeem_the_code_when_the_as_advertis
518499
async def test_an_iss_differing_only_by_a_trailing_slash_is_rejected_without_normalization() -> None:
519500
"""An iss equal to the recorded issuer up to a trailing slash is a mismatch: nothing is normalized away.
520501
521-
Spec-mandated: the comparison is RFC 9207 simple string comparison, and the client MUST NOT
522-
apply scheme or host case folding, default-port elision, trailing-slash, or percent-encoding
523-
normalization before comparing; the trailing-slash arm is pinned as the representative class
524-
(the SDK's comparison is a single string inequality). Both spellings are harness literals:
525-
the canned metadata carries the slash-explicit issuer and the provider stamps the slash-less
526-
redirect iss. Natural metadata would instead source the slash from the SDK server's issuer
527-
serialization -- the load-bearing, churn-prone arm of that difference -- whereas the client's
528-
metadata parse preserves the served bytes and contributes nothing to it.
502+
Spec-mandated: RFC 9207 simple string comparison with no normalization; the trailing-slash
503+
arm is pinned as the representative class (the SDK's comparison is a single string inequality).
529504
"""
530505
recorded, on_request = record_requests()
531506
provider = InMemoryAuthorizationServerProvider(issuer=BASE_URL)
@@ -550,10 +525,7 @@ async def test_an_iss_differing_only_by_a_trailing_slash_is_rejected_without_nor
550525
async def test_a_missing_iss_is_rejected_when_the_as_advertises_iss_support() -> None:
551526
"""A callback without iss is rejected before the code is redeemed when the AS advertises iss support (row 2).
552527
553-
Spec-mandated: advertised support + absent iss -> reject. The SDK's whole authorization-response
554-
input is the callback's `AuthorizationCodeResult`, so the absence is constructed at that boundary
555-
with `omit_iss` (the suite's AS emits iss on every success redirect; the redirect itself is
556-
unchanged). No /token POST is recorded -- the authorization code is never exchanged.
528+
Spec-mandated. The callback is the SDK's whole authorization-response input, so `omit_iss` removes iss there.
557529
"""
558530
recorded, on_request = record_requests()
559531
provider = InMemoryAuthorizationServerProvider()
@@ -584,11 +556,8 @@ async def test_a_missing_iss_is_rejected_when_the_as_advertises_iss_support() ->
584556
async def test_a_missing_iss_is_tolerated_when_the_as_does_not_advertise_iss_support() -> None:
585557
"""A callback without iss proceeds with the code exchange when the AS does not advertise iss support (row 4).
586558
587-
Spec-mandated: no advertisement + absent iss -> proceed. The SDK server's `build_metadata`
588-
never sets `authorization_response_iss_parameter_supported`, so the natural metadata route IS
589-
the unadvertising AS; if it ever started advertising, this test would fail loudly (absent iss
590-
+ advertised -> the row-2 reject), so the precondition cannot silently rot. The absent iss is
591-
constructed at the callback boundary with `omit_iss`.
559+
Spec-mandated. Natural metadata is already the unadvertising arm; if the SDK server ever
560+
started advertising, absent iss would hit the row-2 reject, so the precondition cannot rot.
592561
"""
593562
recorded, on_request = record_requests()
594563
provider = InMemoryAuthorizationServerProvider()
@@ -604,20 +573,15 @@ async def test_a_missing_iss_is_tolerated_when_the_as_does_not_advertise_iss_sup
604573

605574
assert result.tools[0].name == "echo"
606575
assert storage.tokens is not None
607-
# Exactly one token exchange: the flow proceeded directly, no rejection/retry detour.
608576
assert len(find(recorded, "POST", "/token")) == 1
609577

610578

611579
@requirement("client-auth:iss:unadvertised-present-validated")
612580
async def test_a_present_iss_is_validated_and_accepted_even_when_the_as_does_not_advertise_support() -> None:
613581
"""A present iss is compared against the recorded issuer even without metadata advertisement (row 3, match arm).
614582
615-
Spec-mandated, and the point where the MCP spec deliberately exceeds RFC 9207's local-policy
616-
provision: a present iss is validated regardless of advertisement. The natural AS metadata is
617-
the unadvertising AS and the provider stamps the matching iss; `headless.iss` proves it was
618-
present on the callback. The match arm alone cannot prove the comparison ran -- the same
619-
entry's mismatch arm is pinned by `test_a_mismatched_iss_on_the_callback_aborts_the_flow`,
620-
which drives a mismatched iss against the same unadvertising AS.
583+
Spec-mandated; MCP exceeds RFC 9207's local-policy provision here. The mismatch arm is pinned
584+
by `test_a_mismatched_iss_on_the_callback_aborts_the_flow`.
621585
"""
622586
recorded, on_request = record_requests()
623587
provider = InMemoryAuthorizationServerProvider()
@@ -641,14 +605,8 @@ async def test_a_present_iss_is_validated_and_accepted_even_when_the_as_does_not
641605
async def test_an_error_redirect_with_a_mismatched_iss_is_rejected_on_iss_before_the_missing_code_error() -> None:
642606
"""iss validation applies equally to error responses: the mismatch is raised before the missing-code error.
643607
644-
Spec-mandated at 2026-07-28 (SEP-2468): the AS denies the authorize request, producing a real
645-
RFC 6749 error redirect (`error=access_denied`, no code, no iss), and `iss_override` supplies
646-
the mismatching issuer at the callback boundary -- the SDK never parses a callback URL, so its
647-
whole authorization-response input is the callback's `AuthorizationCodeResult`. Raising the
648-
iss mismatch in preference to "No authorization code received" (the arm the error-surfaces
649-
test above pins) is the observable proving the validation ran on an error response. The
650-
MUST-NOT-act-on-or-display half is not asserted: the callback contract carries no error
651-
fields, so the negative would be vacuously true by construction (the manifest note records it).
608+
Spec-mandated at 2026-07-28 (SEP-2468). The mismatch pre-empting the missing-code error proves
609+
validation ran; the MUST-NOT-act-on half is vacuous (no error fields in the callback contract).
652610
"""
653611
recorded, on_request = record_requests()
654612
provider = InMemoryAuthorizationServerProvider(deny_authorize=True)
@@ -661,7 +619,6 @@ async def test_an_error_redirect_with_a_mismatched_iss_is_rejected_on_iss_before
661619
):
662620
await connect_with_oauth(server, provider=provider, headless=headless, on_request=on_request).__aenter__()
663621

664-
# The callback genuinely was an error response, and the tainted exchange never started.
665622
assert headless.error == "access_denied"
666623
# The recorded unauthenticated trigger POST guards the negative below against an unwired hook.
667624
assert find(recorded, "POST", "/mcp") != []

tests/interaction/auth/test_bearer.py

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -158,16 +158,11 @@ async def test_a_token_missing_a_required_scope_is_answered_403_insufficient_sco
158158

159159
@requirement("hosting:auth:scope-403:all-scopes")
160160
async def test_a_token_missing_two_required_scopes_is_challenged_with_only_the_first() -> None:
161-
"""A token missing both required scopes is challenged for one scope per round trip.
162-
163-
The spec says servers SHOULD include all scopes required for the current operation in a
164-
single challenge; the bearer middleware instead checks required scopes in order and 403s on
165-
the first missing one, naming only that scope in `error_description` (and emitting no
166-
`scope` parameter at all -- the sibling `hosting:auth:scope-403` divergence). Pins the known
167-
gap recorded on the requirement (divergence); when the middleware aggregates, this test
168-
fails -- re-pin to a challenge naming both scopes and delete the Divergence. The two-scope
169-
app is built inline: the file's `protected` fixture is single-scope, and a two-scope deficit
170-
is this entry's distinct observable.
161+
"""A token missing both required scopes is challenged for only the first missing scope.
162+
163+
Pins the recorded divergence: the middleware checks required scopes in order and names
164+
only the first missing one, where the spec wants all of them in a single challenge.
165+
When the middleware aggregates: re-pin to a challenge naming both scopes and delete the Divergence.
171166
"""
172167
settings = auth_settings(required_scopes=["mcp:read", "mcp:write"])
173168
verifier = StaticTokenVerifier(
@@ -178,8 +173,6 @@ async def test_a_token_missing_two_required_scopes_is_challenged_with_only_the_f
178173
response = await post_mcp(http, bearer="tok-zeroscope")
179174

180175
assert response.status_code == 403
181-
# Full-dict equality: only the FIRST missing scope (registration order) is named, and no
182-
# `scope` key appears.
183176
assert parse_www_authenticate(response.headers["www-authenticate"]) == {
184177
"error": "insufficient_scope",
185178
"error_description": "Required scope: mcp:read",

0 commit comments

Comments
 (0)