Serve MCP and hooks with a secret through the portal tunnel

The connector now serves /mcp, its OAuth documents and /hooks/ besides
/api/v1/, refuses any dot segment (httpx resolves them, which carried
/api/v1/../../mcp onto the MCP mount), addresses calls to the hub's host,
and bridges served sockets by calling the app with a websocket scope.
A hook without a secret answers the tunnel with the 404 (or 1008) of a
wrong secret. Requests through the hub get the hub's issuer, resource and
consent page in the OAuth metadata and the 401, and the MCP host check
admits the hub while enrolled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
This commit is contained in:
2026-10-15 11:00:19 +02:00
co-authored by Claude Opus 5.5
parent 7a56818213
commit 391edc8766
14 changed files with 526 additions and 31 deletions
+38
View File
@@ -80,6 +80,44 @@ def test_the_metadata_says_how_to_get_in(client: TestClient) -> None:
}
@pytest.mark.usefixtures("enrolled")
def test_through_the_hub_the_metadata_and_resource_are_the_hubs(
client: TestClient, superuser_token_headers: dict[str, str]
) -> None:
"""An agent at /i/{id}/mcp on the hub is sent to the hub's addresses."""
from fluksio.cloud import config as cloud_config
from tests.utils.portal import INSTANCE_ID, ISSUER
via = {cloud_config.VIA_HEADER: cloud_config.VIA_PORTAL}
base = f"{ISSUER}/i/{INSTANCE_ID}"
document = client.get("/.well-known/oauth-authorization-server", headers=via).json()
assert document["issuer"] == base
assert document["token_endpoint"] == f"{base}{PREFIX}/token"
# No link is attached here to name the portal's page, so the hub's own.
assert document["authorization_endpoint"] == f"{base}/oauth/authorize"
# A request made here hears nothing about the hub.
local = client.get("/.well-known/oauth-authorization-server").json()
assert local["issuer"] == settings.oauth_issuer
_verifier, challenge = pkce()
body = {
"client_id": register(client)["client_id"],
"redirect_uri": REDIRECT,
"code_challenge": challenge,
"code_challenge_method": "S256",
"resource": f"{base}/mcp",
}
through = client.post(
f"{PREFIX}/authorize", headers={**superuser_token_headers, **via}, json=body
)
assert through.status_code == 200, through.text
# Only through the hub is that a resource this instance serves.
here = client.post(
f"{PREFIX}/authorize", headers=superuser_token_headers, json=body
)
assert here.json()["error"] == "invalid_target"
def test_a_full_authorization_reaches_the_api(
client: TestClient, superuser_token_headers: dict[str, str]
) -> None: