| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
… branch CI cloned github.com/AuthPlane/conformance at its default branch, so any change to the catalog reached this repo immediately — a case added there could turn an unrelated PR red here with nothing in this repo having changed. Pinning decouples them: a catalog change arrives only when this repo deliberately bumps the pin together with the coverage for it. The revision is single-sourced in a tracked .conformance-catalog-ref, guarded by a 40-hex shape check before the fetch so a branch or tag name cannot silently un-pin CI, and read by both ci.yml and release.yml. A weekly conformance-catalog-drift workflow clones the unpinned tip and runs the alignment assertion, so new cases surface as an early warning instead of a surprise at bump time. No SDK source changes. Verified locally against the pinned revision: the catalog alignment assertion passes, the conformance suite is green (104 passed, 1 xfailed — the xfail is pre-existing and unrelated), and the core suite is green (525). The pin adopts no new case ids, so it requires no coverage change.
…aise mcp floor past PYSEC-2026-3483 - authplane-sdk: issuer identifiers are stored and compared byte-for-byte (RFC 9068 iss, RFC 8414 §3.3) — no trailing-slash stripping on storage or comparison; query- or fragment-bearing issuers are rejected at AuthplaneClient.create() (RFC 8414 §2). Well-known derivation still strips the terminating slash (RFC 8414/9728 §3.1); build_prm_url keeps the resource query and rejects fragment-bearing resources (RFC 8707 §2). - authplane-mcp, authplane-fastmcp: the served Protected Resource Metadata advertises the configured issuer and resource byte-for-byte instead of the AnyHttpUrl-normalised form (RFC 8414/9728 §3.3). - authplane-mcp: mcp floor raised to >=1.28.1,<2 (PYSEC-2026-3483); the elicitation-id field name is resolved from the model schema instead of being hard-coded. authplane-fastmcp declares the same direct floor. - ci: single-source the conformance catalog pin in .conformance-catalog-ref (40-hex guarded) and add a scheduled drift check; pin ruff to >=0.16,<0.17 so formatting stays stable.
…h matchable errors
The fragment check for a resource indicator lived only in `build_prm_url`, whose
production caller is `AuthplaneResource.prm_url()` — a method reached from
inside a 401 response path. A deployment configured with a fragment-bearing
identifier therefore started normally and failed later, from the failure path,
as a 500. It is now rejected at `AuthplaneClient.resource(...)`, symmetrically
with the issuer check in `create()`, and again in `AuthplaneResource` itself so
the gate holds for a resource built without the factory. The check in
`build_prm_url` stays as a backstop.
`InvalidIssuerError` and `InvalidResourceError` subclass both `AuthplaneError`
and `ValueError`, so existing `except ValueError` handlers keep working while
callers gain the ability to tell an identifier misconfiguration apart from any
other `ValueError` the SDK raises — which matters now that the resource
rejection is a behaviour change deployments have to react to.
`build_prm_url` and `build_metadata_url` no longer strip slashes from the front
of the path: `str.strip("/")` took them from both ends, so `//mcp` lost a
segment and derived the same well-known URL as `/mcp` — two distinct identifiers
collapsing onto one document. RFC 9728 §3.1 and RFC 8414 §3.1 speak only of the
terminating slash.
BREAKING CHANGE: a fragment-bearing resource identifier now raises
`InvalidResourceError` at `client.resource(...)` instead of starting and failing
later. Remove the fragment — RFC 8707 §2 forbids one in a resource indicator.
…ake the PRM hook public `urlparse` peels an RFC 3986 `;params` segment off the last path segment, so a request to `/orders;v=2` bound an `htu` of `/orders` — a proof computed over a different resource than the one being accessed, and RFC 3986 §3.3 puts `;params` squarely in the path. The htu construction uses `urlsplit`, which does not split it off, and the round-trip no longer has to fill `urlunparse`'s params slot. `VerbatimPRMRemoteAuthProvider` is now public (was `_VerbatimPRMRemoteAuthProvider`) and `rewrite_prm_routes_verbatim` is exported: building a `RemoteAuthProvider` by hand is a documented FastMCP pattern, and doing so silently lost the verbatim PRM. `install_request_context(mcp)` now detects a verifier carrying no verbatim identifiers and warns instead of skipping the rewrite in silence — a verifier built through the public `AuthplaneTokenVerifier(verifier)` constructor has none, so the previous `is None` check never fired for it and the served document kept advertising slash-normalized identifiers that this SDK's own byte-for-byte comparison rejects. `AuthplaneTokenVerifier.verbatim_identifiers()` exposes the pair without cross-module private attribute reads. `install_request_context` also stops touching `mcp.sse_app` unguarded: SSE is not on the streamable-HTTP path, so a future `mcp` 1.x that drops the attribute would have taken down servers that never touch SSE.
…kfiles, record the changelog The conformance suite stops xfailing the inbound DPoP-Nonce case now that the catalog carries it, and the catalog-fetch tooling is aligned with the pinned ref so a local run matches CI rather than the moving default branch. `backport-fixes.sh` accepts a tag as `--from`: `release.yml` deletes `release/vX.Y.Z` once the tag is pushed, so afterwards the tag is the only ref naming those commits — which is exactly what the release summary tells the operator to pass. `--from` and `--to` are validated as ref names before reaching a fetch refspec, since `git ls-remote` matches its arguments as globs. `uv.lock` is ignored: nothing tracks or consumes these files — no workflow installs with uv — so they are local resolution artifacts. Three of them were swept into a merge commit as untracked files once and accounted for 94% of that diff. Tracking them for reproducible installs is a real decision and belongs in its own PR, alongside the CI change that would make them load-bearing.
| with pytest.raises(ValueError) as exc: | ||
| validate_resource_indicator("https://svc:s3cr3t@api.example.com/mcp#frag") | ||
| assert "s3cr3t" not in str(exc.value) | ||
| assert "api.example.com" in str(exc.value) |
| # call site the failure really is "the installed distribution is unusable", so | ||
| # translate it to the shape a reader expects from a failing import. | ||
| try: | ||
| _ELICITATION_ID_KWARG = _resolve_elicitation_id_kwarg(ElicitRequestURLParams) |
| # call site the failure really is "the installed distribution is unusable", so | ||
| # translate it to the shape a reader expects from a failing import. | ||
| try: | ||
| _ELICITATION_ID_KWARG = _resolve_elicitation_id_kwarg(ElicitRequestURLParams) |
| # RemoteAuthProvider does not silently lose the verbatim PRM. Nothing else | ||
| # imports them from the root — conftest reaches into .auth — so without this | ||
| # the __all__ entries could rot without a test noticing. | ||
| import authplane_fastmcp |
| from mcp.types import URL_ELICITATION_REQUIRED, ElicitRequestURLParams | ||
| from pydantic import BaseModel | ||
|
|
||
| import authplane_mcp.url_elicitation as url_elicitation |
| from mcp.types import URL_ELICITATION_REQUIRED, ElicitRequestURLParams | ||
| from pydantic import BaseModel | ||
|
|
||
| import authplane_fastmcp.url_elicitation as url_elicitation |
|
|
||
| def __call__( | ||
| self, base_url: str, resource: str, *, scopes: list[str] | None = None | ||
| ) -> AuthplaneTokenVerifier: ... |
| Back | FazBrowse Home | New Git URL |
Everything queued for the next release, consolidated into a single branch so it reviews and lands as one unit. Two behaviour changes are breaking; both carry a migration note in CHANGELOG.md.
Identifier identity and validation
The configured issuer is preserved byte-for-byte and compared for identity (RFC 8414 §2/§3.3); the terminating slash is dropped only where a well-known URL is derived (RFC 8414/9728 §3.1). An issuer carrying a query or fragment is rejected at AuthplaneClient.create().
The matching gate for the resource indicator previously lived only in build_prm_url, whose production caller is AuthplaneResource.prm_url() — a method reached from inside a 401 response path. A deployment configured with a fragment-bearing identifier therefore started normally and surfaced the problem later as a 500 emitted from the failure path. It is now rejected at client.resource(...), and again inside AuthplaneResource so a resource built without the factory is covered too; build_prm_url keeps the check as a backstop.
InvalidIssuerError and InvalidResourceError subclass both AuthplaneError and ValueError, so except ValueError handlers are unaffected while callers can now distinguish an identifier misconfiguration from any other ValueError the SDK raises.
build_prm_url and build_metadata_url no longer strip slashes from the front of the path: str.strip("/") removed them from both ends, so //mcp lost a segment and derived the same well-known URL as /mcp — two distinct identifiers collapsing onto one document.
Migration: remove any fragment from a resource indicator (RFC 8707 §2 forbids one), and correct any issuer that differs from the AS's published identifier by a trailing slash.
DPoP htu and the ;params segment
urlparse peels an RFC 3986 ;params segment off the last path segment, so a request to /orders;v=2 bound an htu of /orders — a proof computed over a different resource than the one being accessed. RFC 3986 §3.3 puts ;params in the path; the construction now uses urlsplit, which leaves it there.
Verbatim PRM
VerbatimPRMRemoteAuthProvider becomes public and rewrite_prm_routes_verbatim is exported: building a RemoteAuthProvider by hand is a documented FastMCP pattern and doing so silently lost the verbatim PRM. install_request_context(mcp) now warns when the verifier carries no verbatim identifiers instead of skipping the rewrite in silence — a verifier built through the public constructor has none, so the previous check never fired for it and the served document kept advertising slash-normalized identifiers that this SDK's own comparison rejects. It also stops reading mcp.sse_app unguarded, so a future mcp 1.x that drops the attribute cannot take down servers that never touch SSE.
Security and tooling
The mcp dependency floor moves to >=1.28.1, clearing PYSEC-2026-3483; authplane-fastmcp declares it directly, since it imports the top-level mcp package and the transitive fastmcp dependency does not guarantee the floor. verify_dpop_proof no longer echoes the expected or received nonce into its error — www_authenticate copies the message verbatim into error_description, which would hand an unauthenticated caller a currently-valid resource-server nonce.
The conformance catalog is fetched at a pinned SHA with a drift check, and uv.lock files are ignored: nothing tracks or consumes them, and three were once swept into a PR as untracked files accounting for 94% of its diff.