dominus-sdk-python-dev 2.4.0__py3-none-any.whl → 2.5.0__py3-none-any.whl

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.
@@ -1,323 +0,0 @@
1
- """Architect Cloud service handler - Uses Bridge API and Crossover API"""
2
- from ..helpers.core import execute_bridge_call, execute_command, DominusResponse, _ensure_valid_jwt, _b64_encode
3
- import httpx
4
-
5
- # Bridge method map: command → (bridge_method, cacheable)
6
- # User-scoped operations go through Bridge API at /api/bridge
7
- # These map to Architect's neon.* methods but with role-specific prefixes
8
- # Note: Architect will extract project_id, branch_id, db_name from JWT claims
9
- # The role parameter is derived from the command prefix (sql.app.* → role="app_user")
10
- BRIDGE_METHODS = {
11
- # App user operations (app, config schemas in dominus DB)
12
- "sql.app.list_tables": ("neon.list_tables", True),
13
- "sql.app.query_table": ("neon.query_table_data", True),
14
- "sql.app.insert_row": ("neon.insert_row", False),
15
- "sql.app.update_rows": ("neon.update_rows", False),
16
- "sql.app.delete_rows": ("neon.delete_rows", False),
17
- "sql.app.list_columns": ("neon.list_columns", True),
18
- "sql.app.get_table_size": ("neon.get_table_size", True),
19
-
20
- # Secure user operations (secure, app schemas in dominus DB)
21
- "sql.secure.list_tables": ("neon.list_tables", True),
22
- "sql.secure.query_table": ("neon.query_table_data", True),
23
- "sql.secure.insert_row": ("neon.insert_row", False),
24
- "sql.secure.update_rows": ("neon.update_rows", False),
25
- "sql.secure.delete_rows": ("neon.delete_rows", False), # Only app schema, not secure
26
- "sql.secure.list_columns": ("neon.list_columns", True),
27
- "sql.secure.get_table_size": ("neon.get_table_size", True),
28
-
29
- # Secure machine user operations (same as secure_user)
30
- "sql.secure_machine.list_tables": ("neon.list_tables", True),
31
- "sql.secure_machine.query_table": ("neon.query_table_data", True),
32
- "sql.secure_machine.insert_row": ("neon.insert_row", False),
33
- "sql.secure_machine.update_rows": ("neon.update_rows", False),
34
- "sql.secure_machine.delete_rows": ("neon.delete_rows", False),
35
- "sql.secure_machine.list_columns": ("neon.list_columns", True),
36
- "sql.secure_machine.get_table_size": ("neon.get_table_size", True),
37
-
38
- # Auth user operations (auth schema CRUD only in dominus DB)
39
- # All auth operations are NOT cached - admin UI needs fresh data
40
- # Scopes
41
- "auth.add_scope": ("auth.add_scope", False),
42
- "auth.delete_scope": ("auth.delete_scope", False),
43
- "auth.list_scopes": ("auth.list_scopes", False),
44
- "auth.get_scope": ("auth.get_scope", False),
45
- # Roles
46
- "auth.add_role": ("auth.add_role", False),
47
- "auth.delete_role": ("auth.delete_role", False),
48
- "auth.list_roles": ("auth.list_roles", False),
49
- "auth.get_role": ("auth.get_role", False),
50
- "auth.update_role_scopes": ("auth.update_role_scopes", False),
51
- # Users
52
- "auth.add_user": ("auth.add_user", False),
53
- "auth.delete_user": ("auth.delete_user", False),
54
- "auth.list_users": ("auth.list_users", False),
55
- "auth.get_user": ("auth.get_user", False),
56
- "auth.update_user_status": ("auth.update_user_status", False),
57
- "auth.update_user_role": ("auth.update_user_role", False),
58
- "auth.update_user": ("auth.update_user", False),
59
- "auth.update_user_password": ("auth.update_user_password", False),
60
- "auth.verify_user_password": ("auth.verify_user_password", False),
61
- # Clients (PSK)
62
- "auth.add_client": ("auth.add_client", False),
63
- "auth.delete_client": ("auth.delete_client", False),
64
- "auth.list_clients": ("auth.list_clients", False),
65
- "auth.get_client": ("auth.get_client", False),
66
- "auth.regenerate_client_psk": ("auth.regenerate_client_psk", False),
67
- "auth.verify_client_psk": ("auth.verify_client_psk", False),
68
- # Refresh tokens
69
- "auth.add_refresh_token": ("auth.add_refresh_token", False),
70
- "auth.delete_refresh_token": ("auth.delete_refresh_token", False),
71
- "auth.list_refresh_tokens": ("auth.list_refresh_tokens", False),
72
- # Frontend template methods
73
- "auth.check_page_access": ("auth.check_page_access", False),
74
- "auth.get_scope_navigation": ("auth.get_scope_navigation", False),
75
- "auth.get_user_navigation_scopes": ("auth.get_user_navigation_scopes", False),
76
- "auth.get_user_preferences": ("auth.get_user_preferences", False),
77
- "auth.set_user_preference": ("auth.set_user_preference", False),
78
- # Pages (auth.pages table - requires auth schema access)
79
- "auth.list_pages": ("auth.list_pages", False),
80
- "auth.get_page": ("auth.get_page", False),
81
- "auth.add_page": ("auth.add_page", False),
82
- "auth.update_page": ("auth.update_page", False),
83
- "auth.delete_page": ("auth.delete_page", False),
84
- "auth.get_page_scopes": ("auth.get_page_scopes", False),
85
- "auth.set_page_scopes": ("auth.set_page_scopes", False),
86
- # Navigation items (auth.nav_items table)
87
- "auth.list_nav_items": ("auth.list_nav_items", False),
88
- "auth.get_nav_item": ("auth.get_nav_item", False),
89
- "auth.add_nav_item": ("auth.add_nav_item", False),
90
- "auth.update_nav_item": ("auth.update_nav_item", False),
91
- "auth.delete_nav_item": ("auth.delete_nav_item", False),
92
- # Tenants (auth.tenants table)
93
- "auth.list_tenants": ("auth.list_tenants", False),
94
- "auth.get_tenant": ("auth.get_tenant", False),
95
- "auth.add_tenant": ("auth.add_tenant", False),
96
- "auth.update_tenant": ("auth.update_tenant", False),
97
- "auth.delete_tenant": ("auth.delete_tenant", False),
98
- "auth.get_tenant_users": ("auth.get_tenant_users", False),
99
- # Tenant categories (auth.tenant_categories table)
100
- "auth.list_tenant_categories": ("auth.list_tenant_categories", False),
101
- "auth.get_tenant_category": ("auth.get_tenant_category", False),
102
- "auth.add_tenant_category": ("auth.add_tenant_category", False),
103
- "auth.update_tenant_category": ("auth.update_tenant_category", False),
104
- "auth.delete_tenant_category": ("auth.delete_tenant_category", False),
105
- "auth.get_category_tenants": ("auth.get_category_tenants", False),
106
- # User junction tables (user_roles, user_scopes, user_tenants)
107
- "auth.get_user_roles": ("auth.get_user_roles", False),
108
- "auth.set_user_roles": ("auth.set_user_roles", False),
109
- "auth.get_user_scopes": ("auth.get_user_scopes", False),
110
- "auth.set_user_scopes": ("auth.set_user_scopes", False),
111
- "auth.get_user_tenants": ("auth.get_user_tenants", False),
112
- "auth.set_user_tenants": ("auth.set_user_tenants", False),
113
- # Role junction tables (role_scopes, role_tenants, role_categories)
114
- "auth.get_role_scopes": ("auth.get_role_scopes", False),
115
- "auth.set_role_tenants": ("auth.set_role_tenants", False),
116
- "auth.get_role_tenants": ("auth.get_role_tenants", False),
117
- "auth.set_role_categories": ("auth.set_role_categories", False),
118
- "auth.get_role_categories": ("auth.get_role_categories", False),
119
-
120
- # Schema user operations (DDL on app/secure, CRUD on meta in dominus DB)
121
- # App schema DDL
122
- "schema.add_table": ("schema.add_table", False),
123
- "schema.delete_table": ("schema.delete_table", False),
124
- "schema.list_tables": ("schema.list_tables", True),
125
- "schema.list_columns": ("schema.list_columns", True),
126
- "schema.add_column": ("schema.add_column", False),
127
- "schema.delete_column": ("schema.delete_column", False),
128
- # Secure schema DDL
129
- "schema.secure_add_table": ("schema.secure_add_table", False),
130
- "schema.secure_delete_table": ("schema.secure_delete_table", False),
131
- "schema.secure_list_tables": ("schema.secure_list_tables", True),
132
- "schema.secure_list_columns": ("schema.secure_list_columns", True),
133
- "schema.secure_add_column": ("schema.secure_add_column", False),
134
- "schema.secure_delete_column": ("schema.secure_delete_column", False),
135
- }
136
-
137
- # Crossover methods (admin-scoped, require admin JWT)
138
- # Note: provision_complete removed from SDK - use Architect crossover API directly
139
- CROSSOVER_METHODS = {
140
- # Placeholder for future admin-only methods
141
- # "sql.some_admin_op": ("admin.some_op", False),
142
- }
143
-
144
-
145
- async def _execute_bridge_with_sov_jwt(
146
- method: str,
147
- architect_url: str,
148
- sovereign_url: str,
149
- token: str,
150
- params: dict,
151
- cacheable: bool = False,
152
- endpoint: str = "/api/bridge",
153
- ) -> DominusResponse:
154
- """
155
- Bridge call that always mints the JWT from Sovereign but targets Architect.
156
- Avoids passing sovereign_url into execute_bridge_call for compatibility with older SDK installs.
157
- """
158
- # Mint JWT from Sovereign
159
- jwt = await _ensure_valid_jwt(token, sovereign_url)
160
-
161
- # Cache key (simple) if needed
162
- cache_key = None
163
- if cacheable and params:
164
- cache_key = f"bridge:{method}:{str(sorted(params.items()))}"
165
- from ..helpers.cache import dominus_cache
166
- cached = dominus_cache.get(cache_key)
167
- if cached:
168
- return cached
169
-
170
- # Prepare request
171
- headers = {
172
- "Authorization": f"Bearer {jwt}",
173
- "Content-Type": "text/plain",
174
- }
175
- body_b64 = _b64_encode({"method": method, "params": params})
176
-
177
- async with httpx.AsyncClient(timeout=30.0) as client:
178
- resp = await client.post(f"{architect_url}{endpoint}", content=body_b64, headers=headers)
179
- resp.raise_for_status()
180
- from ..helpers.core import _b64_decode
181
- result = _b64_decode(resp.text)
182
-
183
- if not result.get("success"):
184
- error_msg = result.get("error", "Unknown bridge error")
185
- raise RuntimeError(error_msg)
186
-
187
- data = result.get("data", {})
188
- if cache_key:
189
- dominus_cache.set(cache_key, data, ttl=300)
190
- return data
191
-
192
-
193
- async def handle(command: str, token: str, architect_url: str, sovereign_url: str, **kwargs) -> DominusResponse:
194
- """
195
- Handle Architect Cloud command.
196
-
197
- Special case: sql.open.get_dsn - fetches DSN from Sovereign (not Architect endpoint)
198
- Crossover: crossover.sql.* - admin functions via /api/crossover
199
- Bridge: sql.* - user-scoped functions via /api/bridge
200
-
201
- Args:
202
- command: Command name (e.g., "sql.app.list_tables", "crossover.sql.provision_complete")
203
- token: PSK auth token (DOMINUS_TOKEN, used to get JWT)
204
- architect_url: Architect base URL
205
- sovereign_url: Sovereign base URL (for sql.open.get_dsn)
206
- **kwargs: Command parameters
207
-
208
- Returns:
209
- Response dict
210
-
211
- Raises:
212
- ValueError: If command is unknown or missing required parameters
213
- RuntimeError: If auth token is missing
214
- """
215
- # Special case: sql.open.get_dsn - get full DSN from Architect Bridge API
216
- if command == "sql.open.get_dsn":
217
- # Route through Architect Bridge API which constructs full DSN from Infisical
218
- # Architect uses provisioning token to access Infisical secrets for the user's project
219
- return await execute_bridge_call(
220
- method="sql.open.get_dsn",
221
- base_url=architect_url,
222
- token=token,
223
- params={}, # project_slug and environment extracted from JWT by bridge route
224
- cacheable=True,
225
- endpoint="/api/bridge",
226
- sovereign_url=sovereign_url,
227
- )
228
-
229
- # Check for crossover prefix (admin functions)
230
- # Note: Most admin operations (like provisioning) should go directly to Architect
231
- # This section is reserved for future admin methods that make sense in the SDK
232
- if command.startswith("crossover.sql."):
233
- # Extract method name (remove "crossover.sql." prefix)
234
- method = command[14:] # len("crossover.sql.") = 14
235
-
236
- # Check if method is in CROSSOVER_METHODS
237
- if method not in CROSSOVER_METHODS:
238
- raise ValueError(
239
- f"Unknown crossover.sql method: {method}. "
240
- "Note: provision_complete has been removed from SDK. "
241
- "Use Architect's /api/crossover endpoint directly for provisioning."
242
- )
243
-
244
- bridge_method, cacheable = CROSSOVER_METHODS[method]
245
- return await execute_bridge_call(
246
- method=bridge_method,
247
- base_url=architect_url,
248
- token=token,
249
- params=kwargs,
250
- cacheable=cacheable,
251
- endpoint="/api/crossover",
252
- sovereign_url=sovereign_url,
253
- )
254
-
255
- # Check Bridge API methods (user-scoped operations)
256
- if command in BRIDGE_METHODS:
257
- bridge_method, cacheable = BRIDGE_METHODS[command]
258
-
259
- if command.startswith("auth."):
260
- # Auth routes already use auth_user role internally; don't add DB params that NeonService methods don't accept.
261
- # Filter out None values to avoid passing unnecessary null params that may cause issues on Architect Cloud
262
- params_with_context = {k: v for k, v in kwargs.items() if v is not None}
263
- else:
264
- # Determine role from command prefix
265
- # sql.app.* → role="app_user"
266
- # sql.secure.* → role="secure_user"
267
- # sql.secure_machine.* → role="secure_machine_user"
268
- # schema.* → role="schema_user"
269
- parts = command.split(".")
270
-
271
- if command.startswith("sql."):
272
- role_prefix = parts[1] # sql.app.list_tables -> "app"
273
- elif command.startswith("schema."):
274
- role_prefix = "schema"
275
- else:
276
- role_prefix = "app"
277
-
278
- role_mapping = {
279
- "app": "app_user",
280
- "secure": "secure_user",
281
- "secure_machine": "secure_machine_user",
282
- "auth": "auth_user",
283
- "schema": "schema_user"
284
- }
285
- db_role = role_mapping.get(role_prefix, "app_user")
286
-
287
- # Determine default schema based on role
288
- schema_defaults = {
289
- "app": "app",
290
- "secure": "secure",
291
- "secure_machine": "secure",
292
- "auth": "auth",
293
- "schema": "app" # Default to app schema for DDL, secure_ prefix overrides
294
- }
295
- default_schema = schema_defaults.get(role_prefix, "app")
296
-
297
- # Add role and default schema to params
298
- # Architect will extract project_id, branch_id, db_name from JWT
299
- params_with_context = {
300
- **kwargs,
301
- "role": db_role,
302
- "db_name": "dominus", # All user-scoped operations use dominus DB
303
- "schema": kwargs.get("schema", default_schema) # Allow override, but provide default
304
- }
305
-
306
- # Use a local helper to mint JWT from Sovereign and call Architect bridge without passing sovereign_url kwarg.
307
- return await _execute_bridge_with_sov_jwt(
308
- method=bridge_method,
309
- architect_url=architect_url,
310
- sovereign_url=sovereign_url,
311
- token=token,
312
- params=params_with_context,
313
- cacheable=cacheable,
314
- )
315
-
316
- # Unknown command
317
- all_commands = list(BRIDGE_METHODS.keys()) + ["sql.open.get_dsn"]
318
- crossover_commands = [f"crossover.sql.{cmd}" for cmd in CROSSOVER_METHODS.keys()]
319
- all_commands.extend(crossover_commands)
320
- raise ValueError(
321
- f"Unknown command: {command}. "
322
- f"Available: {all_commands}"
323
- )
@@ -1,93 +0,0 @@
1
- """Sovereign Cloud service handler - Uses Bridge API"""
2
- from ..helpers.core import execute_bridge_call, execute_with_retry, DominusResponse
3
-
4
- # Bridge method map: command → (bridge_method, cacheable)
5
- # All secrets/project operations go through the Bridge API at /newapi/bridge
6
- # Auth operations (auth.self, auth.mint, auth.jwks) are handled separately via /newapi/auth
7
- BRIDGE_METHODS = {
8
- # Secrets (via Bridge API)
9
- "secrets.get": ("secrets.get", True),
10
- "secrets.upsert": ("secrets.upsert", False),
11
- }
12
-
13
- # Legacy routes for non-bridge endpoints
14
- LEGACY_ROUTES = {
15
- # Health (public, no auth needed)
16
- "sovereign.health.ping": ("GET", "/health", False, False),
17
- "sovereign.health.ready": ("GET", "/health/ready", False, False),
18
-
19
- # Project info - TODO: migrate to Bridge API
20
- "project.info": ("POST", "/api/project/info", True, True),
21
- }
22
-
23
-
24
- async def handle(command: str, token: str, sovereign_url: str, **kwargs) -> DominusResponse:
25
- """
26
- Handle Sovereign Cloud command.
27
-
28
- Uses Bridge API for secrets operations (JWT authenticated).
29
- Uses Crossover API for cross-project operations (JWT authenticated, admin scope).
30
- Falls back to legacy routes for health checks and project info.
31
-
32
- Args:
33
- command: Command name (e.g., "secrets.get", "crossover.secrets.get")
34
- token: PSK auth token (DOMINUS_TOKEN, used to get JWT)
35
- sovereign_url: Sovereign base URL
36
- **kwargs: Command parameters
37
-
38
- Returns:
39
- Response dict
40
-
41
- Raises:
42
- ValueError: If command is unknown or missing required parameters
43
- RuntimeError: If auth token is missing
44
- """
45
- # Check for crossover prefix
46
- if command.startswith("crossover."):
47
- # Extract method name (remove "crossover." prefix)
48
- method = command[10:] # len("crossover.") = 10
49
-
50
- # Validate required parameters
51
- if "project_slug" not in kwargs:
52
- raise ValueError("crossover commands require 'project_slug' parameter")
53
- if "environment" not in kwargs:
54
- raise ValueError("crossover commands require 'environment' parameter")
55
-
56
- # Check if method is in BRIDGE_METHODS
57
- if method not in BRIDGE_METHODS:
58
- raise ValueError(f"Unknown crossover method: {method}. Available: {list(BRIDGE_METHODS.keys())}")
59
-
60
- bridge_method, cacheable = BRIDGE_METHODS[method]
61
- return await execute_bridge_call(
62
- method=bridge_method,
63
- base_url=sovereign_url,
64
- token=token,
65
- params=kwargs,
66
- cacheable=cacheable,
67
- endpoint="/newapi/crossover"
68
- )
69
-
70
- # Check Bridge API methods (own-project operations)
71
- if command in BRIDGE_METHODS:
72
- bridge_method, cacheable = BRIDGE_METHODS[command]
73
- return await execute_bridge_call(
74
- method=bridge_method,
75
- base_url=sovereign_url,
76
- token=token,
77
- params=kwargs,
78
- cacheable=cacheable
79
- )
80
-
81
- # Fall back to legacy routes
82
- if command in LEGACY_ROUTES:
83
- route_info = LEGACY_ROUTES[command]
84
- return await execute_with_retry(route_info, sovereign_url, token, kwargs)
85
-
86
- # Unknown command
87
- all_commands = list(BRIDGE_METHODS.keys()) + list(LEGACY_ROUTES.keys())
88
- crossover_commands = [f"crossover.{cmd}" for cmd in BRIDGE_METHODS.keys()]
89
- all_commands.extend(crossover_commands)
90
- raise ValueError(
91
- f"Unknown command: {command}. "
92
- f"Available: {all_commands}"
93
- )