dominus-sdk-python 3.0.3__tar.gz → 3.0.4__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 (58) hide show
  1. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/PKG-INFO +4 -2
  2. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/README.md +3 -1
  3. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/__init__.py +4 -0
  4. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/__init__.py +4 -0
  5. dominus_sdk_python-3.0.4/dominus/namespaces/deployer.py +39 -0
  6. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/sync.py +6 -6
  7. dominus_sdk_python-3.0.4/dominus/namespaces/warden.py +39 -0
  8. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/start.py +131 -0
  9. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus_sdk_python.egg-info/PKG-INFO +4 -2
  10. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus_sdk_python.egg-info/SOURCES.txt +3 -0
  11. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/pyproject.toml +1 -1
  12. dominus_sdk_python-3.0.4/tests/test_control_plane_namespaces.py +49 -0
  13. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/tests/test_public_exports.py +8 -1
  14. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/tests/test_workflow_lifecycle.py +2 -2
  15. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/config/__init__.py +0 -0
  16. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/config/endpoints.py +0 -0
  17. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/errors.py +0 -0
  18. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/helpers/__init__.py +0 -0
  19. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/helpers/auth.py +0 -0
  20. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/helpers/cache.py +0 -0
  21. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/helpers/console_capture.py +0 -0
  22. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/helpers/core.py +0 -0
  23. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/helpers/crypto.py +0 -0
  24. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/helpers/sse.py +0 -0
  25. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/helpers/trace.py +0 -0
  26. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/admin.py +0 -0
  27. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/ai.py +0 -0
  28. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/artifacts.py +0 -0
  29. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/auth.py +0 -0
  30. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/authority.py +0 -0
  31. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/courier.py +0 -0
  32. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/db.py +0 -0
  33. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/ddl.py +0 -0
  34. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/fastapi.py +0 -0
  35. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/files.py +0 -0
  36. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/health.py +0 -0
  37. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/jobs.py +0 -0
  38. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/logs.py +0 -0
  39. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/portal.py +0 -0
  40. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/processor.py +0 -0
  41. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/redis.py +0 -0
  42. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/secrets.py +0 -0
  43. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/secure.py +0 -0
  44. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/namespaces/workflow.py +0 -0
  45. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus/services/__init__.py +0 -0
  46. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus_sdk_python.egg-info/dependency_links.txt +0 -0
  47. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus_sdk_python.egg-info/requires.txt +0 -0
  48. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/dominus_sdk_python.egg-info/top_level.txt +0 -0
  49. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/setup.cfg +0 -0
  50. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/tests/test_auth.py +0 -0
  51. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/tests/test_authority_public_vocabulary.py +0 -0
  52. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/tests/test_errors.py +0 -0
  53. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/tests/test_flat_commands.py +0 -0
  54. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/tests/test_health.py +0 -0
  55. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/tests/test_logs.py +0 -0
  56. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/tests/test_provisioning_parity.py +0 -0
  57. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/tests/test_transport_compat.py +0 -0
  58. {dominus_sdk_python-3.0.3 → dominus_sdk_python-3.0.4}/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: 3.0.3
3
+ Version: 3.0.4
4
4
  Summary: Python SDK for the Dominus gateway-first platform
5
5
  Author-email: CareBridge Systems <dev@carebridge.io>
6
6
  License: Proprietary
@@ -41,7 +41,7 @@ Async Python SDK for the Dominus gateway-first service plane.
41
41
  - Namespace-first API with a small root shortcut surface
42
42
  - Gateway-scoped client mode for MCP and other user-JWT sessions
43
43
  - Local helpers for JWT verification, trace propagation, retries, and console capture
44
- - Current package version: `3.0.2`
44
+ - Current package version: `3.0.4`
45
45
 
46
46
  ## Install
47
47
 
@@ -126,6 +126,8 @@ JWT and selected scope headers directly through Gateway.
126
126
  | `processor` | Processor | Batch and single-job processing |
127
127
  | `sync` | Sync Worker | KV synchronization |
128
128
  | `authority` | Dominus Authority | Runs, companies, deploys, managed clients, context |
129
+ | `deployer` | Deployer | Thin operator control-plane request surface |
130
+ | `warden` | Warden | Thin operator control-plane request surface |
129
131
  | `fastapi` | Local decorators | `@jwt`, `@psk`, `@scopes(...)` |
130
132
 
131
133
  ## Root Shortcuts
@@ -8,7 +8,7 @@ Async Python SDK for the Dominus gateway-first service plane.
8
8
  - Namespace-first API with a small root shortcut surface
9
9
  - Gateway-scoped client mode for MCP and other user-JWT sessions
10
10
  - Local helpers for JWT verification, trace propagation, retries, and console capture
11
- - Current package version: `3.0.2`
11
+ - Current package version: `3.0.4`
12
12
 
13
13
  ## Install
14
14
 
@@ -93,6 +93,8 @@ JWT and selected scope headers directly through Gateway.
93
93
  | `processor` | Processor | Batch and single-job processing |
94
94
  | `sync` | Sync Worker | KV synchronization |
95
95
  | `authority` | Dominus Authority | Runs, companies, deploys, managed clients, context |
96
+ | `deployer` | Deployer | Thin operator control-plane request surface |
97
+ | `warden` | Warden | Thin operator control-plane request surface |
96
98
  | `fastapi` | Local decorators | `@jwt`, `@psk`, `@scopes(...)` |
97
99
 
98
100
  ## Root Shortcuts
@@ -111,6 +111,8 @@ from .namespaces.jobs import JobsNamespace
111
111
  from .namespaces.processor import ProcessorNamespace
112
112
  from .namespaces.sync import SyncNamespace
113
113
  from .namespaces.authority import AuthorityNamespace
114
+ from .namespaces.deployer import DeployerNamespace
115
+ from .namespaces.warden import WardenNamespace
114
116
 
115
117
  # Export AI namespace for agent-runtime operations
116
118
  from .namespaces.ai import (
@@ -211,6 +213,8 @@ __all__ = [
211
213
  "ProcessorNamespace",
212
214
  "SyncNamespace",
213
215
  "AuthorityNamespace",
216
+ "DeployerNamespace",
217
+ "WardenNamespace",
214
218
  # AI namespace for agent-runtime operations
215
219
  "AiNamespace",
216
220
  "RagSubNamespace",
@@ -15,6 +15,8 @@ from .jobs import JobsNamespace
15
15
  from .processor import ProcessorNamespace
16
16
  from .sync import SyncNamespace
17
17
  from .authority import AuthorityNamespace
18
+ from .deployer import DeployerNamespace
19
+ from .warden import WardenNamespace
18
20
  from .ai import (
19
21
  AiNamespace,
20
22
  RagSubNamespace,
@@ -40,6 +42,8 @@ __all__ = [
40
42
  "ProcessorNamespace",
41
43
  "SyncNamespace",
42
44
  "AuthorityNamespace",
45
+ "DeployerNamespace",
46
+ "WardenNamespace",
43
47
  "AiNamespace",
44
48
  "RagSubNamespace",
45
49
  "ArtifactsSubNamespace",
@@ -0,0 +1,39 @@
1
+ """Thin Deployer control-plane namespace."""
2
+ from typing import Any, Dict, Optional, TYPE_CHECKING
3
+
4
+ if TYPE_CHECKING:
5
+ from ..start import Dominus
6
+
7
+
8
+ def _normalize_deployer_path(path: str) -> str:
9
+ trimmed = path.strip()
10
+ normalized = trimmed if trimmed.startswith("/") else f"/{trimmed}"
11
+ if normalized == "/svc/deployer" or normalized.startswith("/svc/deployer/"):
12
+ return normalized
13
+ if normalized == "/api/deployer" or normalized.startswith("/api/deployer/"):
14
+ return normalized
15
+ return f"/svc/deployer{normalized}"
16
+
17
+
18
+ class DeployerNamespace:
19
+ """Deployer operator control-plane routes used by Mothership and MCP."""
20
+
21
+ def __init__(self, client: "Dominus"):
22
+ self._client = client
23
+
24
+ async def request(
25
+ self,
26
+ path: str,
27
+ *,
28
+ method: str = "GET",
29
+ body: Any = None,
30
+ headers: Optional[Dict[str, str]] = None,
31
+ timeout: float = 30.0,
32
+ ) -> Any:
33
+ return await self._client.gateway_fetch(
34
+ _normalize_deployer_path(path),
35
+ method=method,
36
+ body=body,
37
+ headers=headers,
38
+ timeout=timeout,
39
+ )
@@ -1,7 +1,7 @@
1
1
  """
2
2
  Sync Namespace - KV synchronization operations.
3
3
 
4
- Provides manual trigger for KV sync (token + project metadata)
4
+ Provides manual trigger for KV sync (token + app metadata)
5
5
  from database to Cloudflare KV. Routes through gateway to sync-worker.
6
6
 
7
7
  The sync worker also runs automatically at 4AM UTC via cron.
@@ -11,7 +11,7 @@ Usage:
11
11
 
12
12
  # Trigger manual sync (admin only)
13
13
  result = await dominus.sync.trigger_sync()
14
- print(f"Synced {result['tokens_synced']} tokens, {result['projects_synced']} projects")
14
+ print(f"Synced {result['tokens_synced']} tokens, {result['apps_synced']} apps")
15
15
 
16
16
  # Health check
17
17
  health = await dominus.sync.get_health()
@@ -26,7 +26,7 @@ class SyncNamespace:
26
26
  """
27
27
  KV sync namespace.
28
28
 
29
- Admin-only operations that synchronize token hashes and project
29
+ Admin-only operations that synchronize token hashes and app
30
30
  metadata from the database into Cloudflare KV. Purges stale
31
31
  entries and re-seeds current data.
32
32
  """
@@ -54,15 +54,15 @@ class SyncNamespace:
54
54
  """
55
55
  Trigger a manual KV sync. Requires admin system level.
56
56
 
57
- Synchronizes token hashes and project metadata from the database
57
+ Synchronizes token hashes and app metadata from the database
58
58
  into Cloudflare KV. Purges stale entries and re-seeds current data.
59
59
 
60
60
  Args:
61
61
  timeout: Request timeout in seconds (default 60; Mothership uses 180).
62
62
 
63
63
  Returns:
64
- {tokens_synced, projects_synced, tokens_deleted,
65
- projects_deleted, errors, duration_ms, triggered_at}
64
+ {tokens_synced, apps_synced, tokens_deleted,
65
+ apps_deleted, errors, duration_ms, triggered_at}
66
66
  """
67
67
  return await self._api(
68
68
  "/api/sync/",
@@ -0,0 +1,39 @@
1
+ """Thin Warden control-plane namespace."""
2
+ from typing import Any, Dict, Optional, TYPE_CHECKING
3
+
4
+ if TYPE_CHECKING:
5
+ from ..start import Dominus
6
+
7
+
8
+ def _normalize_warden_path(path: str) -> str:
9
+ trimmed = path.strip()
10
+ normalized = trimmed if trimmed.startswith("/") else f"/{trimmed}"
11
+ if normalized == "/svc/warden" or normalized.startswith("/svc/warden/"):
12
+ return normalized
13
+ if normalized == "/api/warden" or normalized.startswith("/api/warden/"):
14
+ return normalized
15
+ return f"/svc/warden{normalized}"
16
+
17
+
18
+ class WardenNamespace:
19
+ """Warden operator control-plane routes used by Mothership and MCP."""
20
+
21
+ def __init__(self, client: "Dominus"):
22
+ self._client = client
23
+
24
+ async def request(
25
+ self,
26
+ path: str,
27
+ *,
28
+ method: str = "GET",
29
+ body: Any = None,
30
+ headers: Optional[Dict[str, str]] = None,
31
+ timeout: float = 30.0,
32
+ ) -> Any:
33
+ return await self._client.gateway_fetch(
34
+ _normalize_warden_path(path),
35
+ method=method,
36
+ body=body,
37
+ headers=headers,
38
+ timeout=timeout,
39
+ )
@@ -172,6 +172,12 @@ class Dominus:
172
172
  from .namespaces.authority import AuthorityNamespace
173
173
  self.authority = AuthorityNamespace(self)
174
174
 
175
+ # Thin operator control-plane namespaces (Mothership / MCP parity)
176
+ from .namespaces.deployer import DeployerNamespace
177
+ from .namespaces.warden import WardenNamespace
178
+ self.deployer = DeployerNamespace(self)
179
+ self.warden = WardenNamespace(self)
180
+
175
181
  # Cache for JWT public key
176
182
  self._public_key_cache = None
177
183
 
@@ -475,6 +481,131 @@ class Dominus:
475
481
 
476
482
  return result.get("data", {})
477
483
 
484
+ async def gateway_fetch(
485
+ self,
486
+ path: str,
487
+ *,
488
+ method: str = "GET",
489
+ body: Optional[Dict[str, Any]] = None,
490
+ headers: Optional[Dict[str, str]] = None,
491
+ timeout: float = 30.0,
492
+ ) -> Any:
493
+ """Gateway `/svc/*` fetch with mixed JSON/base64 wire handling.
494
+
495
+ Mirrors the Node SDK `DominusClient.gatewayFetch()` contract so Python
496
+ callers can use the same remaining operator control-plane surfaces.
497
+ """
498
+ await self._ensure_ready()
499
+ from .helpers.core import _ensure_valid_jwt
500
+ jwt = await _ensure_valid_jwt(_TOKEN, _BASE_URL)
501
+
502
+ path = path.strip()
503
+ if not path.startswith("/"):
504
+ path = f"/{path}"
505
+
506
+ is_base64 = (
507
+ "/svc/warden/secrets" in path
508
+ or "/svc/secrets/" in path
509
+ or "/svc/admin/" in path
510
+ )
511
+ decode_base64 = (
512
+ is_base64
513
+ or "/svc/database/" in path
514
+ or "/svc/sync/" in path
515
+ or "/svc/authority/" in path
516
+ )
517
+ is_get = method.upper() in {"GET", "HEAD"}
518
+
519
+ from .helpers.trace import get_current_trace_id, get_current_span_id
520
+
521
+ req_headers = {
522
+ "Authorization": f"Bearer {jwt}",
523
+ "X-Trace-Id": get_current_trace_id(),
524
+ "X-Parent-Span-Id": get_current_span_id(),
525
+ }
526
+ if headers:
527
+ req_headers.update(headers)
528
+
529
+ request_content = None
530
+ request_json = None
531
+ if not is_get and body is not None:
532
+ if is_base64:
533
+ req_headers["Content-Type"] = "text/plain"
534
+ request_content = base64.b64encode(json.dumps(body).encode()).decode()
535
+ else:
536
+ req_headers["Content-Type"] = "application/json"
537
+ request_json = body
538
+
539
+ try:
540
+ async with httpx.AsyncClient(base_url=_GATEWAY_URL, headers=req_headers, timeout=timeout) as client:
541
+ response = await client.request(
542
+ method.upper(),
543
+ path,
544
+ content=request_content,
545
+ json=request_json,
546
+ )
547
+ except httpx.TimeoutException as exc:
548
+ raise DominusTimeoutError("Request timed out", endpoint=path) from exc
549
+ except httpx.NetworkError as exc:
550
+ raise DominusConnectionError(f"Request failed: {exc}", endpoint=path) from exc
551
+
552
+ def _decode_error_payload(text: str) -> Dict[str, Any]:
553
+ if not text:
554
+ return {}
555
+ try:
556
+ from .helpers.core import _decode_json_or_b64_json
557
+
558
+ decoded = _decode_json_or_b64_json(text)
559
+ return decoded if isinstance(decoded, dict) else {"detail": decoded}
560
+ except Exception:
561
+ return {"detail": text}
562
+
563
+ if response.is_error:
564
+ error_payload = _decode_error_payload(response.text)
565
+ nested = error_payload.get("error")
566
+ nested_err: Dict[str, Any] = nested if isinstance(nested, dict) else {}
567
+ error_message = (
568
+ error_payload.get("message")
569
+ or (nested_err.get("message") if nested_err else None)
570
+ or (nested if isinstance(nested, str) else None)
571
+ or error_payload.get("error")
572
+ or error_payload.get("detail")
573
+ or f"HTTP {response.status_code}"
574
+ )
575
+ error_details = error_payload.get("details")
576
+ if not isinstance(error_details, dict):
577
+ error_details = {}
578
+ for src in (error_payload, nested_err):
579
+ for key in ("code", "category", "retryable", "trace_id", "request_id"):
580
+ if key in src and key not in error_details:
581
+ error_details[key] = src[key]
582
+ raise_for_status(response.status_code, str(error_message), error_details, path)
583
+
584
+ text = response.text.strip()
585
+ if not text:
586
+ return {}
587
+
588
+ if decode_base64:
589
+ decoded = base64.b64decode(text.encode("utf-8")).decode("utf-8")
590
+ result = json.loads(decoded)
591
+ else:
592
+ try:
593
+ result = json.loads(text)
594
+ except json.JSONDecodeError:
595
+ return text
596
+
597
+ if isinstance(result, dict) and result.get("success") is False:
598
+ error_msg = result.get("error") or result.get("message") or "Unknown error"
599
+ error_details = result.get("details")
600
+ if not isinstance(error_details, dict):
601
+ error_details = {}
602
+ for key in ("code", "category", "retryable", "trace_id", "request_id"):
603
+ if key in result:
604
+ error_details[key] = result[key]
605
+ raise DominusError(str(error_msg), details=error_details, endpoint=path)
606
+
607
+ return result
608
+
478
609
  async def _stream_request(
479
610
  self,
480
611
  endpoint: str,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dominus-sdk-python
3
- Version: 3.0.3
3
+ Version: 3.0.4
4
4
  Summary: Python SDK for the Dominus gateway-first platform
5
5
  Author-email: CareBridge Systems <dev@carebridge.io>
6
6
  License: Proprietary
@@ -41,7 +41,7 @@ Async Python SDK for the Dominus gateway-first service plane.
41
41
  - Namespace-first API with a small root shortcut surface
42
42
  - Gateway-scoped client mode for MCP and other user-JWT sessions
43
43
  - Local helpers for JWT verification, trace propagation, retries, and console capture
44
- - Current package version: `3.0.2`
44
+ - Current package version: `3.0.4`
45
45
 
46
46
  ## Install
47
47
 
@@ -126,6 +126,8 @@ JWT and selected scope headers directly through Gateway.
126
126
  | `processor` | Processor | Batch and single-job processing |
127
127
  | `sync` | Sync Worker | KV synchronization |
128
128
  | `authority` | Dominus Authority | Runs, companies, deploys, managed clients, context |
129
+ | `deployer` | Deployer | Thin operator control-plane request surface |
130
+ | `warden` | Warden | Thin operator control-plane request surface |
129
131
  | `fastapi` | Local decorators | `@jwt`, `@psk`, `@scopes(...)` |
130
132
 
131
133
  ## Root Shortcuts
@@ -22,6 +22,7 @@ dominus/namespaces/authority.py
22
22
  dominus/namespaces/courier.py
23
23
  dominus/namespaces/db.py
24
24
  dominus/namespaces/ddl.py
25
+ dominus/namespaces/deployer.py
25
26
  dominus/namespaces/fastapi.py
26
27
  dominus/namespaces/files.py
27
28
  dominus/namespaces/health.py
@@ -33,6 +34,7 @@ dominus/namespaces/redis.py
33
34
  dominus/namespaces/secrets.py
34
35
  dominus/namespaces/secure.py
35
36
  dominus/namespaces/sync.py
37
+ dominus/namespaces/warden.py
36
38
  dominus/namespaces/workflow.py
37
39
  dominus/services/__init__.py
38
40
  dominus_sdk_python.egg-info/PKG-INFO
@@ -42,6 +44,7 @@ dominus_sdk_python.egg-info/requires.txt
42
44
  dominus_sdk_python.egg-info/top_level.txt
43
45
  tests/test_auth.py
44
46
  tests/test_authority_public_vocabulary.py
47
+ tests/test_control_plane_namespaces.py
45
48
  tests/test_errors.py
46
49
  tests/test_flat_commands.py
47
50
  tests/test_health.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dominus-sdk-python"
7
- version = "3.0.3"
7
+ version = "3.0.4"
8
8
  description = "Python SDK for the Dominus gateway-first platform"
9
9
  readme = "README.md"
10
10
  license = {text = "Proprietary"}
@@ -0,0 +1,49 @@
1
+ import pytest
2
+
3
+ import dominus.start as start_module
4
+
5
+
6
+ @pytest.fixture()
7
+ def sdk(monkeypatch):
8
+ monkeypatch.setattr(start_module, "_VALIDATION_ERROR", None)
9
+ monkeypatch.setattr(start_module, "_TOKEN", "a" * 64)
10
+ monkeypatch.setattr(start_module, "_VALIDATED", False)
11
+ monkeypatch.setattr(start_module, "_BASE_URL", "https://gateway.example")
12
+ monkeypatch.setattr(start_module, "_GATEWAY_URL", "https://gateway.example")
13
+ return start_module.Dominus()
14
+
15
+
16
+ @pytest.mark.asyncio
17
+ async def test_deployer_namespace_uses_gateway_fetch(monkeypatch, sdk):
18
+ calls = []
19
+
20
+ async def fake_gateway_fetch(path, **kwargs):
21
+ calls.append((path, kwargs))
22
+ return {"ok": True}
23
+
24
+ monkeypatch.setattr(sdk, "gateway_fetch", fake_gateway_fetch)
25
+
26
+ result = await sdk.deployer.request("/deployments/active", method="GET")
27
+
28
+ assert result == {"ok": True}
29
+ assert calls == [
30
+ ("/svc/deployer/deployments/active", {"method": "GET", "body": None, "headers": None, "timeout": 30.0})
31
+ ]
32
+
33
+
34
+ @pytest.mark.asyncio
35
+ async def test_warden_namespace_preserves_explicit_service_path(monkeypatch, sdk):
36
+ calls = []
37
+
38
+ async def fake_gateway_fetch(path, **kwargs):
39
+ calls.append((path, kwargs))
40
+ return {"ok": True}
41
+
42
+ monkeypatch.setattr(sdk, "gateway_fetch", fake_gateway_fetch)
43
+
44
+ result = await sdk.warden.request("/svc/warden/users/example", method="DELETE")
45
+
46
+ assert result == {"ok": True}
47
+ assert calls == [
48
+ ("/svc/warden/users/example", {"method": "DELETE", "body": None, "headers": None, "timeout": 30.0})
49
+ ]
@@ -1,4 +1,9 @@
1
- from dominus import gateway_circuit_breaker, mint_selected_scope_jwt
1
+ from dominus import (
2
+ DeployerNamespace,
3
+ WardenNamespace,
4
+ gateway_circuit_breaker,
5
+ mint_selected_scope_jwt,
6
+ )
2
7
 
3
8
 
4
9
  def test_top_level_exports_drop_delegate_alias():
@@ -22,3 +27,5 @@ def test_top_level_exports_drop_delegate_alias():
22
27
  OpenNamespace = None
23
28
 
24
29
  assert OpenNamespace is None
30
+ assert DeployerNamespace is not None
31
+ assert WardenNamespace is not None
@@ -269,8 +269,8 @@ async def test_workflow_ensure_supports_authority_one_call_lifecycle():
269
269
  assert body["subject"] == "PCM47474562"
270
270
  assert body["company"] == "summit-radiology"
271
271
  assert body["inputs"] == {"report_snapshot": "ar://artifact"}
272
- assert body["target_project_id"] == "proj-1"
273
- assert body["target_environment"] == "production"
272
+ assert body["target_org_id"] == "proj-1"
273
+ assert body["target_env"] == "production"
274
274
  assert isinstance(body["idempotency_key"], str) and body["idempotency_key"]
275
275
 
276
276