dominus-sdk-python 4.6.2__tar.gz → 5.1.0__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.
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/PKG-INFO +9 -3
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/README.md +8 -2
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/__init__.py +1 -7
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/artifacts.py +10 -27
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/authority.py +64 -61
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/workflow.py +40 -8
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/start.py +1 -1
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus_sdk_python.egg-info/PKG-INFO +9 -3
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/pyproject.toml +1 -1
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_authority_public_vocabulary.py +64 -22
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_workflow_lifecycle.py +17 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_workflow_refs.py +42 -1
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/config/__init__.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/config/endpoints.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/errors.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/helpers/__init__.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/helpers/auth.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/helpers/cache.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/helpers/console_capture.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/helpers/core.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/helpers/crypto.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/helpers/sse.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/helpers/trace.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/__init__.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/admin.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/ai.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/auth.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/browser.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/courier.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/db.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/ddl.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/deployer.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/fastapi.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/files.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/health.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/jobs.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/logs.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/portal.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/processor.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/recipes.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/redis.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/secrets.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/secure.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/stash.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/sync.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/namespaces/warden.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus/services/__init__.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus_sdk_python.egg-info/SOURCES.txt +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus_sdk_python.egg-info/dependency_links.txt +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus_sdk_python.egg-info/requires.txt +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus_sdk_python.egg-info/top_level.txt +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/setup.cfg +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_auth.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_browser_namespace.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_control_plane_namespaces.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_errors.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_flat_commands.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_health.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_logs.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_provisioning_parity.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_public_exports.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_recipes_namespace.py +0 -0
- {dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_transport_compat.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dominus-sdk-python
|
|
3
|
-
Version:
|
|
3
|
+
Version: 5.1.0
|
|
4
4
|
Summary: Python SDK for the Dominus gateway-first platform
|
|
5
5
|
Author-email: CareBridge Systems <dev@carebridge.io>
|
|
6
6
|
License: Proprietary
|
|
@@ -43,7 +43,7 @@ Async Python SDK for the Dominus gateway-first service plane.
|
|
|
43
43
|
- Gateway-scoped client mode for MCP and other user-JWT sessions
|
|
44
44
|
- Transport compatibility for wrapped `{success,data}` responses and unwrapped Warden/control-plane success objects
|
|
45
45
|
- Local helpers for JWT verification, trace propagation, retries, and console capture
|
|
46
|
-
- Current package version: `
|
|
46
|
+
- Current package version: `5.1.0`
|
|
47
47
|
|
|
48
48
|
## Install
|
|
49
49
|
|
|
@@ -71,6 +71,12 @@ run = await dominus.workflow.ensure(
|
|
|
71
71
|
company="summit-radiology",
|
|
72
72
|
)
|
|
73
73
|
|
|
74
|
+
recipe_run = await dominus.workflow.ensure(
|
|
75
|
+
workflow_recipe_ref="recipe://workflow-recipe-v1/report-cycle@v3",
|
|
76
|
+
subject="PCM47474562",
|
|
77
|
+
company="summit-radiology",
|
|
78
|
+
)
|
|
79
|
+
|
|
74
80
|
timeline = await dominus.authority.get_run_timeline(
|
|
75
81
|
run["run_id"],
|
|
76
82
|
since="2026-04-11T08:33:00Z",
|
|
@@ -198,7 +204,7 @@ JWT and selected scope headers directly through Gateway.
|
|
|
198
204
|
| `jobs` | Job Worker | Enqueue, poll, dead-letter management |
|
|
199
205
|
| `processor` | Processor | Batch and single-job processing |
|
|
200
206
|
| `sync` | Sync Worker | KV synchronization |
|
|
201
|
-
| `authority` | Dominus Authority | Runs,
|
|
207
|
+
| `authority` | Dominus Authority | Runs, provisioning targets, deploys, managed clients, context |
|
|
202
208
|
| `browser` | Browser Worker | Browser run health, ensure/start/status/result/retry/nudge/cancel/timeline/dossier |
|
|
203
209
|
| `deployer` | Deployer | Thin operator control-plane request surface |
|
|
204
210
|
| `warden` | Warden | Thin operator control-plane request surface |
|
|
@@ -9,7 +9,7 @@ Async Python SDK for the Dominus gateway-first service plane.
|
|
|
9
9
|
- Gateway-scoped client mode for MCP and other user-JWT sessions
|
|
10
10
|
- Transport compatibility for wrapped `{success,data}` responses and unwrapped Warden/control-plane success objects
|
|
11
11
|
- Local helpers for JWT verification, trace propagation, retries, and console capture
|
|
12
|
-
- Current package version: `
|
|
12
|
+
- Current package version: `5.1.0`
|
|
13
13
|
|
|
14
14
|
## Install
|
|
15
15
|
|
|
@@ -37,6 +37,12 @@ run = await dominus.workflow.ensure(
|
|
|
37
37
|
company="summit-radiology",
|
|
38
38
|
)
|
|
39
39
|
|
|
40
|
+
recipe_run = await dominus.workflow.ensure(
|
|
41
|
+
workflow_recipe_ref="recipe://workflow-recipe-v1/report-cycle@v3",
|
|
42
|
+
subject="PCM47474562",
|
|
43
|
+
company="summit-radiology",
|
|
44
|
+
)
|
|
45
|
+
|
|
40
46
|
timeline = await dominus.authority.get_run_timeline(
|
|
41
47
|
run["run_id"],
|
|
42
48
|
since="2026-04-11T08:33:00Z",
|
|
@@ -164,7 +170,7 @@ JWT and selected scope headers directly through Gateway.
|
|
|
164
170
|
| `jobs` | Job Worker | Enqueue, poll, dead-letter management |
|
|
165
171
|
| `processor` | Processor | Batch and single-job processing |
|
|
166
172
|
| `sync` | Sync Worker | KV synchronization |
|
|
167
|
-
| `authority` | Dominus Authority | Runs,
|
|
173
|
+
| `authority` | Dominus Authority | Runs, provisioning targets, deploys, managed clients, context |
|
|
168
174
|
| `browser` | Browser Worker | Browser run health, ensure/start/status/result/retry/nudge/cancel/timeline/dossier |
|
|
169
175
|
| `deployer` | Deployer | Thin operator control-plane request surface |
|
|
170
176
|
| `warden` | Warden | Thin operator control-plane request surface |
|
|
@@ -90,14 +90,12 @@ from .namespaces.health import HealthNamespace
|
|
|
90
90
|
# Export new namespaces (Node.js SDK parity)
|
|
91
91
|
from .namespaces.artifacts import (
|
|
92
92
|
ARTIFACT_REF_PREFIX,
|
|
93
|
-
DISPLAY_REF_PREFIX,
|
|
94
93
|
ARTIFACT_ENVIRONMENTS,
|
|
95
94
|
ArtifactsNamespace,
|
|
96
95
|
build_artifact_ref,
|
|
97
96
|
build_v2_artifact_ref,
|
|
98
97
|
build_pinned_artifact_ref,
|
|
99
98
|
build_legacy_artifact_ref,
|
|
100
|
-
build_display_artifact_ref,
|
|
101
99
|
parse_artifact_ref,
|
|
102
100
|
try_parse_artifact_ref,
|
|
103
101
|
validate_artifact_address,
|
|
@@ -105,7 +103,6 @@ from .namespaces.artifacts import (
|
|
|
105
103
|
is_pinned_artifact_ref,
|
|
106
104
|
is_head_artifact_ref,
|
|
107
105
|
is_legacy_artifact_ref,
|
|
108
|
-
is_display_artifact_ref,
|
|
109
106
|
)
|
|
110
107
|
from .namespaces.jobs import JobsNamespace
|
|
111
108
|
from .namespaces.processor import ProcessorNamespace
|
|
@@ -165,7 +162,7 @@ from .errors import (
|
|
|
165
162
|
TimeoutError as DominusTimeoutError,
|
|
166
163
|
)
|
|
167
164
|
|
|
168
|
-
__version__ = "
|
|
165
|
+
__version__ = "5.1.0"
|
|
169
166
|
__all__ = [
|
|
170
167
|
# Main SDK instance
|
|
171
168
|
"dominus",
|
|
@@ -195,14 +192,12 @@ __all__ = [
|
|
|
195
192
|
"HealthNamespace",
|
|
196
193
|
# New namespaces (Node.js SDK parity)
|
|
197
194
|
"ARTIFACT_REF_PREFIX",
|
|
198
|
-
"DISPLAY_REF_PREFIX",
|
|
199
195
|
"ARTIFACT_ENVIRONMENTS",
|
|
200
196
|
"ArtifactsNamespace",
|
|
201
197
|
"build_artifact_ref",
|
|
202
198
|
"build_v2_artifact_ref",
|
|
203
199
|
"build_pinned_artifact_ref",
|
|
204
200
|
"build_legacy_artifact_ref",
|
|
205
|
-
"build_display_artifact_ref",
|
|
206
201
|
"parse_artifact_ref",
|
|
207
202
|
"try_parse_artifact_ref",
|
|
208
203
|
"validate_artifact_address",
|
|
@@ -210,7 +205,6 @@ __all__ = [
|
|
|
210
205
|
"is_pinned_artifact_ref",
|
|
211
206
|
"is_head_artifact_ref",
|
|
212
207
|
"is_legacy_artifact_ref",
|
|
213
|
-
"is_display_artifact_ref",
|
|
214
208
|
"JobsNamespace",
|
|
215
209
|
"ProcessorNamespace",
|
|
216
210
|
"SyncNamespace",
|
|
@@ -35,10 +35,13 @@ def _safe_string(value: Any) -> str:
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
ARTIFACT_REF_PREFIX = "ar://"
|
|
38
|
-
DISPLAY_REF_PREFIX = "art:r:"
|
|
39
38
|
ARTIFACT_ENVIRONMENTS = ("development", "staging", "production")
|
|
40
39
|
|
|
41
40
|
|
|
41
|
+
def _legacy_project_head_ref(project_id: str, environment: str, key: str) -> str:
|
|
42
|
+
return f"{ARTIFACT_REF_PREFIX}dominus/project:{project_id}/{environment}/legacy/{quote(key, safe='')}"
|
|
43
|
+
|
|
44
|
+
|
|
42
45
|
def build_artifact_ref(
|
|
43
46
|
*,
|
|
44
47
|
project_slug: Optional[str] = None,
|
|
@@ -109,13 +112,6 @@ def build_pinned_artifact_ref(
|
|
|
109
112
|
return f"{ref}@v{version}"
|
|
110
113
|
|
|
111
114
|
|
|
112
|
-
def build_display_artifact_ref(artifact_key: str) -> Optional[str]:
|
|
113
|
-
normalized_key = _safe_string(artifact_key)
|
|
114
|
-
if not normalized_key:
|
|
115
|
-
return None
|
|
116
|
-
return f"{DISPLAY_REF_PREFIX}{normalized_key}"
|
|
117
|
-
|
|
118
|
-
|
|
119
115
|
def build_legacy_artifact_ref(
|
|
120
116
|
*,
|
|
121
117
|
project_slug: str,
|
|
@@ -146,15 +142,6 @@ def parse_artifact_ref(artifact_ref: str) -> Optional[Dict[str, Any]]:
|
|
|
146
142
|
normalized = _safe_string(artifact_ref)
|
|
147
143
|
if not normalized:
|
|
148
144
|
return None
|
|
149
|
-
if normalized.startswith(DISPLAY_REF_PREFIX):
|
|
150
|
-
artifact_key = normalized[len(DISPLAY_REF_PREFIX):]
|
|
151
|
-
if not artifact_key:
|
|
152
|
-
return None
|
|
153
|
-
return {
|
|
154
|
-
"format": "display",
|
|
155
|
-
"raw": normalized,
|
|
156
|
-
"artifact_key": artifact_key,
|
|
157
|
-
}
|
|
158
145
|
if not normalized.startswith(ARTIFACT_REF_PREFIX):
|
|
159
146
|
return None
|
|
160
147
|
|
|
@@ -245,10 +232,6 @@ def is_legacy_artifact_ref(artifact_ref: Dict[str, Any]) -> bool:
|
|
|
245
232
|
return artifact_ref.get("format") == "v1"
|
|
246
233
|
|
|
247
234
|
|
|
248
|
-
def is_display_artifact_ref(artifact_ref: Dict[str, Any]) -> bool:
|
|
249
|
-
return artifact_ref.get("format") == "display"
|
|
250
|
-
|
|
251
|
-
|
|
252
235
|
def _split_version_suffix(value: str) -> tuple[str, Optional[str]]:
|
|
253
236
|
if "@" not in value:
|
|
254
237
|
return value, None
|
|
@@ -366,10 +349,10 @@ class ArtifactsNamespace:
|
|
|
366
349
|
category=category,
|
|
367
350
|
content_type=content_type,
|
|
368
351
|
)
|
|
369
|
-
|
|
352
|
+
fallback_ref = _legacy_project_head_ref(project_id, environment, use_key)
|
|
370
353
|
return {
|
|
371
354
|
"key": use_key,
|
|
372
|
-
"ref": v2.get("
|
|
355
|
+
"ref": v2.get("head_ref") or fallback_ref,
|
|
373
356
|
"storage_type": v2.get("storage_type") or "redis",
|
|
374
357
|
"size_bytes": v2.get("size_bytes", 0),
|
|
375
358
|
"expires_at": v2.get("expires_at") or "",
|
|
@@ -377,14 +360,14 @@ class ArtifactsNamespace:
|
|
|
377
360
|
|
|
378
361
|
async def retrieve(self, key: str) -> Dict[str, Any]:
|
|
379
362
|
"""
|
|
380
|
-
Retrieve by key via
|
|
363
|
+
Retrieve by key via the addressed V2 compatibility head.
|
|
381
364
|
"""
|
|
382
|
-
project_id,
|
|
365
|
+
project_id, environment = await self._legacy_project_context()
|
|
366
|
+
ref = _legacy_project_head_ref(project_id, environment, key)
|
|
383
367
|
return await self._api(
|
|
384
368
|
"/api/artifact/v2/retrieve",
|
|
385
369
|
body={
|
|
386
|
-
"ref":
|
|
387
|
-
"target_project_id": project_id,
|
|
370
|
+
"ref": ref,
|
|
388
371
|
},
|
|
389
372
|
)
|
|
390
373
|
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Authority Namespace - Dominus Authority service surface.
|
|
3
3
|
|
|
4
4
|
Canonical SDK entry point for the dominus-authority service. Mirrors the MCP
|
|
5
|
-
``authority_*`` tool surface so application code can drive runs,
|
|
6
|
-
deploys, managed clients, timelines, dossiers, and Authority context resolution
|
|
5
|
+
``authority_*`` tool surface so application code can drive runs, provisioning
|
|
6
|
+
targets, deploys, managed clients, timelines, dossiers, and Authority context resolution
|
|
7
7
|
without touching workflow-manager / client-worker / deploy-worker routes
|
|
8
8
|
directly.
|
|
9
9
|
|
|
@@ -44,8 +44,8 @@ def _normalize_run_kind_token(raw: Optional[str]) -> str:
|
|
|
44
44
|
return s
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
def
|
|
48
|
-
return _normalize_run_kind_token(run_kind) == "
|
|
47
|
+
def _is_provisioning_bootstrap_run_kind(run_kind: Optional[str]) -> bool:
|
|
48
|
+
return _normalize_run_kind_token(run_kind) == "provisioning_bootstrap"
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
def _query_string(params: Mapping[str, Any]) -> str:
|
|
@@ -62,7 +62,7 @@ class AuthorityNamespace:
|
|
|
62
62
|
Usage::
|
|
63
63
|
|
|
64
64
|
await dominus.authority.ensure_run(workflow_id="...", subject="PCM47474562")
|
|
65
|
-
await dominus.authority.
|
|
65
|
+
await dominus.authority.list_provisioning_targets()
|
|
66
66
|
await dominus.authority.get_run_dossier(run_id)
|
|
67
67
|
"""
|
|
68
68
|
|
|
@@ -170,9 +170,8 @@ class AuthorityNamespace:
|
|
|
170
170
|
workflow_id: Optional[str] = None,
|
|
171
171
|
workflow_ref: Optional[str] = None,
|
|
172
172
|
run_kind: Optional[str] = None,
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
slug: Optional[str] = None,
|
|
173
|
+
bootstrap_profile_ref: Optional[str] = None,
|
|
174
|
+
provisioning_target_slug: Optional[str] = None,
|
|
176
175
|
instance_id: Optional[str] = None,
|
|
177
176
|
instance_key: Optional[str] = None,
|
|
178
177
|
group: Optional[str] = None,
|
|
@@ -209,22 +208,20 @@ class AuthorityNamespace:
|
|
|
209
208
|
|
|
210
209
|
Calls ``POST /api/authority/runs/ensure``.
|
|
211
210
|
|
|
212
|
-
For
|
|
213
|
-
``
|
|
214
|
-
``
|
|
211
|
+
For provisioning bootstrap, pass ``run_kind="provisioning.bootstrap"`` plus
|
|
212
|
+
``provisioning_target_slug``. Optional bootstrap fields mirror
|
|
213
|
+
``bootstrap_provisioning_target`` (``execution_mode``, ``region``, ``bootstrap_profile_ref``, ...).
|
|
215
214
|
"""
|
|
216
|
-
bootstrap =
|
|
215
|
+
bootstrap = _is_provisioning_bootstrap_run_kind(run_kind)
|
|
217
216
|
if not bootstrap and not workflow_id and not workflow_ref:
|
|
218
217
|
raise ValueError(
|
|
219
218
|
"ensure_run requires workflow_id or workflow_ref unless run_kind is "
|
|
220
|
-
"
|
|
219
|
+
"provisioning.bootstrap"
|
|
221
220
|
)
|
|
222
221
|
if bootstrap:
|
|
223
|
-
|
|
224
|
-
if not
|
|
225
|
-
raise ValueError(
|
|
226
|
-
"ensure_run with run_kind company.bootstrap requires company, company_slug, or slug"
|
|
227
|
-
)
|
|
222
|
+
target_slug = (provisioning_target_slug or "").strip()
|
|
223
|
+
if not target_slug:
|
|
224
|
+
raise ValueError("ensure_run with run_kind provisioning.bootstrap requires provisioning_target_slug")
|
|
228
225
|
if mode == "streaming":
|
|
229
226
|
raise ValueError(
|
|
230
227
|
"Authority runs do not support streaming mode; "
|
|
@@ -237,7 +234,8 @@ class AuthorityNamespace:
|
|
|
237
234
|
if bootstrap:
|
|
238
235
|
body = _compact({
|
|
239
236
|
"run_kind": run_kind,
|
|
240
|
-
"
|
|
237
|
+
"bootstrap_profile_ref": bootstrap_profile_ref,
|
|
238
|
+
"provisioning_target_slug": provisioning_target_slug,
|
|
241
239
|
"workflow_id": workflow_id,
|
|
242
240
|
"workflow_ref": workflow_ref,
|
|
243
241
|
"instance_id": instance_id,
|
|
@@ -245,9 +243,6 @@ class AuthorityNamespace:
|
|
|
245
243
|
"group": group,
|
|
246
244
|
"owner": owner,
|
|
247
245
|
"subject": subject,
|
|
248
|
-
"company": company,
|
|
249
|
-
"company_slug": company_slug,
|
|
250
|
-
"slug": slug,
|
|
251
246
|
"bindings": bindings,
|
|
252
247
|
"inputs": inputs,
|
|
253
248
|
"context": context,
|
|
@@ -269,7 +264,6 @@ class AuthorityNamespace:
|
|
|
269
264
|
body = _compact({
|
|
270
265
|
"workflow_id": workflow_id,
|
|
271
266
|
"workflow_ref": workflow_ref,
|
|
272
|
-
"bootstrap_profile": bootstrap_profile,
|
|
273
267
|
"instance_id": instance_id,
|
|
274
268
|
"instance_key": instance_key,
|
|
275
269
|
"group": group,
|
|
@@ -779,13 +773,13 @@ class AuthorityNamespace:
|
|
|
779
773
|
)
|
|
780
774
|
|
|
781
775
|
# ==================================================================
|
|
782
|
-
#
|
|
776
|
+
# Provisioning Targets
|
|
783
777
|
# ==================================================================
|
|
784
778
|
|
|
785
|
-
async def
|
|
779
|
+
async def create_provisioning_target(
|
|
786
780
|
self,
|
|
787
781
|
*,
|
|
788
|
-
|
|
782
|
+
provisioning_target_slug: str,
|
|
789
783
|
display_name: Optional[str] = None,
|
|
790
784
|
description: Optional[str] = None,
|
|
791
785
|
bootstrap_status: Optional[str] = None,
|
|
@@ -794,34 +788,43 @@ class AuthorityNamespace:
|
|
|
794
788
|
app_slug: Optional[str] = None,
|
|
795
789
|
env: Optional[str] = None,
|
|
796
790
|
target_org_id: Optional[str] = None,
|
|
791
|
+
target_app_slug: Optional[str] = None,
|
|
797
792
|
target_env: Optional[str] = None,
|
|
793
|
+
shared_app_slug: Optional[str] = None,
|
|
798
794
|
initiator_type: Optional[str] = None,
|
|
799
795
|
initiator_id: Optional[str] = None,
|
|
800
796
|
idempotency_key: Optional[str] = None,
|
|
801
797
|
timeout: Optional[float] = None,
|
|
802
798
|
) -> Dict[str, Any]:
|
|
803
|
-
"""Create a new
|
|
804
|
-
if not
|
|
805
|
-
raise ValueError("
|
|
799
|
+
"""Create a new provisioning target. ``POST /api/authority/provisioning-targets``."""
|
|
800
|
+
if not provisioning_target_slug:
|
|
801
|
+
raise ValueError("create_provisioning_target requires provisioning_target_slug")
|
|
806
802
|
body = _compact({
|
|
807
|
-
"
|
|
803
|
+
"provisioning_target_slug": provisioning_target_slug,
|
|
808
804
|
"display_name": display_name,
|
|
809
805
|
"description": description,
|
|
810
806
|
"bootstrap_status": bootstrap_status,
|
|
811
807
|
"bootstrap_run_id": bootstrap_run_id,
|
|
812
808
|
"metadata": metadata,
|
|
813
809
|
**self._initiator(initiator_type, initiator_id, idempotency_key),
|
|
814
|
-
**self._scope(
|
|
810
|
+
**self._scope(
|
|
811
|
+
app_slug,
|
|
812
|
+
env,
|
|
813
|
+
target_org_id,
|
|
814
|
+
target_env,
|
|
815
|
+
target_app_slug=target_app_slug,
|
|
816
|
+
shared_app_slug=shared_app_slug,
|
|
817
|
+
),
|
|
815
818
|
})
|
|
816
819
|
return await self._post(
|
|
817
|
-
"/api/authority/
|
|
820
|
+
"/api/authority/provisioning-targets",
|
|
818
821
|
body,
|
|
819
822
|
timeout=self._http_timeout(timeout, 30.0),
|
|
820
823
|
)
|
|
821
824
|
|
|
822
|
-
async def
|
|
825
|
+
async def get_provisioning_target(
|
|
823
826
|
self,
|
|
824
|
-
|
|
827
|
+
provisioning_target_slug: str,
|
|
825
828
|
*,
|
|
826
829
|
app_slug: Optional[str] = None,
|
|
827
830
|
env: Optional[str] = None,
|
|
@@ -829,9 +832,9 @@ class AuthorityNamespace:
|
|
|
829
832
|
target_env: Optional[str] = None,
|
|
830
833
|
timeout: Optional[float] = None,
|
|
831
834
|
) -> Dict[str, Any]:
|
|
832
|
-
"""Get an Authority
|
|
833
|
-
if not
|
|
834
|
-
raise ValueError("
|
|
835
|
+
"""Get an Authority provisioning target. ``GET /api/authority/provisioning-targets/{provisioning_target_slug}``."""
|
|
836
|
+
if not provisioning_target_slug:
|
|
837
|
+
raise ValueError("provisioning_target_slug is required")
|
|
835
838
|
tid, tev = self._target_query_params(target_org_id, target_env)
|
|
836
839
|
qs = _query_string({
|
|
837
840
|
"app_slug": app_slug,
|
|
@@ -840,11 +843,11 @@ class AuthorityNamespace:
|
|
|
840
843
|
"target_env": tev,
|
|
841
844
|
})
|
|
842
845
|
return await self._get(
|
|
843
|
-
f"/api/authority/
|
|
846
|
+
f"/api/authority/provisioning-targets/{quote(provisioning_target_slug, safe='')}{qs}",
|
|
844
847
|
timeout=self._http_timeout(timeout, 30.0),
|
|
845
848
|
)
|
|
846
849
|
|
|
847
|
-
async def
|
|
850
|
+
async def list_provisioning_targets(
|
|
848
851
|
self,
|
|
849
852
|
*,
|
|
850
853
|
status: Optional[str] = None,
|
|
@@ -856,7 +859,7 @@ class AuthorityNamespace:
|
|
|
856
859
|
offset: int = 0,
|
|
857
860
|
timeout: Optional[float] = None,
|
|
858
861
|
) -> Dict[str, Any]:
|
|
859
|
-
"""List Authority
|
|
862
|
+
"""List Authority provisioning targets. ``GET /api/authority/provisioning-targets``."""
|
|
860
863
|
tid, tev = self._target_query_params(target_org_id, target_env)
|
|
861
864
|
qs = _query_string({
|
|
862
865
|
"app_slug": app_slug,
|
|
@@ -868,18 +871,18 @@ class AuthorityNamespace:
|
|
|
868
871
|
"offset": offset,
|
|
869
872
|
})
|
|
870
873
|
return await self._get(
|
|
871
|
-
f"/api/authority/
|
|
874
|
+
f"/api/authority/provisioning-targets{qs}",
|
|
872
875
|
timeout=self._http_timeout(timeout, 30.0),
|
|
873
876
|
)
|
|
874
877
|
|
|
875
|
-
async def
|
|
878
|
+
async def bootstrap_provisioning_target(
|
|
876
879
|
self,
|
|
877
|
-
|
|
880
|
+
provisioning_target_slug: str,
|
|
878
881
|
*,
|
|
879
882
|
action: Optional[str] = None,
|
|
880
883
|
run_id: Optional[str] = None,
|
|
881
884
|
reason: Optional[str] = None,
|
|
882
|
-
|
|
885
|
+
bootstrap_profile_ref: Optional[str] = None,
|
|
883
886
|
shared_app_slug: Optional[str] = None,
|
|
884
887
|
region: Optional[str] = None,
|
|
885
888
|
system: Optional[str] = None,
|
|
@@ -902,14 +905,14 @@ class AuthorityNamespace:
|
|
|
902
905
|
idempotency_key: Optional[str] = None,
|
|
903
906
|
timeout: Optional[float] = None,
|
|
904
907
|
) -> Dict[str, Any]:
|
|
905
|
-
"""Trigger or replay
|
|
906
|
-
if not
|
|
907
|
-
raise ValueError("
|
|
908
|
+
"""Trigger or replay provisioning target bootstrap. ``POST /api/authority/provisioning-targets/{provisioning_target_slug}/bootstrap``."""
|
|
909
|
+
if not provisioning_target_slug:
|
|
910
|
+
raise ValueError("provisioning_target_slug is required")
|
|
908
911
|
body = _compact({
|
|
909
912
|
"action": action,
|
|
910
913
|
"run_id": run_id,
|
|
911
914
|
"reason": reason,
|
|
912
|
-
"
|
|
915
|
+
"bootstrap_profile_ref": bootstrap_profile_ref,
|
|
913
916
|
"shared_app_slug": shared_app_slug,
|
|
914
917
|
"region": region,
|
|
915
918
|
"system": system,
|
|
@@ -933,36 +936,36 @@ class AuthorityNamespace:
|
|
|
933
936
|
),
|
|
934
937
|
})
|
|
935
938
|
return await self._post(
|
|
936
|
-
f"/api/authority/
|
|
939
|
+
f"/api/authority/provisioning-targets/{quote(provisioning_target_slug, safe='')}/bootstrap",
|
|
937
940
|
body,
|
|
938
941
|
timeout=self._http_timeout(timeout, 60.0),
|
|
939
942
|
)
|
|
940
943
|
|
|
941
|
-
async def
|
|
944
|
+
async def get_provisioning_target_bootstrap(
|
|
942
945
|
self,
|
|
943
|
-
|
|
946
|
+
provisioning_target_slug: str,
|
|
944
947
|
*,
|
|
945
948
|
run_id: Optional[str] = None,
|
|
946
949
|
app_slug: Optional[str] = None,
|
|
947
950
|
env: Optional[str] = None,
|
|
948
951
|
timeout: Optional[float] = None,
|
|
949
952
|
) -> Dict[str, Any]:
|
|
950
|
-
"""Get
|
|
951
|
-
if not
|
|
952
|
-
raise ValueError("
|
|
953
|
+
"""Get provisioning target bootstrap state. ``GET /api/authority/provisioning-targets/{provisioning_target_slug}/bootstrap``."""
|
|
954
|
+
if not provisioning_target_slug:
|
|
955
|
+
raise ValueError("provisioning_target_slug is required")
|
|
953
956
|
qs = _query_string({
|
|
954
957
|
"app_slug": app_slug,
|
|
955
958
|
"env": env,
|
|
956
959
|
"run_id": run_id,
|
|
957
960
|
})
|
|
958
961
|
return await self._get(
|
|
959
|
-
f"/api/authority/
|
|
962
|
+
f"/api/authority/provisioning-targets/{quote(provisioning_target_slug, safe='')}/bootstrap{qs}",
|
|
960
963
|
timeout=self._http_timeout(timeout, 30.0),
|
|
961
964
|
)
|
|
962
965
|
|
|
963
|
-
async def
|
|
966
|
+
async def get_provisioning_target_dossier(
|
|
964
967
|
self,
|
|
965
|
-
|
|
968
|
+
provisioning_target_slug: str,
|
|
966
969
|
*,
|
|
967
970
|
app_slug: Optional[str] = None,
|
|
968
971
|
env: Optional[str] = None,
|
|
@@ -974,9 +977,9 @@ class AuthorityNamespace:
|
|
|
974
977
|
limit: Optional[int] = None,
|
|
975
978
|
timeout: Optional[float] = None,
|
|
976
979
|
) -> Dict[str, Any]:
|
|
977
|
-
"""Get full Authority dossier for a
|
|
978
|
-
if not
|
|
979
|
-
raise ValueError("
|
|
980
|
+
"""Get full Authority dossier for a provisioning target. ``GET /api/authority/dossiers/provisioning-target/{provisioning_target_slug}``."""
|
|
981
|
+
if not provisioning_target_slug:
|
|
982
|
+
raise ValueError("provisioning_target_slug is required")
|
|
980
983
|
tid, tev = self._target_query_params(target_org_id, target_env)
|
|
981
984
|
qs = _query_string({
|
|
982
985
|
"app_slug": app_slug,
|
|
@@ -989,7 +992,7 @@ class AuthorityNamespace:
|
|
|
989
992
|
"limit": limit,
|
|
990
993
|
})
|
|
991
994
|
return await self._get(
|
|
992
|
-
f"/api/authority/dossiers/
|
|
995
|
+
f"/api/authority/dossiers/provisioning-target/{quote(provisioning_target_slug, safe='')}{qs}",
|
|
993
996
|
timeout=self._http_timeout(timeout, 30.0),
|
|
994
997
|
)
|
|
995
998
|
|
|
@@ -104,6 +104,14 @@ class WorkflowNamespace:
|
|
|
104
104
|
return {"workflow_id": str(workflow_id).strip()}
|
|
105
105
|
raise ValueError("workflow_id or workflow_ref is required")
|
|
106
106
|
|
|
107
|
+
@staticmethod
|
|
108
|
+
def _is_workflow_recipe_ref(value: Optional[str]) -> bool:
|
|
109
|
+
return str(value or "").strip().startswith("recipe://workflow-recipe-v1/")
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def _is_pipeline_recipe_ref(value: Optional[str]) -> bool:
|
|
113
|
+
return str(value or "").strip().startswith("recipe://pipeline-recipe-v1/")
|
|
114
|
+
|
|
107
115
|
@staticmethod
|
|
108
116
|
def _instance_base_endpoint(workflow_id: str) -> str:
|
|
109
117
|
from urllib.parse import quote
|
|
@@ -210,9 +218,11 @@ class WorkflowNamespace:
|
|
|
210
218
|
|
|
211
219
|
def _build_authority_ensure_body(
|
|
212
220
|
self,
|
|
213
|
-
workflow_id: str,
|
|
221
|
+
workflow_id: Optional[str] = None,
|
|
214
222
|
*,
|
|
215
223
|
workflow_ref: Optional[str] = None,
|
|
224
|
+
workflow_recipe_ref: Optional[str] = None,
|
|
225
|
+
pipeline_recipe_ref: Optional[str] = None,
|
|
216
226
|
subject: Optional[str] = None,
|
|
217
227
|
company: Optional[str] = None,
|
|
218
228
|
inputs: Optional[Dict[str, Any]] = None,
|
|
@@ -227,12 +237,30 @@ class WorkflowNamespace:
|
|
|
227
237
|
idempotency_key: Optional[str] = None,
|
|
228
238
|
) -> Dict[str, Any]:
|
|
229
239
|
body: Dict[str, Any] = {"mode": mode}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
240
|
+
launch_sources: List[tuple[str, str]] = []
|
|
241
|
+
normalized_workflow_id = str(workflow_id or "").strip()
|
|
242
|
+
if workflow_ref and str(workflow_ref).strip():
|
|
243
|
+
launch_sources.append(("workflow_ref", str(workflow_ref).strip()))
|
|
244
|
+
if workflow_recipe_ref and str(workflow_recipe_ref).strip():
|
|
245
|
+
launch_sources.append(("workflow_recipe_ref", str(workflow_recipe_ref).strip()))
|
|
246
|
+
if pipeline_recipe_ref and str(pipeline_recipe_ref).strip():
|
|
247
|
+
launch_sources.append(("pipeline_recipe_ref", str(pipeline_recipe_ref).strip()))
|
|
248
|
+
if normalized_workflow_id:
|
|
249
|
+
if self._is_workflow_ref(normalized_workflow_id):
|
|
250
|
+
launch_sources.append(("workflow_ref", normalized_workflow_id))
|
|
251
|
+
elif self._is_workflow_recipe_ref(normalized_workflow_id):
|
|
252
|
+
launch_sources.append(("workflow_recipe_ref", normalized_workflow_id))
|
|
253
|
+
elif self._is_pipeline_recipe_ref(normalized_workflow_id):
|
|
254
|
+
launch_sources.append(("pipeline_recipe_ref", normalized_workflow_id))
|
|
255
|
+
else:
|
|
256
|
+
launch_sources.append(("workflow_id", normalized_workflow_id))
|
|
257
|
+
if len(launch_sources) != 1:
|
|
258
|
+
raise ValueError(
|
|
259
|
+
"ensure requires exactly one of workflow_id, workflow_ref, "
|
|
260
|
+
"workflow_recipe_ref, or pipeline_recipe_ref"
|
|
261
|
+
)
|
|
262
|
+
field, value = launch_sources[0]
|
|
263
|
+
body[field] = value
|
|
236
264
|
if subject is not None:
|
|
237
265
|
body["subject"] = subject
|
|
238
266
|
if company is not None:
|
|
@@ -855,7 +883,7 @@ class WorkflowNamespace:
|
|
|
855
883
|
|
|
856
884
|
async def ensure(
|
|
857
885
|
self,
|
|
858
|
-
workflow_id: str,
|
|
886
|
+
workflow_id: Optional[str] = None,
|
|
859
887
|
*,
|
|
860
888
|
instance_id: Optional[str] = None,
|
|
861
889
|
group: Optional[str] = None,
|
|
@@ -866,6 +894,8 @@ class WorkflowNamespace:
|
|
|
866
894
|
mode: str = "blocking",
|
|
867
895
|
context: Optional[Dict[str, Any]] = None,
|
|
868
896
|
workflow_ref: Optional[str] = None,
|
|
897
|
+
workflow_recipe_ref: Optional[str] = None,
|
|
898
|
+
pipeline_recipe_ref: Optional[str] = None,
|
|
869
899
|
subject: Optional[str] = None,
|
|
870
900
|
company: Optional[str] = None,
|
|
871
901
|
inputs: Optional[Dict[str, Any]] = None,
|
|
@@ -886,6 +916,8 @@ class WorkflowNamespace:
|
|
|
886
916
|
body=self._build_authority_ensure_body(
|
|
887
917
|
workflow_id,
|
|
888
918
|
workflow_ref=workflow_ref,
|
|
919
|
+
workflow_recipe_ref=workflow_recipe_ref,
|
|
920
|
+
pipeline_recipe_ref=pipeline_recipe_ref,
|
|
889
921
|
subject=subject,
|
|
890
922
|
company=company,
|
|
891
923
|
inputs=inputs,
|
|
@@ -168,7 +168,7 @@ class Dominus:
|
|
|
168
168
|
from .namespaces.sync import SyncNamespace
|
|
169
169
|
self.sync = SyncNamespace(self)
|
|
170
170
|
|
|
171
|
-
# Authority service (runs,
|
|
171
|
+
# Authority service (runs, provisioning targets, deploys, managed clients, dossiers)
|
|
172
172
|
from .namespaces.authority import AuthorityNamespace
|
|
173
173
|
self.authority = AuthorityNamespace(self)
|
|
174
174
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dominus-sdk-python
|
|
3
|
-
Version:
|
|
3
|
+
Version: 5.1.0
|
|
4
4
|
Summary: Python SDK for the Dominus gateway-first platform
|
|
5
5
|
Author-email: CareBridge Systems <dev@carebridge.io>
|
|
6
6
|
License: Proprietary
|
|
@@ -43,7 +43,7 @@ Async Python SDK for the Dominus gateway-first service plane.
|
|
|
43
43
|
- Gateway-scoped client mode for MCP and other user-JWT sessions
|
|
44
44
|
- Transport compatibility for wrapped `{success,data}` responses and unwrapped Warden/control-plane success objects
|
|
45
45
|
- Local helpers for JWT verification, trace propagation, retries, and console capture
|
|
46
|
-
- Current package version: `
|
|
46
|
+
- Current package version: `5.1.0`
|
|
47
47
|
|
|
48
48
|
## Install
|
|
49
49
|
|
|
@@ -71,6 +71,12 @@ run = await dominus.workflow.ensure(
|
|
|
71
71
|
company="summit-radiology",
|
|
72
72
|
)
|
|
73
73
|
|
|
74
|
+
recipe_run = await dominus.workflow.ensure(
|
|
75
|
+
workflow_recipe_ref="recipe://workflow-recipe-v1/report-cycle@v3",
|
|
76
|
+
subject="PCM47474562",
|
|
77
|
+
company="summit-radiology",
|
|
78
|
+
)
|
|
79
|
+
|
|
74
80
|
timeline = await dominus.authority.get_run_timeline(
|
|
75
81
|
run["run_id"],
|
|
76
82
|
since="2026-04-11T08:33:00Z",
|
|
@@ -198,7 +204,7 @@ JWT and selected scope headers directly through Gateway.
|
|
|
198
204
|
| `jobs` | Job Worker | Enqueue, poll, dead-letter management |
|
|
199
205
|
| `processor` | Processor | Batch and single-job processing |
|
|
200
206
|
| `sync` | Sync Worker | KV synchronization |
|
|
201
|
-
| `authority` | Dominus Authority | Runs,
|
|
207
|
+
| `authority` | Dominus Authority | Runs, provisioning targets, deploys, managed clients, context |
|
|
202
208
|
| `browser` | Browser Worker | Browser run health, ensure/start/status/result/retry/nudge/cancel/timeline/dossier |
|
|
203
209
|
| `deployer` | Deployer | Thin operator control-plane request surface |
|
|
204
210
|
| `warden` | Warden | Thin operator control-plane request surface |
|
{dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_authority_public_vocabulary.py
RENAMED
|
@@ -73,7 +73,7 @@ class FakeMintClient:
|
|
|
73
73
|
|
|
74
74
|
def test_authority_scope_signatures_use_new_public_vocabulary():
|
|
75
75
|
ensure_sig = inspect.signature(AuthorityNamespace.ensure_run)
|
|
76
|
-
bootstrap_sig = inspect.signature(AuthorityNamespace.
|
|
76
|
+
bootstrap_sig = inspect.signature(AuthorityNamespace.bootstrap_provisioning_target)
|
|
77
77
|
release_sig = inspect.signature(AuthorityNamespace.publish_client_release)
|
|
78
78
|
context_sig = inspect.signature(AuthorityNamespace.context_resolve)
|
|
79
79
|
timeline_sig = inspect.signature(AuthorityNamespace.get_run_timeline)
|
|
@@ -86,14 +86,17 @@ def test_authority_scope_signatures_use_new_public_vocabulary():
|
|
|
86
86
|
schedule_create_sig = inspect.signature(AuthorityNamespace.create_schedule)
|
|
87
87
|
mint_sig = inspect.signature(core_helpers.mint_selected_scope_jwt)
|
|
88
88
|
|
|
89
|
-
for name in ("app_slug", "env", "target_org_id", "target_env", "run_kind", "target_app_slug", "
|
|
89
|
+
for name in ("app_slug", "env", "target_org_id", "target_env", "run_kind", "target_app_slug", "bootstrap_profile_ref", "provisioning_target_slug"):
|
|
90
90
|
assert name in ensure_sig.parameters
|
|
91
|
-
|
|
91
|
+
old_profile_key = "bootstrap" + "_profile"
|
|
92
|
+
for legacy in ("project_slug", "environment", "target_project_id", "target_environment", old_profile_key):
|
|
92
93
|
assert legacy not in ensure_sig.parameters
|
|
93
94
|
|
|
94
|
-
for name in ("shared_app_slug", "target_app_slug", "target_env", "
|
|
95
|
+
for name in ("shared_app_slug", "target_app_slug", "target_env", "bootstrap_profile_ref"):
|
|
95
96
|
assert name in bootstrap_sig.parameters
|
|
96
|
-
|
|
97
|
+
old_target_key = "company" + "_slug"
|
|
98
|
+
for legacy in ("shared_project_slug", old_profile_key, old_target_key):
|
|
99
|
+
assert legacy not in bootstrap_sig.parameters
|
|
97
100
|
|
|
98
101
|
for name in ("storage_app_slug", "storage_env", "app_slug", "env"):
|
|
99
102
|
assert name in release_sig.parameters
|
|
@@ -137,16 +140,15 @@ async def test_authority_scope_methods_use_canonical_context_wire_names():
|
|
|
137
140
|
env="production",
|
|
138
141
|
target_org_id="org-123",
|
|
139
142
|
target_env="production",
|
|
140
|
-
bootstrap_profile="carebridge_company_v1",
|
|
141
143
|
)
|
|
142
|
-
await namespace.
|
|
144
|
+
await namespace.bootstrap_provisioning_target(
|
|
143
145
|
"summit-radiology",
|
|
144
146
|
shared_app_slug="shared-core",
|
|
145
147
|
app_slug="carebridge",
|
|
146
148
|
env="production",
|
|
147
149
|
target_app_slug="carebridge",
|
|
148
150
|
target_env="production",
|
|
149
|
-
|
|
151
|
+
bootstrap_profile_ref="recipe://bootstrap-profile-v1/default@head",
|
|
150
152
|
)
|
|
151
153
|
await namespace.publish_client_release(
|
|
152
154
|
variant_slug="desktop",
|
|
@@ -179,7 +181,7 @@ async def test_authority_scope_methods_use_canonical_context_wire_names():
|
|
|
179
181
|
window_hours=24,
|
|
180
182
|
limit=150,
|
|
181
183
|
)
|
|
182
|
-
await namespace.
|
|
184
|
+
await namespace.get_provisioning_target_dossier(
|
|
183
185
|
"summit-radiology",
|
|
184
186
|
app_slug="carebridge",
|
|
185
187
|
env="production",
|
|
@@ -253,14 +255,14 @@ async def test_authority_scope_methods_use_canonical_context_wire_names():
|
|
|
253
255
|
assert ensure_body["env"] == "production"
|
|
254
256
|
assert ensure_body["target_org_id"] == "org-123"
|
|
255
257
|
assert ensure_body["target_env"] == "production"
|
|
256
|
-
assert
|
|
258
|
+
assert "bootstrap_profile_ref" not in ensure_body
|
|
257
259
|
|
|
258
260
|
bootstrap_body = client.calls[1]["body"]
|
|
259
261
|
assert bootstrap_body["shared_app_slug"] == "shared-core"
|
|
260
262
|
assert bootstrap_body["app_slug"] == "carebridge"
|
|
261
263
|
assert bootstrap_body["target_app_slug"] == "carebridge"
|
|
262
264
|
assert bootstrap_body["target_env"] == "production"
|
|
263
|
-
assert bootstrap_body["
|
|
265
|
+
assert bootstrap_body["bootstrap_profile_ref"] == "recipe://bootstrap-profile-v1/default@head"
|
|
264
266
|
|
|
265
267
|
release_body = client.calls[2]["body"]
|
|
266
268
|
assert release_body["storage_app_slug"] == "storage-core"
|
|
@@ -284,7 +286,7 @@ async def test_authority_scope_methods_use_canonical_context_wire_names():
|
|
|
284
286
|
"since=2026-04-11T08%3A33%3A00Z&until=2026-04-11T09%3A33%3A00Z&window_hours=24&limit=150"
|
|
285
287
|
)
|
|
286
288
|
assert client.calls[6]["endpoint"] == (
|
|
287
|
-
"/api/authority/dossiers/
|
|
289
|
+
"/api/authority/dossiers/provisioning-target/summit-radiology?"
|
|
288
290
|
"app_slug=carebridge&env=production&target_org_id=target-org-1&target_env=production"
|
|
289
291
|
"&since=2026-04-11T08%3A33%3A00Z&until=2026-04-11T09%3A33%3A00Z&window_hours=24&limit=150"
|
|
290
292
|
)
|
|
@@ -351,6 +353,46 @@ async def test_authority_scope_methods_use_canonical_context_wire_names():
|
|
|
351
353
|
assert client.calls[18]["endpoint"] == "/api/authority/schedules/demo.hourly/runs/run-2/fail"
|
|
352
354
|
|
|
353
355
|
|
|
356
|
+
@pytest.mark.asyncio
|
|
357
|
+
async def test_authority_provisioning_target_helpers_use_final_routes_and_payload_keys():
|
|
358
|
+
client = FakeClient()
|
|
359
|
+
namespace = AuthorityNamespace(client)
|
|
360
|
+
|
|
361
|
+
await namespace.create_provisioning_target(
|
|
362
|
+
provisioning_target_slug="summit-radiology",
|
|
363
|
+
app_slug="carebridge",
|
|
364
|
+
env="production",
|
|
365
|
+
target_app_slug="carebridge",
|
|
366
|
+
target_env="production",
|
|
367
|
+
shared_app_slug="carebridge-platform",
|
|
368
|
+
)
|
|
369
|
+
await namespace.get_provisioning_target(
|
|
370
|
+
"summit-radiology",
|
|
371
|
+
app_slug="carebridge",
|
|
372
|
+
env="production",
|
|
373
|
+
)
|
|
374
|
+
await namespace.list_provisioning_targets(app_slug="carebridge", env="production", limit=25)
|
|
375
|
+
await namespace.bootstrap_provisioning_target(
|
|
376
|
+
"summit-radiology",
|
|
377
|
+
action="start",
|
|
378
|
+
bootstrap_profile_ref="recipe://bootstrap-profile-v1/default@head",
|
|
379
|
+
execution_mode="async",
|
|
380
|
+
)
|
|
381
|
+
await namespace.get_provisioning_target_bootstrap(
|
|
382
|
+
"summit-radiology",
|
|
383
|
+
run_id="provisioning-run::run-1",
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
assert client.calls[0]["endpoint"] == "/api/authority/provisioning-targets"
|
|
387
|
+
assert client.calls[0]["body"]["provisioning_target_slug"] == "summit-radiology"
|
|
388
|
+
assert client.calls[0]["body"]["target_app_slug"] == "carebridge"
|
|
389
|
+
assert client.calls[1]["endpoint"] == "/api/authority/provisioning-targets/summit-radiology?app_slug=carebridge&env=production"
|
|
390
|
+
assert client.calls[2]["endpoint"] == "/api/authority/provisioning-targets?app_slug=carebridge&env=production&limit=25&offset=0"
|
|
391
|
+
assert client.calls[3]["endpoint"] == "/api/authority/provisioning-targets/summit-radiology/bootstrap"
|
|
392
|
+
assert client.calls[3]["body"]["bootstrap_profile_ref"] == "recipe://bootstrap-profile-v1/default@head"
|
|
393
|
+
assert client.calls[4]["endpoint"] == "/api/authority/provisioning-targets/summit-radiology/bootstrap?run_id=provisioning-run%3A%3Arun-1"
|
|
394
|
+
|
|
395
|
+
|
|
354
396
|
@pytest.mark.asyncio
|
|
355
397
|
async def test_selected_scope_mint_helper_uses_new_public_names_and_route_canonical_mint_payload(monkeypatch):
|
|
356
398
|
FakeMintClient.instances.clear()
|
|
@@ -414,35 +456,35 @@ async def test_list_runs_keeps_target_query_when_org_differs_from_gateway():
|
|
|
414
456
|
|
|
415
457
|
|
|
416
458
|
@pytest.mark.asyncio
|
|
417
|
-
async def
|
|
459
|
+
async def test_authority_ensure_run_provisioning_bootstrap_omits_workflow_mode():
|
|
418
460
|
client = FakeClient()
|
|
419
461
|
namespace = AuthorityNamespace(client)
|
|
420
462
|
await namespace.ensure_run(
|
|
421
|
-
run_kind="
|
|
422
|
-
|
|
463
|
+
run_kind="provisioning.bootstrap",
|
|
464
|
+
provisioning_target_slug="acme-corp",
|
|
423
465
|
app_slug="carebridge",
|
|
424
466
|
env="production",
|
|
425
467
|
target_org_id="org-1",
|
|
426
468
|
execution_mode="async",
|
|
427
469
|
shared_app_slug="shared-core",
|
|
428
|
-
|
|
470
|
+
bootstrap_profile_ref="recipe://bootstrap-profile-v1/default@head",
|
|
429
471
|
)
|
|
430
472
|
body = client.calls[0]["body"]
|
|
431
|
-
assert body["run_kind"] == "
|
|
432
|
-
assert body["
|
|
473
|
+
assert body["run_kind"] == "provisioning.bootstrap"
|
|
474
|
+
assert body["provisioning_target_slug"] == "acme-corp"
|
|
433
475
|
assert body["execution_mode"] == "async"
|
|
434
476
|
assert body["shared_app_slug"] == "shared-core"
|
|
435
|
-
assert body["
|
|
477
|
+
assert body["bootstrap_profile_ref"] == "recipe://bootstrap-profile-v1/default@head"
|
|
436
478
|
assert "mode" not in body
|
|
437
479
|
|
|
438
480
|
|
|
439
481
|
@pytest.mark.asyncio
|
|
440
|
-
async def
|
|
482
|
+
async def test_authority_ensure_run_bootstrap_requires_provisioning_target_slug():
|
|
441
483
|
client = FakeClient()
|
|
442
484
|
namespace = AuthorityNamespace(client)
|
|
443
|
-
with pytest.raises(ValueError, match="
|
|
485
|
+
with pytest.raises(ValueError, match="provisioning_target_slug"):
|
|
444
486
|
await namespace.ensure_run(
|
|
445
|
-
run_kind="
|
|
487
|
+
run_kind="provisioning.bootstrap",
|
|
446
488
|
app_slug="carebridge",
|
|
447
489
|
env="production",
|
|
448
490
|
)
|
|
@@ -274,6 +274,23 @@ async def test_workflow_ensure_supports_authority_one_call_lifecycle():
|
|
|
274
274
|
assert isinstance(body["idempotency_key"], str) and body["idempotency_key"]
|
|
275
275
|
|
|
276
276
|
|
|
277
|
+
@pytest.mark.asyncio
|
|
278
|
+
async def test_workflow_ensure_can_infer_recipe_ref_from_first_argument():
|
|
279
|
+
client = FakeClient()
|
|
280
|
+
namespace = WorkflowNamespace(client)
|
|
281
|
+
|
|
282
|
+
await namespace.ensure(
|
|
283
|
+
"recipe://workflow-recipe-v1/report-cycle@v3",
|
|
284
|
+
company="summit-radiology",
|
|
285
|
+
mode="async",
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
body = client.calls[0]["body"]
|
|
289
|
+
assert body["workflow_recipe_ref"] == "recipe://workflow-recipe-v1/report-cycle@v3"
|
|
290
|
+
assert body["company"] == "summit-radiology"
|
|
291
|
+
assert "workflow_id" not in body
|
|
292
|
+
|
|
293
|
+
|
|
277
294
|
@pytest.mark.asyncio
|
|
278
295
|
async def test_workflow_get_detects_authority_run_ids():
|
|
279
296
|
client = FakeClient()
|
|
@@ -76,6 +76,47 @@ async def test_workflow_ensure_accepts_workflow_ref():
|
|
|
76
76
|
assert body["context"] == {"report_ref": {"report_id": "r-1"}}
|
|
77
77
|
|
|
78
78
|
|
|
79
|
+
@pytest.mark.asyncio
|
|
80
|
+
async def test_workflow_ensure_accepts_recipe_refs():
|
|
81
|
+
client = FakeClient()
|
|
82
|
+
namespace = WorkflowNamespace(client)
|
|
83
|
+
|
|
84
|
+
await namespace.ensure(
|
|
85
|
+
workflow_recipe_ref="recipe://workflow-recipe-v1/patient-intake@v4",
|
|
86
|
+
subject="sub-1",
|
|
87
|
+
company="co-1",
|
|
88
|
+
mode="async",
|
|
89
|
+
)
|
|
90
|
+
await namespace.ensure(
|
|
91
|
+
pipeline_recipe_ref="recipe://pipeline-recipe-v1/intake-pipeline@v2",
|
|
92
|
+
context={"report_ref": {"report_id": "r-1"}},
|
|
93
|
+
mode="async",
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
first = client.calls[0]["body"]
|
|
97
|
+
assert first["workflow_recipe_ref"] == "recipe://workflow-recipe-v1/patient-intake@v4"
|
|
98
|
+
assert first["subject"] == "sub-1"
|
|
99
|
+
assert "workflow_id" not in first
|
|
100
|
+
second = client.calls[1]["body"]
|
|
101
|
+
assert second["pipeline_recipe_ref"] == "recipe://pipeline-recipe-v1/intake-pipeline@v2"
|
|
102
|
+
assert second["context"] == {"report_ref": {"report_id": "r-1"}}
|
|
103
|
+
assert "workflow_ref" not in second
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@pytest.mark.asyncio
|
|
107
|
+
async def test_workflow_ensure_rejects_mixed_legacy_and_recipe_refs():
|
|
108
|
+
client = FakeClient()
|
|
109
|
+
namespace = WorkflowNamespace(client)
|
|
110
|
+
|
|
111
|
+
with pytest.raises(ValueError, match="exactly one"):
|
|
112
|
+
await namespace.ensure(
|
|
113
|
+
"wf-123",
|
|
114
|
+
workflow_recipe_ref="recipe://workflow-recipe-v1/patient-intake@v4",
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
assert client.calls == []
|
|
118
|
+
|
|
119
|
+
|
|
79
120
|
@pytest.mark.asyncio
|
|
80
121
|
async def test_workflow_save_forwards_builder_metadata():
|
|
81
122
|
client = FakeClient()
|
|
@@ -125,7 +166,7 @@ def test_artifact_ref_helpers_round_trip():
|
|
|
125
166
|
}
|
|
126
167
|
|
|
127
168
|
|
|
128
|
-
def
|
|
169
|
+
def test_artifact_ref_helpers_support_v2_refs():
|
|
129
170
|
v2_ref = build_artifact_ref(
|
|
130
171
|
group="carebridge",
|
|
131
172
|
owner="carebridge-summit",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus_sdk_python.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus_sdk_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/dominus_sdk_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-4.6.2 → dominus_sdk_python-5.1.0}/tests/test_control_plane_namespaces.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|