dominus-sdk-python 9.0.13__tar.gz → 9.0.15__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/PKG-INFO +2 -2
  2. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/README.md +1 -1
  3. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/__init__.py +1 -1
  4. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/secrets.py +16 -6
  5. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/start.py +3 -1
  6. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus_sdk_python.egg-info/PKG-INFO +2 -2
  7. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/pyproject.toml +1 -1
  8. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_secrets_presence_contract.py +36 -0
  9. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_transport_compat.py +92 -0
  10. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/config/__init__.py +0 -0
  11. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/config/endpoints.py +0 -0
  12. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/contract/__init__.py +0 -0
  13. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/contract/envelope.py +0 -0
  14. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/contract/projections.py +0 -0
  15. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/errors.py +0 -0
  16. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/helpers/__init__.py +0 -0
  17. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/helpers/auth.py +0 -0
  18. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/helpers/cache.py +0 -0
  19. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/helpers/console_capture.py +0 -0
  20. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/helpers/core.py +0 -0
  21. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/helpers/crypto.py +0 -0
  22. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/helpers/sse.py +0 -0
  23. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/helpers/trace.py +0 -0
  24. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/__init__.py +0 -0
  25. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/admin.py +0 -0
  26. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/ai.py +0 -0
  27. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/artifacts.py +0 -0
  28. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/auth.py +0 -0
  29. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/authority.py +0 -0
  30. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/browser.py +0 -0
  31. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/coder.py +0 -0
  32. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/courier.py +0 -0
  33. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/db.py +0 -0
  34. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/ddl.py +0 -0
  35. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/deployer.py +0 -0
  36. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/fastapi.py +0 -0
  37. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/files.py +0 -0
  38. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/health.py +0 -0
  39. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/jobs.py +0 -0
  40. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/logs.py +0 -0
  41. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/platform.py +0 -0
  42. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/portal.py +0 -0
  43. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/processor.py +0 -0
  44. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/publisher.py +0 -0
  45. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/recipes.py +0 -0
  46. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/redis.py +0 -0
  47. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/secure.py +0 -0
  48. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/stash.py +0 -0
  49. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/sync.py +0 -0
  50. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/usage.py +0 -0
  51. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/warden.py +0 -0
  52. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/namespaces/workflow.py +0 -0
  53. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/py.typed +0 -0
  54. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus/services/__init__.py +0 -0
  55. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus_sdk_python.egg-info/SOURCES.txt +0 -0
  56. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus_sdk_python.egg-info/dependency_links.txt +0 -0
  57. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus_sdk_python.egg-info/requires.txt +0 -0
  58. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/dominus_sdk_python.egg-info/top_level.txt +0 -0
  59. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/setup.cfg +0 -0
  60. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_ai_namespace.py +0 -0
  61. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_artifacts_namespace.py +0 -0
  62. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_auth.py +0 -0
  63. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_authority_public_vocabulary.py +0 -0
  64. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_browser_namespace.py +0 -0
  65. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_contract.py +0 -0
  66. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_control_plane_namespaces.py +0 -0
  67. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_error_recovery_action.py +0 -0
  68. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_errors.py +0 -0
  69. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_errors_aliases.py +0 -0
  70. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_flat_commands.py +0 -0
  71. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_health.py +0 -0
  72. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_logs.py +0 -0
  73. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_namespace_barrel_exports.py +0 -0
  74. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_platform_coder_namespaces.py +0 -0
  75. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_provisioning_parity.py +0 -0
  76. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_public_exports.py +0 -0
  77. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_publisher_namespace.py +0 -0
  78. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_readme_quickstart_catalog.py +0 -0
  79. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_recipes_namespace.py +0 -0
  80. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_recipes_stash_routing.py +0 -0
  81. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_stash_artifact_facade.py +0 -0
  82. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_stash_tables_namespace.py +0 -0
  83. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_token_precedence.py +0 -0
  84. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_usage_namespace.py +0 -0
  85. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_version_consistency.py +0 -0
  86. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_workflow_lifecycle.py +0 -0
  87. {dominus_sdk_python-9.0.13 → dominus_sdk_python-9.0.15}/tests/test_workflow_refs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dominus-sdk-python
3
- Version: 9.0.13
3
+ Version: 9.0.15
4
4
  Summary: Python SDK for the Dominus gateway-first platform
5
5
  Author-email: CareBridge Systems <dev@carebridge.io>
6
6
  License-Expression: LicenseRef-Proprietary
@@ -48,7 +48,7 @@ cleanup audit is `docs/janitor/2026-09-19-1300-sdk-python-cleanup-audit.md`.
48
48
  - Gateway-scoped client mode for MCP and other user-JWT sessions
49
49
  - Transport compatibility for wrapped `{success,data}` responses and unwrapped Warden/control-plane success objects
50
50
  - Local helpers for JWT verification, trace propagation, retries, and console capture
51
- - Current package version: `9.0.13`
51
+ - Current package version: `9.0.15`
52
52
 
53
53
  ## Install
54
54
 
@@ -15,7 +15,7 @@ cleanup audit is `docs/janitor/2026-09-19-1300-sdk-python-cleanup-audit.md`.
15
15
  - Gateway-scoped client mode for MCP and other user-JWT sessions
16
16
  - Transport compatibility for wrapped `{success,data}` responses and unwrapped Warden/control-plane success objects
17
17
  - Local helpers for JWT verification, trace propagation, retries, and console capture
18
- - Current package version: `9.0.13`
18
+ - Current package version: `9.0.15`
19
19
 
20
20
  ## Install
21
21
 
@@ -191,7 +191,7 @@ from .errors import (
191
191
  TimeoutError as DominusTimeoutError,
192
192
  )
193
193
 
194
- __version__ = "9.0.13"
194
+ __version__ = "9.0.15"
195
195
  __all__ = [
196
196
  # Main SDK instance
197
197
  "dominus",
@@ -262,15 +262,22 @@ class SecretsNamespace:
262
262
  environment: str,
263
263
  project_id: str,
264
264
  ) -> Dict[str, Any]:
265
- """Set one Infisical secret for an environment (``POST /api/secrets/set``)."""
265
+ """Set one Infisical secret for an environment (``POST /api/secrets/set``).
266
+
267
+ The wire keys are the canonical ``target_org_id`` / ``target_env``
268
+ (PLAN T6 / board T7); secrets-core rejects the retired
269
+ ``target_project_id`` / ``environment`` aliases with a typed
270
+ ``invalid_wire_key`` validation error. The Python parameter names are
271
+ unchanged — only the request body vocabulary is canonical.
272
+ """
266
273
  return await self._client._request(
267
274
  endpoint="/api/secrets/set",
268
275
  method="POST",
269
276
  body={
270
277
  "key": key,
271
278
  "value": value,
272
- "environment": environment,
273
- "target_project_id": project_id,
279
+ "target_env": environment,
280
+ "target_org_id": project_id,
274
281
  },
275
282
  use_gateway=True,
276
283
  )
@@ -282,14 +289,17 @@ class SecretsNamespace:
282
289
  environment: str,
283
290
  project_id: str,
284
291
  ) -> Dict[str, Any]:
285
- """Delete one Infisical secret for an environment (``POST /api/secrets/delete``)."""
292
+ """Delete one Infisical secret for an environment (``POST /api/secrets/delete``).
293
+
294
+ Canonical wire keys only — see :meth:`set_project_secret`.
295
+ """
286
296
  return await self._client._request(
287
297
  endpoint="/api/secrets/delete",
288
298
  method="POST",
289
299
  body={
290
300
  "key": key,
291
- "environment": environment,
292
- "target_project_id": project_id,
301
+ "target_env": environment,
302
+ "target_org_id": project_id,
293
303
  },
294
304
  use_gateway=True,
295
305
  )
@@ -437,7 +437,9 @@ class Dominus:
437
437
  response = await client.get(endpoint)
438
438
  elif method == "DELETE":
439
439
  # Kernel wire format: same base64 JSON body as POST (Node SDK parity).
440
- response = await client.delete(endpoint, content=body_b64)
440
+ # httpx.AsyncClient.delete() accepts no body kwarg (unlike
441
+ # post/put), so use the generic verb to keep the body on the wire.
442
+ response = await client.request("DELETE", endpoint, content=body_b64)
441
443
  elif method == "PUT":
442
444
  response = await client.put(endpoint, content=body_b64)
443
445
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dominus-sdk-python
3
- Version: 9.0.13
3
+ Version: 9.0.15
4
4
  Summary: Python SDK for the Dominus gateway-first platform
5
5
  Author-email: CareBridge Systems <dev@carebridge.io>
6
6
  License-Expression: LicenseRef-Proprietary
@@ -48,7 +48,7 @@ cleanup audit is `docs/janitor/2026-09-19-1300-sdk-python-cleanup-audit.md`.
48
48
  - Gateway-scoped client mode for MCP and other user-JWT sessions
49
49
  - Transport compatibility for wrapped `{success,data}` responses and unwrapped Warden/control-plane success objects
50
50
  - Local helpers for JWT verification, trace propagation, retries, and console capture
51
- - Current package version: `9.0.13`
51
+ - Current package version: `9.0.15`
52
52
 
53
53
  ## Install
54
54
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dominus-sdk-python"
7
- version = "9.0.13"
7
+ version = "9.0.15"
8
8
  description = "Python SDK for the Dominus gateway-first platform"
9
9
  readme = "README.md"
10
10
  license = "LicenseRef-Proprietary"
@@ -120,6 +120,42 @@ async def test_malformed_responses_fail_without_raw_cell_in_error_or_logs(caplog
120
120
  assert RAW_SENTINEL not in caplog.text
121
121
 
122
122
 
123
+ @pytest.mark.asyncio
124
+ async def test_project_secret_mutations_speak_the_canonical_wire_vocabulary():
125
+ """T7 contracts the secrets request surface onto target_org_id/target_env.
126
+
127
+ dominus-secrets-core rejects the retired `target_project_id` / `environment`
128
+ aliases with a typed `invalid_wire_key` validation error instead of
129
+ silently ignoring them, so emitting either key here would 400 the call.
130
+ The Python method signatures keep their own parameter names; only the wire
131
+ body keys are canonical.
132
+ """
133
+ client = Client({"ok": True})
134
+ ns = SecretsNamespace(client)
135
+
136
+ await ns.set_project_secret(key="K", value="V", environment="production", project_id="org-1")
137
+ await ns.delete_project_secret(key="K", environment="production", project_id="org-1")
138
+
139
+ assert client.calls == [
140
+ {
141
+ "endpoint": "/api/secrets/set",
142
+ "method": "POST",
143
+ "body": {"key": "K", "value": "V", "target_env": "production", "target_org_id": "org-1"},
144
+ "use_gateway": True,
145
+ },
146
+ {
147
+ "endpoint": "/api/secrets/delete",
148
+ "method": "POST",
149
+ "body": {"key": "K", "target_env": "production", "target_org_id": "org-1"},
150
+ "use_gateway": True,
151
+ },
152
+ ]
153
+
154
+ for call in client.calls:
155
+ assert "target_project_id" not in call["body"]
156
+ assert "environment" not in call["body"]
157
+
158
+
123
159
  def test_public_types_and_return_annotation_are_exact():
124
160
  from dominus import SecretEnvironment, SecretPresenceCell, SecretPresenceGrid
125
161
  from dominus.namespaces import (
@@ -1,3 +1,4 @@
1
+ import base64
1
2
  import json
2
3
  import sys
3
4
  from pathlib import Path
@@ -56,6 +57,51 @@ class RequestClient:
56
57
  return FakeResponse(json.dumps({"success": True, "data": {"ok": True}}))
57
58
 
58
59
 
60
+ class HttpxFaithfulDeleteClient:
61
+ """Fake AsyncClient whose ``delete()`` mirrors httpx's real signature.
62
+
63
+ httpx.AsyncClient.delete() takes no body kwarg (unlike post/put), so a fake
64
+ that tolerated ``content=`` here would silently mask the very regression
65
+ these tests exist to catch. ``request()`` is the body-capable generic verb.
66
+ """
67
+
68
+ calls = []
69
+
70
+ def __init__(self, *, base_url, headers, timeout):
71
+ self.base_url = base_url
72
+ self.headers = headers
73
+ self.timeout = timeout
74
+
75
+ async def __aenter__(self):
76
+ return self
77
+
78
+ async def __aexit__(self, exc_type, exc, tb):
79
+ return False
80
+
81
+ async def delete(self, endpoint, *, params=None, headers=None, cookies=None):
82
+ # Exact httpx 0.28 surface: no content/json/data parameter.
83
+ raise AssertionError(
84
+ "_request() must not send a body through httpx's body-less delete(); "
85
+ "use client.request('DELETE', ...) instead"
86
+ )
87
+
88
+ async def get(self, endpoint):
89
+ self.calls.append({"method": "GET", "endpoint": endpoint, "content": None})
90
+ return FakeResponse(json.dumps({"success": True, "data": {"ok": True}}))
91
+
92
+ async def post(self, endpoint, content=None):
93
+ self.calls.append({"method": "POST", "endpoint": endpoint, "content": content})
94
+ return FakeResponse(json.dumps({"success": True, "data": {"ok": True}}))
95
+
96
+ async def put(self, endpoint, content=None):
97
+ self.calls.append({"method": "PUT", "endpoint": endpoint, "content": content})
98
+ return FakeResponse(json.dumps({"success": True, "data": {"ok": True}}))
99
+
100
+ async def request(self, method, endpoint, *, content=None, **kwargs):
101
+ self.calls.append({"method": method, "endpoint": endpoint, "content": content})
102
+ return FakeResponse(json.dumps({"success": True, "data": {"ok": True}}))
103
+
104
+
59
105
  class UnwrappedRequestClient:
60
106
  calls = []
61
107
 
@@ -199,6 +245,52 @@ async def test_request_accepts_raw_json_success_envelope(monkeypatch, sdk):
199
245
  assert RequestClient.calls[0]["endpoint"] == "/svc/health"
200
246
 
201
247
 
248
+ @pytest.mark.asyncio
249
+ async def test_guardian_delete_reaches_transport_with_body(monkeypatch, sdk):
250
+ """Regression: guardian_delete (no explicit body) hit httpx's delete() kwarg wall.
251
+
252
+ Live failure 2026-09-22: AsyncClient.delete() got an unexpected keyword
253
+ argument 'content' -- every DELETE through _request raised TypeError.
254
+ """
255
+ HttpxFaithfulDeleteClient.calls = []
256
+
257
+ async def fake_ensure_valid_jwt(psk_token, base_url):
258
+ return "jwt-abc"
259
+
260
+ monkeypatch.setattr(core_module, "_ensure_valid_jwt", fake_ensure_valid_jwt)
261
+ monkeypatch.setattr(start_module.httpx, "AsyncClient", HttpxFaithfulDeleteClient)
262
+
263
+ result = await sdk.auth.guardian_delete("tenants", "5d05b96e-0aef-4dbf-a4dc-19354da9f58e")
264
+
265
+ assert result == {"ok": True}
266
+ call = HttpxFaithfulDeleteClient.calls[0]
267
+ assert call["method"] == "DELETE"
268
+ assert call["endpoint"] == "/svc/guardian/tenants/5d05b96e-0aef-4dbf-a4dc-19354da9f58e"
269
+ assert call["content"] == base64.b64encode(json.dumps({}).encode()).decode()
270
+
271
+
272
+ @pytest.mark.asyncio
273
+ async def test_non_guardian_delete_reaches_transport_with_body(monkeypatch, sdk):
274
+ """Same shared _request path, non-guardian namespace, real body on the wire."""
275
+ HttpxFaithfulDeleteClient.calls = []
276
+
277
+ async def fake_ensure_valid_jwt(psk_token, base_url):
278
+ return "jwt-abc"
279
+
280
+ monkeypatch.setattr(core_module, "_ensure_valid_jwt", fake_ensure_valid_jwt)
281
+ monkeypatch.setattr(start_module.httpx, "AsyncClient", HttpxFaithfulDeleteClient)
282
+
283
+ result = await sdk.ddl.drop_table("public", "widgets")
284
+
285
+ assert result == {"ok": True}
286
+ call = HttpxFaithfulDeleteClient.calls[0]
287
+ assert call["method"] == "DELETE"
288
+ assert call["endpoint"] == "/svc/smith/schema/drop-table"
289
+ assert call["content"] == base64.b64encode(
290
+ json.dumps({"schema": "public", "table": "widgets"}).encode()
291
+ ).decode()
292
+
293
+
202
294
  @pytest.mark.asyncio
203
295
  async def test_request_accepts_unwrapped_control_plane_success(monkeypatch, sdk):
204
296
  UnwrappedRequestClient.calls = []