From 817d8b9d400ccb189f6960df5b3370d94bee5229 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Mon, 17 Aug 2026 12:05:11 +0530 Subject: [PATCH] feat(trusted-issuer): expose enable_token_review and apiserver URL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The server has accepted enable_token_review and kubernetes_api_server_url on _add_trusted_issuer / _update_trusted_issuer, and returned them on the TrustedIssuer type, for some time. This SDK carried neither: the request dataclasses had no such fields, and TrustedIssuer.from_dict drops unknown keys through _known(), so a value the server returned was silently discarded. Kubernetes TokenReview was therefore unreachable from Python at all — not awkward, unreachable. Adds the pair to AddTrustedIssuerRequest, UpdateTrustedIssuerRequest and the TrustedIssuer response, plus TRUSTED_ISSUER_FRAGMENT so the GraphQL selection actually asks for them. Verified against a live server, not just by unit test: set both through add_trusted_issuer and read both back through trusted_issuers. Also corrects a stale comment listing spiffe_bundle_endpoint as a valid key_source_type. It has no fetcher server-side and is now rejected at write time, so a caller following that comment gets an error. --- src/authorizer/_queries.py | 1 + src/authorizer/types.py | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/authorizer/_queries.py b/src/authorizer/_queries.py index 8d42590..e09be10 100644 --- a/src/authorizer/_queries.py +++ b/src/authorizer/_queries.py @@ -317,6 +317,7 @@ TRUSTED_ISSUER_FRAGMENT = ( "id service_account_id name issuer_url key_source_type jwks_url expected_aud " "subject_claim allowed_subjects issuer_type is_active spiffe_refresh_hint_seconds " + "enable_token_review kubernetes_api_server_url " "created_at updated_at" ) ORGANIZATION_FRAGMENT = "id name display_name enabled created_at updated_at" diff --git a/src/authorizer/types.py b/src/authorizer/types.py index 73de56e..851165b 100644 --- a/src/authorizer/types.py +++ b/src/authorizer/types.py @@ -824,7 +824,9 @@ class AddTrustedIssuerRequest(_Request): service_account_id: str name: str issuer_url: str - # key_source_type: "oidc_discovery" | "static_jwks_url" | "spiffe_bundle_endpoint" + # key_source_type: "oidc_discovery" | "static_jwks_url". + # "spiffe_bundle_endpoint" is declared server-side but has no fetcher and is + # REJECTED at write time — use static_jwks_url for SPIFFE issuers. key_source_type: str expected_aud: str # issuer_type: "kubernetes_sa" | "spiffe_jwt" | "oidc" | "cloud_oidc" @@ -835,6 +837,18 @@ class AddTrustedIssuerRequest(_Request): # allowed_subjects: comma-separated exact subject allow-list. Empty = deny-all. allowed_subjects: str | None = None spiffe_refresh_hint_seconds: int | None = None + # enable_token_review turns on online Kubernetes TokenReview validation: + # after the offline JWKS checks pass, the server asks the cluster whether the + # presented token is still authenticated, which offline validation cannot + # tell (a deleted pod's unexpired token still verifies). + enable_token_review: bool | None = None + # kubernetes_api_server_url is REQUIRED, and must be https, whenever + # enable_token_review is true — the server rejects the write otherwise. + # + # Security-sensitive: the server authenticates that call with its own + # in-cluster ServiceAccount token, so whatever host is set here receives + # that credential. It must be the cluster's real API server. + kubernetes_api_server_url: str | None = None @dataclass @@ -846,6 +860,11 @@ class UpdateTrustedIssuerRequest(_Request): allowed_subjects: str | None = None is_active: bool | None = None spiffe_refresh_hint_seconds: int | None = None + # See AddTrustedIssuerRequest for both fields. On update the server + # validates the MERGED row, so enabling review without a previously stored + # apiserver URL is rejected at write time. + enable_token_review: bool | None = None + kubernetes_api_server_url: str | None = None @dataclass @@ -1455,6 +1474,8 @@ class TrustedIssuer: issuer_type: str = "" is_active: bool = False spiffe_refresh_hint_seconds: int | None = None + enable_token_review: bool = False + kubernetes_api_server_url: str | None = None created_at: int | None = None updated_at: int | None = None