From 95b9139697bf4ae74324cbc5723228481e201c37 Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Fri, 19 Jun 2026 07:12:29 -0300 Subject: [PATCH 1/8] feat: wire up SDK compliance checking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the three files needed to integrate with the cross-SDK capability matrix (https://github.com/supabase/sdk): - sdk-compliance.yaml — declares implementation status for every feature in the canonical registry, with symbol names mapped to Python class methods so the parser can cross-reference them - sdk-parse-ignore — tells the Python API-surface parser to skip test directories and conftest files - .github/workflows/validate-capabilities.yml — calls the reusable validate-sdk-compliance workflow from supabase/sdk on every push to main and every PR The compliance file covers auth, database (postgrest), storage, realtime, functions, and client configuration. Notable gaps flagged as not_implemented: passkeys, OAuth server/admin APIs, several newer realtime features, and storage vector/analytics buckets. Part of SDK-991. --- .github/workflows/validate-capabilities.yml | 16 + sdk-compliance.yaml | 650 ++++++++++++++++++++ sdk-parse-ignore | 3 + 3 files changed, 669 insertions(+) create mode 100644 .github/workflows/validate-capabilities.yml create mode 100644 sdk-compliance.yaml create mode 100644 sdk-parse-ignore diff --git a/.github/workflows/validate-capabilities.yml b/.github/workflows/validate-capabilities.yml new file mode 100644 index 00000000..b87e1e14 --- /dev/null +++ b/.github/workflows/validate-capabilities.yml @@ -0,0 +1,16 @@ +name: Validate SDK Compliance + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + +jobs: + validate: + uses: supabase/sdk/.github/workflows/validate-sdk-compliance.yml@main + with: + language: python diff --git a/sdk-compliance.yaml b/sdk-compliance.yaml new file mode 100644 index 00000000..97c69fc4 --- /dev/null +++ b/sdk-compliance.yaml @@ -0,0 +1,650 @@ +sdk: python + +# Full declaration of all features from the supabase/sdk capability registry. +# See https://github.com/supabase/sdk for the canonical feature registry. + +features: + + # ── Auth ─────────────────────────────────────────────────────────────────── + + auth.sign_in.sign_up: + status: implemented + symbols: + - AsyncGoTrueClient.sign_up + - SyncGoTrueClient.sign_up + auth.sign_in.sign_in_with_password: + status: implemented + symbols: + - AsyncGoTrueClient.sign_in_with_password + - SyncGoTrueClient.sign_in_with_password + auth.sign_in.sign_in_with_oauth: + status: implemented + symbols: + - AsyncGoTrueClient.sign_in_with_oauth + - SyncGoTrueClient.sign_in_with_oauth + auth.sign_in.sign_in_with_otp: + status: implemented + symbols: + - AsyncGoTrueClient.sign_in_with_otp + - SyncGoTrueClient.sign_in_with_otp + auth.sign_in.sign_in_with_sso: + status: implemented + symbols: + - AsyncGoTrueClient.sign_in_with_sso + - SyncGoTrueClient.sign_in_with_sso + auth.sign_in.sign_in_with_id_token: + status: implemented + symbols: + - AsyncGoTrueClient.sign_in_with_id_token + - SyncGoTrueClient.sign_in_with_id_token + auth.sign_in.sign_in_anonymously: + status: implemented + symbols: + - AsyncGoTrueClient.sign_in_anonymously + - SyncGoTrueClient.sign_in_anonymously + auth.sign_in.sign_in_with_web3: not_implemented + auth.sign_in.verify_otp: + status: implemented + symbols: + - AsyncGoTrueClient.verify_otp + - SyncGoTrueClient.verify_otp + auth.sign_in.resend_confirmation: + status: implemented + symbols: + - AsyncGoTrueClient.resend + - SyncGoTrueClient.resend + auth.sign_in.reset_password: + status: implemented + symbols: + - AsyncGoTrueClient.reset_password_for_email + - SyncGoTrueClient.reset_password_for_email + auth.sign_in.reauthenticate: + status: implemented + symbols: + - AsyncGoTrueClient.reauthenticate + - SyncGoTrueClient.reauthenticate + auth.sign_in.exchange_code_for_session: + status: implemented + symbols: + - AsyncGoTrueClient.exchange_code_for_session + - SyncGoTrueClient.exchange_code_for_session + + auth.session.get_session: + status: implemented + symbols: + - AsyncGoTrueClient.get_session + - SyncGoTrueClient.get_session + auth.session.get_user: + status: implemented + symbols: + - AsyncGoTrueClient.get_user + - SyncGoTrueClient.get_user + auth.session.get_claims: + status: implemented + symbols: + - AsyncGoTrueClient.get_claims + - SyncGoTrueClient.get_claims + auth.session.refresh_session: + status: implemented + symbols: + - AsyncGoTrueClient.refresh_session + - SyncGoTrueClient.refresh_session + auth.session.set_session: + status: implemented + symbols: + - AsyncGoTrueClient.set_session + - SyncGoTrueClient.set_session + auth.session.sign_out: + status: implemented + symbols: + - AsyncGoTrueClient.sign_out + - SyncGoTrueClient.sign_out + auth.session.update_user: + status: implemented + symbols: + - AsyncGoTrueClient.update_user + - SyncGoTrueClient.update_user + auth.session.subscribe_auth_events: + status: implemented + symbols: + - AsyncGoTrueClient.on_auth_state_change + - SyncGoTrueClient.on_auth_state_change + auth.session.auto_refresh: + status: partially_implemented + note: "auto_refresh_token is a constructor option; no explicit start/stop control is exposed." + + auth.identities.link_identity: + status: implemented + symbols: + - AsyncGoTrueClient.link_identity + - SyncGoTrueClient.link_identity + auth.identities.unlink_identity: + status: implemented + symbols: + - AsyncGoTrueClient.unlink_identity + - SyncGoTrueClient.unlink_identity + auth.identities.list_identities: + status: implemented + symbols: + - AsyncGoTrueClient.get_user_identities + - SyncGoTrueClient.get_user_identities + + auth.mfa.enroll: + status: implemented + symbols: + - AsyncGoTrueMFAAPI.enroll + - SyncGoTrueMFAAPI.enroll + auth.mfa.challenge: + status: implemented + symbols: + - AsyncGoTrueMFAAPI.challenge + - SyncGoTrueMFAAPI.challenge + auth.mfa.verify: + status: implemented + symbols: + - AsyncGoTrueMFAAPI.verify + - SyncGoTrueMFAAPI.verify + auth.mfa.unenroll: + status: implemented + symbols: + - AsyncGoTrueMFAAPI.unenroll + - SyncGoTrueMFAAPI.unenroll + auth.mfa.challenge_and_verify: + status: implemented + symbols: + - AsyncGoTrueMFAAPI.challenge_and_verify + - SyncGoTrueMFAAPI.challenge_and_verify + auth.mfa.list_factors: + status: implemented + symbols: + - AsyncGoTrueMFAAPI.list_factors + - SyncGoTrueMFAAPI.list_factors + auth.mfa.get_authenticator_assurance_level: + status: implemented + symbols: + - AsyncGoTrueMFAAPI.get_authenticator_assurance_level + - SyncGoTrueMFAAPI.get_authenticator_assurance_level + + auth.admin.create_user: + status: implemented + symbols: + - AsyncGoTrueAdminAPI.create_user + - SyncGoTrueAdminAPI.create_user + auth.admin.delete_user: + status: implemented + symbols: + - AsyncGoTrueAdminAPI.delete_user + - SyncGoTrueAdminAPI.delete_user + auth.admin.update_user: + status: implemented + symbols: + - AsyncGoTrueAdminAPI.update_user_by_id + - SyncGoTrueAdminAPI.update_user_by_id + auth.admin.get_user: + status: implemented + symbols: + - AsyncGoTrueAdminAPI.get_user_by_id + - SyncGoTrueAdminAPI.get_user_by_id + auth.admin.list_users: + status: implemented + symbols: + - AsyncGoTrueAdminAPI.list_users + - SyncGoTrueAdminAPI.list_users + auth.admin.invite_user: + status: implemented + symbols: + - AsyncGoTrueAdminAPI.invite_user_by_email + - SyncGoTrueAdminAPI.invite_user_by_email + auth.admin.sign_out: + status: implemented + symbols: + - AsyncGoTrueAdminAPI.sign_out + - SyncGoTrueAdminAPI.sign_out + auth.admin.generate_link: + status: implemented + symbols: + - AsyncGoTrueAdminAPI.generate_link + - SyncGoTrueAdminAPI.generate_link + auth.admin.list_mfa_factors: not_implemented + auth.admin.delete_mfa_factor: not_implemented + auth.admin.create_provider: not_implemented + auth.admin.delete_provider: not_implemented + auth.admin.update_provider: not_implemented + auth.admin.get_provider: not_implemented + auth.admin.list_providers: not_implemented + + auth.passkey.register_passkey: not_implemented + auth.passkey.sign_in_with_passkey: not_implemented + + auth.passkey_admin.list_passkeys: not_implemented + auth.passkey_admin.delete_passkey: not_implemented + + auth.oauth_server.approve_authorization: not_implemented + auth.oauth_server.deny_authorization: not_implemented + auth.oauth_server.get_authorization_details: not_implemented + auth.oauth_server.list_grants: not_implemented + auth.oauth_server.revoke_grant: not_implemented + + auth.oauth_admin.create_client: not_implemented + auth.oauth_admin.delete_client: not_implemented + auth.oauth_admin.get_client: not_implemented + auth.oauth_admin.list_clients: not_implemented + auth.oauth_admin.regenerate_client_secret: not_implemented + auth.oauth_admin.update_client: not_implemented + + # ── Client ───────────────────────────────────────────────────────────────── + + client.authentication_integration.third_party_auth: not_implemented + client.authentication_integration.cross_client_token_sync: not_implemented + client.authentication_integration.oauth_flow_type: + status: implemented + note: "flow_type constructor parameter on the auth client." + client.authentication_integration.session_url_detection: not_implemented + + client.session_management.custom_storage: + status: implemented + note: "storage parameter on the auth client accepts a custom async/sync storage backend." + client.session_management.persist_session: + status: implemented + note: "persist_session constructor parameter on the auth client." + + client.request_configuration.custom_http_client: + status: implemented + note: "http_client parameter on client constructors accepts a custom httpx client." + client.request_configuration.global_headers: + status: implemented + note: "headers parameter accepted by all sub-client constructors." + + client.observability.trace_propagation: not_implemented + + # ── Database ─────────────────────────────────────────────────────────────── + + database.query.from_table: + status: implemented + symbols: + - AsyncPostgrestClient.from_ + - AsyncPostgrestClient.table + - SyncPostgrestClient.from_ + - SyncPostgrestClient.table + database.query.select: + status: implemented + symbols: + - AsyncRequestBuilder.select + - SyncRequestBuilder.select + database.query.schema_selection: + status: implemented + symbols: + - AsyncPostgrestClient.schema + - SyncPostgrestClient.schema + database.query.rpc: + status: implemented + symbols: + - AsyncPostgrestClient.rpc + - SyncPostgrestClient.rpc + + database.mutate.insert: + status: implemented + symbols: + - AsyncRequestBuilder.insert + - SyncRequestBuilder.insert + database.mutate.update: + status: implemented + symbols: + - AsyncRequestBuilder.update + - SyncRequestBuilder.update + database.mutate.upsert: + status: implemented + symbols: + - AsyncRequestBuilder.upsert + - SyncRequestBuilder.upsert + database.mutate.delete: + status: implemented + symbols: + - AsyncRequestBuilder.delete + - SyncRequestBuilder.delete + database.mutate.select_after_mutation: + status: implemented + note: "count and returning parameters on mutate methods; select via returning='representation'." + + database.using_filters.eq: implemented + database.using_filters.neq: implemented + database.using_filters.gt: implemented + database.using_filters.gte: implemented + database.using_filters.lt: implemented + database.using_filters.lte: implemented + database.using_filters.like: implemented + database.using_filters.ilike: implemented + database.using_filters.is: implemented + database.using_filters.in: implemented + database.using_filters.contains: implemented + database.using_filters.contained_by: implemented + database.using_filters.range_gt: implemented + database.using_filters.range_gte: implemented + database.using_filters.range_lt: implemented + database.using_filters.range_lte: implemented + database.using_filters.range_adjacent: implemented + database.using_filters.overlaps: implemented + database.using_filters.text_search: implemented + database.using_filters.match: implemented + database.using_filters.not: implemented + database.using_filters.or: implemented + database.using_filters.raw: implemented + database.using_filters.regex: implemented + database.using_filters.regex_icase: implemented + database.using_filters.is_distinct: not_implemented + database.using_filters.not_in: not_implemented + database.using_filters.like_all: not_implemented + database.using_filters.like_any: not_implemented + database.using_filters.ilike_all: not_implemented + database.using_filters.ilike_any: not_implemented + + database.using_modifiers.order: implemented + database.using_modifiers.limit: implemented + database.using_modifiers.range: implemented + database.using_modifiers.single_row: + status: implemented + symbols: + - AsyncSelectRequestBuilder.single + - SyncSelectRequestBuilder.single + database.using_modifiers.maybe_single_row: + status: implemented + symbols: + - AsyncSelectRequestBuilder.maybe_single + - SyncSelectRequestBuilder.maybe_single + database.using_modifiers.strip_nulls: not_implemented + database.using_modifiers.format_csv: + status: implemented + symbols: + - AsyncSelectRequestBuilder.csv + - SyncSelectRequestBuilder.csv + database.using_modifiers.format_geojson: not_implemented + database.using_modifiers.explain: + status: implemented + symbols: + - AsyncSelectRequestBuilder.explain + - SyncSelectRequestBuilder.explain + database.using_modifiers.max_affected_rows: not_implemented + database.using_modifiers.request_cancellation: not_implemented + database.using_modifiers.relationship_embed: + status: implemented + note: "Supported via query-string syntax in select() (e.g. 'user(*)'); no dedicated relationship builder API." + database.using_modifiers.dry_run: not_implemented + + database.configuration.auto_retry: + status: implemented + symbols: + - AsyncSelectRequestBuilder.retry + - SyncSelectRequestBuilder.retry + database.configuration.request_timeout: not_implemented + + # ── Functions ────────────────────────────────────────────────────────────── + + functions.invocation.invoke: + status: implemented + symbols: + - AsyncFunctionsClient.invoke + - SyncFunctionsClient.invoke + functions.invocation.set_auth_token: + status: implemented + symbols: + - AsyncFunctionsClient.set_auth + - SyncFunctionsClient.set_auth + functions.invocation.method_override: not_implemented + functions.invocation.streaming_response: not_implemented + functions.invocation.region_selection: not_implemented + functions.invocation.request_cancellation: not_implemented + functions.invocation.timeout: not_implemented + + # ── Realtime ─────────────────────────────────────────────────────────────── + + realtime.client.connect: + status: implemented + symbols: + - AsyncRealtimeClient.connect + - SyncRealtimeClient.connect + realtime.client.disconnect: + status: implemented + symbols: + - AsyncRealtimeClient.disconnect + - SyncRealtimeClient.disconnect + realtime.client.get_channels: + status: implemented + symbols: + - AsyncRealtimeClient.get_channels + - SyncRealtimeClient.get_channels + realtime.client.remove_channel: + status: implemented + symbols: + - AsyncRealtimeClient.remove_channel + - SyncRealtimeClient.remove_channel + realtime.client.remove_all_channels: + status: implemented + symbols: + - AsyncRealtimeClient.remove_all_channels + - SyncRealtimeClient.remove_all_channels + realtime.client.connection_state: + status: partially_implemented + note: "is_connected boolean property; no full connection-state enum exposed." + symbols: + - AsyncRealtimeClient.is_connected + - SyncRealtimeClient.is_connected + realtime.client.listen_heartbeats: not_implemented + realtime.client.set_auth_token: + status: implemented + symbols: + - AsyncRealtimeClient.set_auth + - SyncRealtimeClient.set_auth + realtime.client.channel: + status: implemented + symbols: + - AsyncRealtimeClient.channel + - SyncRealtimeClient.channel + + realtime.channel.subscribe: + status: implemented + symbols: + - AsyncRealtimeChannel.subscribe + - SyncRealtimeChannel.subscribe + realtime.channel.unsubscribe: + status: implemented + symbols: + - AsyncRealtimeChannel.unsubscribe + - SyncRealtimeChannel.unsubscribe + realtime.channel.send: + status: implemented + symbols: + - AsyncRealtimeChannel.send + - SyncRealtimeChannel.send + realtime.channel.broadcast_http: not_implemented + + realtime.subscriptions.broadcast: + status: implemented + symbols: + - AsyncRealtimeChannel.on_broadcast + - SyncRealtimeChannel.on_broadcast + realtime.subscriptions.postgres_changes: + status: implemented + symbols: + - AsyncRealtimeChannel.on_postgres_changes + - SyncRealtimeChannel.on_postgres_changes + realtime.subscriptions.subscribe_presence: + status: implemented + symbols: + - AsyncRealtimeChannel.on_presence_change + - SyncRealtimeChannel.on_presence_change + realtime.subscriptions.postgres_changes_filter: + status: implemented + note: "event, schema, table, and filter parameters on on_postgres_changes." + realtime.subscriptions.private_channel: not_implemented + realtime.subscriptions.broadcast_self: not_implemented + realtime.subscriptions.broadcast_ack: not_implemented + realtime.subscriptions.broadcast_replay: not_implemented + + realtime.presence.track: + status: implemented + symbols: + - AsyncRealtimeChannel.track + - SyncRealtimeChannel.track + realtime.presence.untrack: + status: implemented + symbols: + - AsyncRealtimeChannel.untrack + - SyncRealtimeChannel.untrack + realtime.presence.presence_state: + status: implemented + symbols: + - AsyncRealtimeChannel.presences + - SyncRealtimeChannel.presences + realtime.presence.presence_key: not_implemented + + realtime.configuration.custom_websocket_transport: not_implemented + realtime.configuration.reconnect_backoff: + status: implemented + note: "initial_backoff and max_retries constructor parameters." + realtime.configuration.heartbeat_interval: + status: implemented + note: "hb_interval constructor parameter." + realtime.configuration.access_token_callback: not_implemented + realtime.configuration.deferred_disconnect: not_implemented + realtime.configuration.custom_logger: not_implemented + realtime.configuration.binary_protocol: not_implemented + + # ── Storage ──────────────────────────────────────────────────────────────── + + storage.file_buckets.create_file_bucket: + status: implemented + symbols: + - AsyncStorageBucketAPI.create_bucket + - SyncStorageBucketAPI.create_bucket + storage.file_buckets.get_bucket: + status: implemented + symbols: + - AsyncStorageBucketAPI.get_bucket + - SyncStorageBucketAPI.get_bucket + storage.file_buckets.list_file_buckets: + status: implemented + symbols: + - AsyncStorageBucketAPI.list_buckets + - SyncStorageBucketAPI.list_buckets + storage.file_buckets.update_bucket: + status: implemented + symbols: + - AsyncStorageBucketAPI.update_bucket + - SyncStorageBucketAPI.update_bucket + storage.file_buckets.delete_file_bucket: + status: implemented + symbols: + - AsyncStorageBucketAPI.delete_bucket + - SyncStorageBucketAPI.delete_bucket + storage.file_buckets.empty_bucket: + status: implemented + symbols: + - AsyncStorageBucketAPI.empty_bucket + - SyncStorageBucketAPI.empty_bucket + storage.file_buckets.access_bucket: implemented + storage.file_buckets.upload: + status: implemented + symbols: + - AsyncBucketActionsMixin.upload + - SyncBucketActionsMixin.upload + storage.file_buckets.download: + status: implemented + symbols: + - AsyncBucketActionsMixin.download + - SyncBucketActionsMixin.download + storage.file_buckets.list_files: + status: implemented + symbols: + - AsyncBucketActionsMixin.list + - SyncBucketActionsMixin.list + storage.file_buckets.move: + status: implemented + symbols: + - AsyncBucketActionsMixin.move + - SyncBucketActionsMixin.move + storage.file_buckets.copy: + status: implemented + symbols: + - AsyncBucketActionsMixin.copy + - SyncBucketActionsMixin.copy + storage.file_buckets.remove: + status: implemented + symbols: + - AsyncBucketActionsMixin.remove + - SyncBucketActionsMixin.remove + storage.file_buckets.get_public_url: + status: implemented + symbols: + - AsyncBucketActionsMixin.get_public_url + - SyncBucketActionsMixin.get_public_url + storage.file_buckets.create_signed_url: + status: implemented + symbols: + - AsyncBucketActionsMixin.create_signed_url + - SyncBucketActionsMixin.create_signed_url + storage.file_buckets.create_signed_urls: + status: implemented + symbols: + - AsyncBucketActionsMixin.create_signed_urls + - SyncBucketActionsMixin.create_signed_urls + storage.file_buckets.create_signed_upload_url: + status: implemented + symbols: + - AsyncBucketActionsMixin.create_signed_upload_url + - SyncBucketActionsMixin.create_signed_upload_url + storage.file_buckets.upload_with_signed_url: + status: implemented + symbols: + - AsyncBucketActionsMixin.upload_to_signed_url + - SyncBucketActionsMixin.upload_to_signed_url + storage.file_buckets.update_file: + status: implemented + symbols: + - AsyncBucketActionsMixin.update + - SyncBucketActionsMixin.update + storage.file_buckets.file_exists: + status: implemented + symbols: + - AsyncBucketActionsMixin.exists + - SyncBucketActionsMixin.exists + storage.file_buckets.file_info: + status: implemented + symbols: + - AsyncBucketActionsMixin.info + - SyncBucketActionsMixin.info + storage.file_buckets.list_files_paginated: + status: implemented + symbols: + - AsyncBucketActionsMixin.list_v2 + - SyncBucketActionsMixin.list_v2 + storage.file_buckets.download_with_transform: not_implemented + storage.file_buckets.copy_cross_bucket: not_implemented + storage.file_buckets.move_cross_bucket: not_implemented + storage.file_buckets.upload_with_metadata: not_implemented + storage.file_buckets.url_cache_nonce: not_implemented + storage.file_buckets.download_as_stream: not_implemented + + # ── Storage — Vector Buckets ─────────────────────────────────────────────── + + storage.vector_buckets.create_vector_bucket: not_implemented + storage.vector_buckets.list_vector_buckets: not_implemented + storage.vector_buckets.delete_vector_bucket: not_implemented + storage.vector_buckets.access_vector_index: not_implemented + storage.vector_buckets.create_index: not_implemented + storage.vector_buckets.delete_index: not_implemented + storage.vector_buckets.get_index: not_implemented + storage.vector_buckets.list_indexes: not_implemented + storage.vector_buckets.put_vectors: not_implemented + storage.vector_buckets.get_vectors: not_implemented + storage.vector_buckets.delete_vectors: not_implemented + storage.vector_buckets.list_vectors: not_implemented + storage.vector_buckets.query_vectors: not_implemented + storage.vector_buckets.parallel_scan: not_implemented + + # ── Storage — Analytics Buckets ──────────────────────────────────────────── + + storage.analytics.create_analytics_bucket: not_implemented + storage.analytics.list_analytics_buckets: not_implemented + storage.analytics.delete_analytics_bucket: not_implemented + storage.analytics.iceberg_namespace: not_implemented + storage.analytics.iceberg_table: not_implemented diff --git a/sdk-parse-ignore b/sdk-parse-ignore new file mode 100644 index 00000000..6358141d --- /dev/null +++ b/sdk-parse-ignore @@ -0,0 +1,3 @@ +# Exclude test directories and files from the public API surface parser +src/*/tests/ +**/conftest.py From 19e5cbf34d238a8bc31eaa8a5339068c1f1dcda6 Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Fri, 19 Jun 2026 11:08:52 -0300 Subject: [PATCH 2/8] ci: pass griffe package names and search paths to validate workflow --- .github/workflows/validate-capabilities.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/validate-capabilities.yml b/.github/workflows/validate-capabilities.yml index b87e1e14..d7841d75 100644 --- a/.github/workflows/validate-capabilities.yml +++ b/.github/workflows/validate-capabilities.yml @@ -14,3 +14,7 @@ jobs: uses: supabase/sdk/.github/workflows/validate-sdk-compliance.yml@main with: language: python + griffe-packages: >- + supabase supabase_auth postgrest storage3 realtime supabase_functions + griffe-search-paths: >- + src/supabase/src,src/auth/src,src/postgrest/src,src/storage/src,src/realtime/src,src/functions/src From 8b0f8bc8b4b35a90dd19c9824a0f2a744bd2e954 Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Tue, 23 Jun 2026 10:38:25 -0300 Subject: [PATCH 3/8] ci: pin SDK workflow ref to PR branch until #36 merges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use sdk-ref + the branch ref in `uses:` so the validate workflow picks up Python/griffe support from the in-flight supabase/sdk PR. Revert both to @main once SDK PR #36 is merged. Also rename sdk-parse-ignore → .sdk-parse-ignore to match the rename that landed in supabase/sdk#37. --- .github/workflows/validate-capabilities.yml | 3 ++- sdk-parse-ignore => .sdk-parse-ignore | 0 2 files changed, 2 insertions(+), 1 deletion(-) rename sdk-parse-ignore => .sdk-parse-ignore (100%) diff --git a/.github/workflows/validate-capabilities.yml b/.github/workflows/validate-capabilities.yml index d7841d75..4ee4d20f 100644 --- a/.github/workflows/validate-capabilities.yml +++ b/.github/workflows/validate-capabilities.yml @@ -11,9 +11,10 @@ permissions: jobs: validate: - uses: supabase/sdk/.github/workflows/validate-sdk-compliance.yml@main + uses: supabase/sdk/.github/workflows/validate-sdk-compliance.yml@claude/cool-chatterjee-c521b3 with: language: python + sdk-ref: claude/cool-chatterjee-c521b3 griffe-packages: >- supabase supabase_auth postgrest storage3 realtime supabase_functions griffe-search-paths: >- diff --git a/sdk-parse-ignore b/.sdk-parse-ignore similarity index 100% rename from sdk-parse-ignore rename to .sdk-parse-ignore From cd39200dad320c3c9f2ea9e8d59b7e612dca3626 Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Thu, 25 Jun 2026 09:00:52 -0300 Subject: [PATCH 4/8] chore: deep compliance audit against supabase-js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Audit every implemented feature against the supabase-js reference to check behavioral parity, not just method existence. Corrections (wrong not_implemented status): - functions.invocation.region_selection: implemented via region key in invoke_options (FunctionRegion enum → x-region header) - client.authentication_integration.cross_client_token_sync: sub-clients lazily recreated with updated Authorization header on auth events; realtime.set_auth() called directly - realtime.subscriptions.private_channel: private config passed to server - realtime.subscriptions.broadcast_self: broadcast.self config passed to server - realtime.presence.presence_key: presence.key config passed to server Corrections (partial — config passes but behavior diverges from JS): - realtime.subscriptions.broadcast_ack: ack config sent to server but send_broadcast() does not await acknowledgment (JS does) - realtime.configuration.reconnect_backoff: fixed params only; JS accepts a custom reconnect function Symbol fix: - realtime.channel.send: renamed to send_broadcast in Python SDK Note improvements: - auth.session.auto_refresh: mention missing startAutoRefresh/stopAutoRefresh - database.mutate.select_after_mutation: clarify .select() chaining works for column selection after mutations, not just returning='representation' --- sdk-compliance.yaml | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/sdk-compliance.yaml b/sdk-compliance.yaml index 97c69fc4..e81f5c3e 100644 --- a/sdk-compliance.yaml +++ b/sdk-compliance.yaml @@ -111,7 +111,7 @@ features: - SyncGoTrueClient.on_auth_state_change auth.session.auto_refresh: status: partially_implemented - note: "auto_refresh_token is a constructor option; no explicit start/stop control is exposed." + note: "Token refresh runs automatically as an internal background task controlled by the auto_refresh_token constructor option. No public startAutoRefresh() / stopAutoRefresh() methods are exposed as in supabase-js." auth.identities.link_identity: status: implemented @@ -235,7 +235,9 @@ features: # ── Client ───────────────────────────────────────────────────────────────── client.authentication_integration.third_party_auth: not_implemented - client.authentication_integration.cross_client_token_sync: not_implemented + client.authentication_integration.cross_client_token_sync: + status: implemented + note: "On SIGNED_IN, TOKEN_REFRESHED, and SIGNED_OUT events the Authorization header is updated and sub-clients (postgrest, storage, functions) are lazily recreated with the new token on their next access; realtime.set_auth() is called directly." client.authentication_integration.oauth_flow_type: status: implemented note: "flow_type constructor parameter on the auth client." @@ -304,7 +306,7 @@ features: - SyncRequestBuilder.delete database.mutate.select_after_mutation: status: implemented - note: "count and returning parameters on mutate methods; select via returning='representation'." + note: "Chainable .select(*columns) after insert/update/upsert/delete — sets return=representation and adds a column selection query param. count and returning parameters also supported directly on each mutate method." database.using_filters.eq: implemented database.using_filters.neq: implemented @@ -391,7 +393,9 @@ features: - SyncFunctionsClient.set_auth functions.invocation.method_override: not_implemented functions.invocation.streaming_response: not_implemented - functions.invocation.region_selection: not_implemented + functions.invocation.region_selection: + status: implemented + note: "Passed via the region key in invoke_options; maps to the x-region header and forceFunctionRegion query param using the FunctionRegion enum." functions.invocation.request_cancellation: not_implemented functions.invocation.timeout: not_implemented @@ -453,8 +457,8 @@ features: realtime.channel.send: status: implemented symbols: - - AsyncRealtimeChannel.send - - SyncRealtimeChannel.send + - AsyncRealtimeChannel.send_broadcast + - SyncRealtimeChannel.send_broadcast realtime.channel.broadcast_http: not_implemented realtime.subscriptions.broadcast: @@ -475,9 +479,15 @@ features: realtime.subscriptions.postgres_changes_filter: status: implemented note: "event, schema, table, and filter parameters on on_postgres_changes." - realtime.subscriptions.private_channel: not_implemented - realtime.subscriptions.broadcast_self: not_implemented - realtime.subscriptions.broadcast_ack: not_implemented + realtime.subscriptions.private_channel: + status: implemented + note: "Set private: true in the channel config; passed to the server on subscribe to enforce Row Level Security on postgres changes and restrict access." + realtime.subscriptions.broadcast_self: + status: implemented + note: "Set broadcast.self: true in the channel config; passed to the server so the sender receives its own broadcast messages." + realtime.subscriptions.broadcast_ack: + status: partially_implemented + note: "broadcast.ack: true is passed to the server in the channel config, and ack replies from the server are handled internally. However, send_broadcast() returns immediately without awaiting the server acknowledgment — supabase-js resolves the send promise only after the ack is received." realtime.subscriptions.broadcast_replay: not_implemented realtime.presence.track: @@ -495,12 +505,14 @@ features: symbols: - AsyncRealtimeChannel.presences - SyncRealtimeChannel.presences - realtime.presence.presence_key: not_implemented + realtime.presence.presence_key: + status: implemented + note: "Set presence.key in the channel config; passed to the server so multiple connections from the same user share one logical presence key." realtime.configuration.custom_websocket_transport: not_implemented realtime.configuration.reconnect_backoff: - status: implemented - note: "initial_backoff and max_retries constructor parameters." + status: partially_implemented + note: "initial_backoff (seconds) and max_retries constructor parameters control exponential backoff. supabase-js accepts a custom reconnect function mapping attempt count to delay ms; Python only supports the fixed-parameter variant." realtime.configuration.heartbeat_interval: status: implemented note: "hb_interval constructor parameter." From 8c169817c64b39fc865b979149d3555a26122ccf Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Thu, 25 Jun 2026 09:03:48 -0300 Subject: [PATCH 5/8] ci: use @main for validate-sdk-compliance workflow ref --- .github/workflows/validate-capabilities.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/validate-capabilities.yml b/.github/workflows/validate-capabilities.yml index 4ee4d20f..d7841d75 100644 --- a/.github/workflows/validate-capabilities.yml +++ b/.github/workflows/validate-capabilities.yml @@ -11,10 +11,9 @@ permissions: jobs: validate: - uses: supabase/sdk/.github/workflows/validate-sdk-compliance.yml@claude/cool-chatterjee-c521b3 + uses: supabase/sdk/.github/workflows/validate-sdk-compliance.yml@main with: language: python - sdk-ref: claude/cool-chatterjee-c521b3 griffe-packages: >- supabase supabase_auth postgrest storage3 realtime supabase_functions griffe-search-paths: >- From a344079ba51bb6ee85c878ea6b4dd2da38387561 Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Thu, 25 Jun 2026 10:58:00 -0300 Subject: [PATCH 6/8] fix(tests): grant API access to realtime integration test tables Supabase no longer auto-grants public schema access to the anon and authenticated roles. Explicit GRANT statements are now required for tables and sequences to be reachable via the REST Data API. Mirrors the fix applied to supabase-swift in supabase/supabase-swift@8372c18. Ref: https://github.com/orgs/supabase/discussions/45329 --- .../migrations/20260601000000_grant_api_access.sql | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/realtime/infra/supabase/migrations/20260601000000_grant_api_access.sql diff --git a/src/realtime/infra/supabase/migrations/20260601000000_grant_api_access.sql b/src/realtime/infra/supabase/migrations/20260601000000_grant_api_access.sql new file mode 100644 index 00000000..6b820095 --- /dev/null +++ b/src/realtime/infra/supabase/migrations/20260601000000_grant_api_access.sql @@ -0,0 +1,8 @@ +-- Grant API access to tables for anon and authenticated roles. +-- Required since Supabase no longer grants public schema access by default +-- (see https://github.com/orgs/supabase/discussions/45329). +GRANT ALL ON TABLE public.todos TO anon, authenticated; +GRANT ALL ON TABLE public.messages TO anon, authenticated; + +-- Grant sequence usage for tables with generated identity primary keys +GRANT USAGE, SELECT ON SEQUENCE public.messages_id_seq TO anon, authenticated; From 0008c465370efc36baadc54cfd3ffcbe180f0c4c Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Thu, 25 Jun 2026 11:08:45 -0300 Subject: [PATCH 7/8] feat: mark storage vector buckets and analytics as implemented All storage3 vector bucket and analytics features are fully implemented: - AsyncStorageVectorsClient/SyncStorageVectorsClient: create/list/delete bucket, from_() - AsyncVectorBucketScope/SyncVectorBucketScope: create/get/list/delete index, index() - AsyncVectorIndexScope/SyncVectorIndexScope: put/get/list/query/delete vectors; list() supports segment_count/segment_index for parallel scan - AsyncStorageAnalyticsClient/SyncStorageAnalyticsClient: create/list/delete bucket; catalog() returns pyiceberg RestCatalog covering iceberg_namespace and iceberg_table --- sdk-compliance.yaml | 139 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 120 insertions(+), 19 deletions(-) diff --git a/sdk-compliance.yaml b/sdk-compliance.yaml index e81f5c3e..f0dc5352 100644 --- a/sdk-compliance.yaml +++ b/sdk-compliance.yaml @@ -638,25 +638,126 @@ features: # ── Storage — Vector Buckets ─────────────────────────────────────────────── - storage.vector_buckets.create_vector_bucket: not_implemented - storage.vector_buckets.list_vector_buckets: not_implemented - storage.vector_buckets.delete_vector_bucket: not_implemented - storage.vector_buckets.access_vector_index: not_implemented - storage.vector_buckets.create_index: not_implemented - storage.vector_buckets.delete_index: not_implemented - storage.vector_buckets.get_index: not_implemented - storage.vector_buckets.list_indexes: not_implemented - storage.vector_buckets.put_vectors: not_implemented - storage.vector_buckets.get_vectors: not_implemented - storage.vector_buckets.delete_vectors: not_implemented - storage.vector_buckets.list_vectors: not_implemented - storage.vector_buckets.query_vectors: not_implemented - storage.vector_buckets.parallel_scan: not_implemented + storage.vector_buckets.create_vector_bucket: + status: implemented + symbols: + - AsyncStorageVectorsClient.create_bucket + - SyncStorageVectorsClient.create_bucket + + storage.vector_buckets.list_vector_buckets: + status: implemented + symbols: + - AsyncStorageVectorsClient.list_buckets + - SyncStorageVectorsClient.list_buckets + + storage.vector_buckets.delete_vector_bucket: + status: implemented + symbols: + - AsyncStorageVectorsClient.delete_bucket + - SyncStorageVectorsClient.delete_bucket + + storage.vector_buckets.access_vector_index: + status: implemented + note: "AsyncStorageClient.vectors() returns AsyncStorageVectorsClient; .from_(bucket_name) returns AsyncVectorBucketScope; .index(index_name) returns AsyncVectorIndexScope." + symbols: + - AsyncStorageClient.vectors + - AsyncStorageVectorsClient.from_ + - AsyncVectorBucketScope.index + - SyncStorageClient.vectors + - SyncStorageVectorsClient.from_ + - SyncVectorBucketScope.index + + storage.vector_buckets.create_index: + status: implemented + symbols: + - AsyncVectorBucketScope.create_index + - SyncVectorBucketScope.create_index + + storage.vector_buckets.delete_index: + status: implemented + symbols: + - AsyncVectorBucketScope.delete_index + - SyncVectorBucketScope.delete_index + + storage.vector_buckets.get_index: + status: implemented + symbols: + - AsyncVectorBucketScope.get_index + - SyncVectorBucketScope.get_index + + storage.vector_buckets.list_indexes: + status: implemented + symbols: + - AsyncVectorBucketScope.list_indexes + - SyncVectorBucketScope.list_indexes + + storage.vector_buckets.put_vectors: + status: implemented + symbols: + - AsyncVectorIndexScope.put + - SyncVectorIndexScope.put + + storage.vector_buckets.get_vectors: + status: implemented + symbols: + - AsyncVectorIndexScope.get + - SyncVectorIndexScope.get + + storage.vector_buckets.delete_vectors: + status: implemented + symbols: + - AsyncVectorIndexScope.delete + - SyncVectorIndexScope.delete + + storage.vector_buckets.list_vectors: + status: implemented + symbols: + - AsyncVectorIndexScope.list + - SyncVectorIndexScope.list + + storage.vector_buckets.query_vectors: + status: implemented + symbols: + - AsyncVectorIndexScope.query + - SyncVectorIndexScope.query + + storage.vector_buckets.parallel_scan: + status: implemented + note: "list() accepts segment_count and segment_index parameters enabling parallel segment-based scanning." + symbols: + - AsyncVectorIndexScope.list + - SyncVectorIndexScope.list # ── Storage — Analytics Buckets ──────────────────────────────────────────── - storage.analytics.create_analytics_bucket: not_implemented - storage.analytics.list_analytics_buckets: not_implemented - storage.analytics.delete_analytics_bucket: not_implemented - storage.analytics.iceberg_namespace: not_implemented - storage.analytics.iceberg_table: not_implemented + storage.analytics.create_analytics_bucket: + status: implemented + symbols: + - AsyncStorageAnalyticsClient.create + - SyncStorageAnalyticsClient.create + + storage.analytics.list_analytics_buckets: + status: implemented + symbols: + - AsyncStorageAnalyticsClient.list + - SyncStorageAnalyticsClient.list + + storage.analytics.delete_analytics_bucket: + status: implemented + symbols: + - AsyncStorageAnalyticsClient.delete + - SyncStorageAnalyticsClient.delete + + storage.analytics.iceberg_namespace: + status: implemented + note: "catalog() returns a pyiceberg RestCatalog giving full Iceberg REST catalog access including namespace management." + symbols: + - AsyncStorageAnalyticsClient.catalog + - SyncStorageAnalyticsClient.catalog + + storage.analytics.iceberg_table: + status: implemented + note: "catalog() returns a pyiceberg RestCatalog giving full Iceberg REST catalog access including table management." + symbols: + - AsyncStorageAnalyticsClient.catalog + - SyncStorageAnalyticsClient.catalog From f60f7f16b12a7ca1cf80934e2b1563ea1c9f0695 Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Thu, 25 Jun 2026 11:13:01 -0300 Subject: [PATCH 8/8] feat: mark admin MFA and oauth_admin features as implemented - auth.admin.list_mfa_factors / delete_mfa_factor: real HTTP implementations are wired to admin.mfa.list_factors / delete_factor at construction time - auth.oauth_admin.*: all six operations (create/delete/get/list/regenerate_secret/update) are wired to admin.oauth.* at construction time and make real HTTP calls to admin/oauth/clients endpoints Passkeys, oauth_server, and provider admin features remain not_implemented (no code found in the codebase). --- sdk-compliance.yaml | 63 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/sdk-compliance.yaml b/sdk-compliance.yaml index f0dc5352..cb4b420e 100644 --- a/sdk-compliance.yaml +++ b/sdk-compliance.yaml @@ -205,8 +205,20 @@ features: symbols: - AsyncGoTrueAdminAPI.generate_link - SyncGoTrueAdminAPI.generate_link - auth.admin.list_mfa_factors: not_implemented - auth.admin.delete_mfa_factor: not_implemented + auth.admin.list_mfa_factors: + status: implemented + note: "Accessible via admin.mfa.list_factors(params); the mfa attribute is wired to the real HTTP implementation at construction time." + symbols: + - AsyncGoTrueAdminMFAAPI.list_factors + - SyncGoTrueAdminMFAAPI.list_factors + + auth.admin.delete_mfa_factor: + status: implemented + note: "Accessible via admin.mfa.delete_factor(params); wired at construction time." + symbols: + - AsyncGoTrueAdminMFAAPI.delete_factor + - SyncGoTrueAdminMFAAPI.delete_factor + auth.admin.create_provider: not_implemented auth.admin.delete_provider: not_implemented auth.admin.update_provider: not_implemented @@ -225,12 +237,47 @@ features: auth.oauth_server.list_grants: not_implemented auth.oauth_server.revoke_grant: not_implemented - auth.oauth_admin.create_client: not_implemented - auth.oauth_admin.delete_client: not_implemented - auth.oauth_admin.get_client: not_implemented - auth.oauth_admin.list_clients: not_implemented - auth.oauth_admin.regenerate_client_secret: not_implemented - auth.oauth_admin.update_client: not_implemented + auth.oauth_admin.create_client: + status: implemented + note: "Accessible via admin.oauth.create_client(params); wired at construction time." + symbols: + - AsyncGoTrueAdminOAuthAPI.create_client + - SyncGoTrueAdminOAuthAPI.create_client + + auth.oauth_admin.delete_client: + status: implemented + note: "Accessible via admin.oauth.delete_client(client_id); wired at construction time." + symbols: + - AsyncGoTrueAdminOAuthAPI.delete_client + - SyncGoTrueAdminOAuthAPI.delete_client + + auth.oauth_admin.get_client: + status: implemented + note: "Accessible via admin.oauth.get_client(client_id); wired at construction time." + symbols: + - AsyncGoTrueAdminOAuthAPI.get_client + - SyncGoTrueAdminOAuthAPI.get_client + + auth.oauth_admin.list_clients: + status: implemented + note: "Accessible via admin.oauth.list_clients(params); supports pagination via x-total-count and Link headers." + symbols: + - AsyncGoTrueAdminOAuthAPI.list_clients + - SyncGoTrueAdminOAuthAPI.list_clients + + auth.oauth_admin.regenerate_client_secret: + status: implemented + note: "Accessible via admin.oauth.regenerate_client_secret(client_id); wired at construction time." + symbols: + - AsyncGoTrueAdminOAuthAPI.regenerate_client_secret + - SyncGoTrueAdminOAuthAPI.regenerate_client_secret + + auth.oauth_admin.update_client: + status: implemented + note: "Accessible via admin.oauth.update_client(client_id, params); wired at construction time." + symbols: + - AsyncGoTrueAdminOAuthAPI.update_client + - SyncGoTrueAdminOAuthAPI.update_client # ── Client ─────────────────────────────────────────────────────────────────