dominus-sdk-python 3.0.2__tar.gz → 3.0.3__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-3.0.2 → dominus_sdk_python-3.0.3}/PKG-INFO +2 -1
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/README.md +1 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/config/endpoints.py +16 -16
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/authority.py +267 -62
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/db.py +4 -4
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/secrets.py +1 -1
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/workflow.py +10 -10
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus_sdk_python.egg-info/PKG-INFO +2 -1
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/pyproject.toml +1 -1
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/tests/test_authority_public_vocabulary.py +83 -12
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/tests/test_provisioning_parity.py +2 -2
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/__init__.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/config/__init__.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/errors.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/helpers/__init__.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/helpers/auth.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/helpers/cache.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/helpers/console_capture.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/helpers/core.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/helpers/crypto.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/helpers/sse.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/helpers/trace.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/__init__.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/admin.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/ai.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/artifacts.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/auth.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/courier.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/ddl.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/fastapi.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/files.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/health.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/jobs.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/logs.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/portal.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/processor.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/redis.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/secure.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/namespaces/sync.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/services/__init__.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus/start.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus_sdk_python.egg-info/SOURCES.txt +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus_sdk_python.egg-info/dependency_links.txt +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus_sdk_python.egg-info/requires.txt +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus_sdk_python.egg-info/top_level.txt +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/setup.cfg +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/tests/test_auth.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/tests/test_errors.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/tests/test_flat_commands.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/tests/test_health.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/tests/test_logs.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/tests/test_public_exports.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/tests/test_transport_compat.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/tests/test_workflow_lifecycle.py +0 -0
- {dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/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
|
+
Version: 3.0.3
|
|
4
4
|
Summary: Python SDK for the Dominus gateway-first platform
|
|
5
5
|
Author-email: CareBridge Systems <dev@carebridge.io>
|
|
6
6
|
License: Proprietary
|
|
@@ -95,6 +95,7 @@ JWT and selected scope headers directly through Gateway.
|
|
|
95
95
|
|
|
96
96
|
## Transport Model
|
|
97
97
|
|
|
98
|
+
- Default HTTP targets are the production gateway (`https://gateway.getdominus.app`); they do not change based on your app’s git branch or PyPI package variant. Set `DOMINUS_GATEWAY_URL` (or `DOMINUS_BASE_URL` / `DOMINUS_JWT_URL`) only for local or custom routing.
|
|
98
99
|
- `DOMINUS_TOKEN` is exchanged for a JWT through `POST /jwt/mint`
|
|
99
100
|
- Service JWTs are cached for 14 minutes with a 60-second refresh window
|
|
100
101
|
- Auth-required worker routes still send base64-encoded JSON bodies as `text/plain`
|
|
@@ -62,6 +62,7 @@ JWT and selected scope headers directly through Gateway.
|
|
|
62
62
|
|
|
63
63
|
## Transport Model
|
|
64
64
|
|
|
65
|
+
- Default HTTP targets are the production gateway (`https://gateway.getdominus.app`); they do not change based on your app’s git branch or PyPI package variant. Set `DOMINUS_GATEWAY_URL` (or `DOMINUS_BASE_URL` / `DOMINUS_JWT_URL`) only for local or custom routing.
|
|
65
66
|
- `DOMINUS_TOKEN` is exchanged for a JWT through `POST /jwt/mint`
|
|
66
67
|
- Service JWTs are cached for 14 minutes with a 60-second refresh window
|
|
67
68
|
- Auth-required worker routes still send base64-encoded JSON bodies as `text/plain`
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
Dominus SDK Endpoints
|
|
3
3
|
|
|
4
4
|
Gateway URL for service routing and health checks.
|
|
5
|
-
JWT URL for authentication (JWT minting).
|
|
5
|
+
JWT URL for authentication (JWT minting) — defaults to the same host as the gateway.
|
|
6
6
|
Logs URL for log ingestion.
|
|
7
7
|
Base URL for SDK requests (defaults to gateway).
|
|
8
8
|
|
|
9
|
+
Defaults always target the production gateway. They do not depend on the caller’s
|
|
10
|
+
git branch, PyPI package variant, or deployment environment. Override only with
|
|
11
|
+
DOMINUS_* env vars for local or advanced routing.
|
|
12
|
+
|
|
9
13
|
Configuration:
|
|
10
14
|
Set DOMINUS_GATEWAY_URL to override the gateway URL.
|
|
11
|
-
Set DOMINUS_JWT_URL to override the JWT minting URL.
|
|
15
|
+
Set DOMINUS_JWT_URL to override the JWT minting URL (defaults to gateway URL).
|
|
12
16
|
Set DOMINUS_LOGS_URL to override the logs URL.
|
|
13
17
|
Set DOMINUS_BASE_URL to override the SDK request base URL.
|
|
14
18
|
Example: export DOMINUS_BASE_URL=http://localhost:5000
|
|
@@ -18,23 +22,21 @@ Usage:
|
|
|
18
22
|
"""
|
|
19
23
|
import os
|
|
20
24
|
|
|
21
|
-
#
|
|
25
|
+
# Production gateway (Cloudflare Worker). Canonical default for all SDK HTTP traffic.
|
|
22
26
|
_DEFAULT_GATEWAY_URL = "https://gateway.getdominus.app"
|
|
23
|
-
_DEFAULT_JWT_URL = "https://jwt.getdominus.app"
|
|
24
27
|
_DEFAULT_LOGS_URL = "https://logs.getdominus.app"
|
|
25
|
-
_DEFAULT_BASE_URL = _DEFAULT_GATEWAY_URL
|
|
26
28
|
|
|
27
29
|
# Gateway URL for service routing (can be overridden via DOMINUS_GATEWAY_URL)
|
|
28
30
|
GATEWAY_URL = os.environ.get("DOMINUS_GATEWAY_URL", _DEFAULT_GATEWAY_URL)
|
|
29
31
|
|
|
30
|
-
# JWT
|
|
31
|
-
JWT_URL = os.environ.get("DOMINUS_JWT_URL",
|
|
32
|
+
# JWT mint/JWKS: same host as gateway by default (matches Node SDK).
|
|
33
|
+
JWT_URL = os.environ.get("DOMINUS_JWT_URL", GATEWAY_URL)
|
|
32
34
|
|
|
33
35
|
# Logs URL for log ingestion (can be overridden via DOMINUS_LOGS_URL)
|
|
34
36
|
LOGS_URL = os.environ.get("DOMINUS_LOGS_URL", _DEFAULT_LOGS_URL)
|
|
35
37
|
|
|
36
|
-
# Base URL for SDK
|
|
37
|
-
BASE_URL = os.environ.get("DOMINUS_BASE_URL",
|
|
38
|
+
# Base URL for non-gateway SDK paths defaults to the same resolved gateway URL.
|
|
39
|
+
BASE_URL = os.environ.get("DOMINUS_BASE_URL", GATEWAY_URL)
|
|
38
40
|
|
|
39
41
|
# Legacy aliases retained as gateway-first aliases.
|
|
40
42
|
SOVEREIGN_URL = BASE_URL
|
|
@@ -77,12 +79,11 @@ def get_gateway_url() -> str:
|
|
|
77
79
|
|
|
78
80
|
def get_jwt_url() -> str:
|
|
79
81
|
"""
|
|
80
|
-
Get the
|
|
82
|
+
Get the base URL for JWT mint/JWKS (defaults to the same host as the gateway).
|
|
81
83
|
|
|
82
|
-
Returns
|
|
83
|
-
otherwise returns the default Cloudflare Worker URL.
|
|
84
|
+
Returns DOMINUS_JWT_URL if set, otherwise the same resolution as get_gateway_url().
|
|
84
85
|
"""
|
|
85
|
-
return os.environ.get("DOMINUS_JWT_URL",
|
|
86
|
+
return os.environ.get("DOMINUS_JWT_URL", get_gateway_url())
|
|
86
87
|
|
|
87
88
|
|
|
88
89
|
def get_logs_url() -> str:
|
|
@@ -99,10 +100,9 @@ def get_base_url() -> str:
|
|
|
99
100
|
"""
|
|
100
101
|
Get the SDK request base URL.
|
|
101
102
|
|
|
102
|
-
Returns
|
|
103
|
-
otherwise returns the default gateway URL.
|
|
103
|
+
Returns DOMINUS_BASE_URL if set, otherwise the same resolution as get_gateway_url().
|
|
104
104
|
"""
|
|
105
|
-
return os.environ.get("DOMINUS_BASE_URL",
|
|
105
|
+
return os.environ.get("DOMINUS_BASE_URL", get_gateway_url())
|
|
106
106
|
|
|
107
107
|
|
|
108
108
|
# DEPRECATED - use get_base_url()
|
|
@@ -37,6 +37,17 @@ def _compact(payload: Mapping[str, Any]) -> Dict[str, Any]:
|
|
|
37
37
|
return out
|
|
38
38
|
|
|
39
39
|
|
|
40
|
+
def _normalize_run_kind_token(raw: Optional[str]) -> str:
|
|
41
|
+
if not raw:
|
|
42
|
+
return ""
|
|
43
|
+
s = str(raw).strip().lower().replace(".", "_").replace("-", "_")
|
|
44
|
+
return s
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _is_company_bootstrap_run_kind(run_kind: Optional[str]) -> bool:
|
|
48
|
+
return _normalize_run_kind_token(run_kind) == "company_bootstrap"
|
|
49
|
+
|
|
50
|
+
|
|
40
51
|
def _query_string(params: Mapping[str, Any]) -> str:
|
|
41
52
|
cleaned = {k: v for k, v in params.items() if v is not None and v != ""}
|
|
42
53
|
if not cleaned:
|
|
@@ -110,17 +121,37 @@ class AuthorityNamespace:
|
|
|
110
121
|
) -> Dict[str, Any]:
|
|
111
122
|
out: Dict[str, Any] = {}
|
|
112
123
|
if app_slug:
|
|
113
|
-
out["
|
|
124
|
+
out["app_slug"] = app_slug
|
|
114
125
|
if env:
|
|
115
|
-
out["
|
|
126
|
+
out["env"] = env
|
|
116
127
|
if target_org_id:
|
|
117
|
-
out["
|
|
128
|
+
out["target_org_id"] = target_org_id
|
|
118
129
|
if target_app_slug:
|
|
119
|
-
out["
|
|
130
|
+
out["target_app_slug"] = target_app_slug
|
|
120
131
|
if target_env:
|
|
121
|
-
out["
|
|
132
|
+
out["target_env"] = target_env
|
|
122
133
|
return out
|
|
123
134
|
|
|
135
|
+
def _target_query_params(
|
|
136
|
+
self,
|
|
137
|
+
target_org_id: Optional[str],
|
|
138
|
+
target_env: Optional[str],
|
|
139
|
+
) -> tuple[Optional[str], Optional[str]]:
|
|
140
|
+
"""
|
|
141
|
+
Omit target_org_id / target_env from GET query strings when they
|
|
142
|
+
duplicate the JWT gateway org/env (selected-scope MCP and operators).
|
|
143
|
+
"""
|
|
144
|
+
client = self._client
|
|
145
|
+
gw_org = getattr(client, "_gateway_org_id", None)
|
|
146
|
+
gw_env = getattr(client, "_gateway_env", None)
|
|
147
|
+
tid = target_org_id
|
|
148
|
+
tev = target_env
|
|
149
|
+
if tid is not None and gw_org is not None and str(tid) == str(gw_org):
|
|
150
|
+
tid = None
|
|
151
|
+
if tev is not None and gw_env is not None and str(tev) == str(gw_env):
|
|
152
|
+
tev = None
|
|
153
|
+
return tid, tev
|
|
154
|
+
|
|
124
155
|
@staticmethod
|
|
125
156
|
def _http_timeout(explicit: Optional[float], default: float) -> float:
|
|
126
157
|
"""Use explicit client timeout when provided; otherwise the historical SDK default."""
|
|
@@ -135,6 +166,9 @@ class AuthorityNamespace:
|
|
|
135
166
|
*,
|
|
136
167
|
workflow_id: Optional[str] = None,
|
|
137
168
|
workflow_ref: Optional[str] = None,
|
|
169
|
+
run_kind: Optional[str] = None,
|
|
170
|
+
company_slug: Optional[str] = None,
|
|
171
|
+
slug: Optional[str] = None,
|
|
138
172
|
instance_id: Optional[str] = None,
|
|
139
173
|
instance_key: Optional[str] = None,
|
|
140
174
|
group: Optional[str] = None,
|
|
@@ -149,6 +183,18 @@ class AuthorityNamespace:
|
|
|
149
183
|
env: Optional[str] = None,
|
|
150
184
|
target_org_id: Optional[str] = None,
|
|
151
185
|
target_env: Optional[str] = None,
|
|
186
|
+
target_app_slug: Optional[str] = None,
|
|
187
|
+
shared_app_slug: Optional[str] = None,
|
|
188
|
+
execution_mode: Optional[str] = None,
|
|
189
|
+
region: Optional[str] = None,
|
|
190
|
+
system: Optional[str] = None,
|
|
191
|
+
github_mode: Optional[str] = None,
|
|
192
|
+
overwrite_existing: Optional[bool] = None,
|
|
193
|
+
owner_email: Optional[str] = None,
|
|
194
|
+
include: Optional[Dict[str, Any]] = None,
|
|
195
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
196
|
+
display_name: Optional[str] = None,
|
|
197
|
+
description: Optional[str] = None,
|
|
152
198
|
initiator_type: Optional[str] = None,
|
|
153
199
|
initiator_id: Optional[str] = None,
|
|
154
200
|
idempotency_key: Optional[str] = None,
|
|
@@ -158,30 +204,79 @@ class AuthorityNamespace:
|
|
|
158
204
|
Ensure (and optionally launch) an Authority-backed workflow run.
|
|
159
205
|
|
|
160
206
|
Calls ``POST /api/authority/runs/ensure``.
|
|
207
|
+
|
|
208
|
+
For company bootstrap, pass ``run_kind="company.bootstrap"`` (or ``company_bootstrap``) plus
|
|
209
|
+
``company``, ``company_slug``, or ``slug``. Optional bootstrap fields mirror
|
|
210
|
+
``bootstrap_company`` (``execution_mode``, ``region``, …).
|
|
161
211
|
"""
|
|
162
|
-
|
|
163
|
-
|
|
212
|
+
bootstrap = _is_company_bootstrap_run_kind(run_kind)
|
|
213
|
+
if not bootstrap and not workflow_id and not workflow_ref:
|
|
214
|
+
raise ValueError(
|
|
215
|
+
"ensure_run requires workflow_id or workflow_ref unless run_kind is "
|
|
216
|
+
"company.bootstrap / company_bootstrap"
|
|
217
|
+
)
|
|
218
|
+
if bootstrap:
|
|
219
|
+
co = (company_slug or slug or company or "").strip()
|
|
220
|
+
if not co:
|
|
221
|
+
raise ValueError(
|
|
222
|
+
"ensure_run with run_kind company.bootstrap requires company, company_slug, or slug"
|
|
223
|
+
)
|
|
164
224
|
if mode == "streaming":
|
|
165
225
|
raise ValueError(
|
|
166
226
|
"Authority runs do not support streaming mode; "
|
|
167
227
|
"use blocking, async, or ensure_only"
|
|
168
228
|
)
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
229
|
+
|
|
230
|
+
initiator = self._initiator(initiator_type, initiator_id, idempotency_key)
|
|
231
|
+
scope = self._scope(app_slug, env, target_org_id, target_env, target_app_slug=target_app_slug)
|
|
232
|
+
|
|
233
|
+
if bootstrap:
|
|
234
|
+
body = _compact({
|
|
235
|
+
"run_kind": run_kind,
|
|
236
|
+
"workflow_id": workflow_id,
|
|
237
|
+
"workflow_ref": workflow_ref,
|
|
238
|
+
"instance_id": instance_id,
|
|
239
|
+
"instance_key": instance_key,
|
|
240
|
+
"group": group,
|
|
241
|
+
"owner": owner,
|
|
242
|
+
"subject": subject,
|
|
243
|
+
"company": company,
|
|
244
|
+
"company_slug": company_slug,
|
|
245
|
+
"slug": slug,
|
|
246
|
+
"bindings": bindings,
|
|
247
|
+
"inputs": inputs,
|
|
248
|
+
"context": context,
|
|
249
|
+
"execution_mode": execution_mode,
|
|
250
|
+
"region": region,
|
|
251
|
+
"system": system,
|
|
252
|
+
"github_mode": github_mode,
|
|
253
|
+
"overwrite_existing": overwrite_existing,
|
|
254
|
+
"owner_email": owner_email,
|
|
255
|
+
"include": include,
|
|
256
|
+
"metadata": metadata,
|
|
257
|
+
"display_name": display_name,
|
|
258
|
+
"description": description,
|
|
259
|
+
"shared_app_slug": shared_app_slug,
|
|
260
|
+
**initiator,
|
|
261
|
+
**scope,
|
|
262
|
+
})
|
|
263
|
+
else:
|
|
264
|
+
body = _compact({
|
|
265
|
+
"workflow_id": workflow_id,
|
|
266
|
+
"workflow_ref": workflow_ref,
|
|
267
|
+
"instance_id": instance_id,
|
|
268
|
+
"instance_key": instance_key,
|
|
269
|
+
"group": group,
|
|
270
|
+
"owner": owner,
|
|
271
|
+
"subject": subject,
|
|
272
|
+
"company": company,
|
|
273
|
+
"mode": mode,
|
|
274
|
+
"bindings": bindings,
|
|
275
|
+
"inputs": inputs,
|
|
276
|
+
"context": context,
|
|
277
|
+
**initiator,
|
|
278
|
+
**scope,
|
|
279
|
+
})
|
|
185
280
|
return await self._post(
|
|
186
281
|
"/api/authority/runs/ensure",
|
|
187
282
|
body,
|
|
@@ -213,15 +308,16 @@ class AuthorityNamespace:
|
|
|
213
308
|
timeout: Optional[float] = None,
|
|
214
309
|
) -> Dict[str, Any]:
|
|
215
310
|
"""List Authority-backed runs. ``GET /api/authority/runs``."""
|
|
311
|
+
tid, tev = self._target_query_params(target_org_id, target_env)
|
|
216
312
|
qs = _query_string({
|
|
217
313
|
"workflow_id": workflow_id,
|
|
218
314
|
"status": status,
|
|
219
315
|
"group": group,
|
|
220
316
|
"owner": owner,
|
|
221
|
-
"
|
|
222
|
-
"
|
|
223
|
-
"
|
|
224
|
-
"
|
|
317
|
+
"app_slug": app_slug,
|
|
318
|
+
"env": env,
|
|
319
|
+
"target_org_id": tid,
|
|
320
|
+
"target_env": tev,
|
|
225
321
|
"limit": limit,
|
|
226
322
|
"offset": offset,
|
|
227
323
|
})
|
|
@@ -418,14 +514,15 @@ class AuthorityNamespace:
|
|
|
418
514
|
offset: int = 0,
|
|
419
515
|
) -> Dict[str, Any]:
|
|
420
516
|
"""List Authority workflow bindings. ``GET /api/authority/workflow-bindings``."""
|
|
517
|
+
tid, tev = self._target_query_params(target_org_id, target_env)
|
|
421
518
|
qs = _query_string({
|
|
422
519
|
"workflow_ref": workflow_ref,
|
|
423
520
|
"workflow_id": workflow_id,
|
|
424
521
|
"status": status,
|
|
425
|
-
"
|
|
426
|
-
"
|
|
427
|
-
"
|
|
428
|
-
"
|
|
522
|
+
"app_slug": app_slug,
|
|
523
|
+
"env": env,
|
|
524
|
+
"target_org_id": tid,
|
|
525
|
+
"target_env": tev,
|
|
429
526
|
"limit": limit,
|
|
430
527
|
"offset": offset,
|
|
431
528
|
})
|
|
@@ -444,13 +541,14 @@ class AuthorityNamespace:
|
|
|
444
541
|
offset: int = 0,
|
|
445
542
|
) -> Dict[str, Any]:
|
|
446
543
|
"""List Authority workflow publications. ``GET /api/authority/workflow-publications``."""
|
|
544
|
+
tid, tev = self._target_query_params(target_org_id, target_env)
|
|
447
545
|
qs = _query_string({
|
|
448
546
|
"workflow_ref": workflow_ref,
|
|
449
547
|
"status": status,
|
|
450
|
-
"
|
|
451
|
-
"
|
|
452
|
-
"
|
|
453
|
-
"
|
|
548
|
+
"app_slug": app_slug,
|
|
549
|
+
"env": env,
|
|
550
|
+
"target_org_id": tid,
|
|
551
|
+
"target_env": tev,
|
|
454
552
|
"limit": limit,
|
|
455
553
|
"offset": offset,
|
|
456
554
|
})
|
|
@@ -510,11 +608,12 @@ class AuthorityNamespace:
|
|
|
510
608
|
"""Get an Authority company. ``GET /api/authority/companies/{company}``."""
|
|
511
609
|
if not company_slug:
|
|
512
610
|
raise ValueError("company_slug is required")
|
|
611
|
+
tid, tev = self._target_query_params(target_org_id, target_env)
|
|
513
612
|
qs = _query_string({
|
|
514
|
-
"
|
|
515
|
-
"
|
|
516
|
-
"
|
|
517
|
-
"
|
|
613
|
+
"app_slug": app_slug,
|
|
614
|
+
"env": env,
|
|
615
|
+
"target_org_id": tid,
|
|
616
|
+
"target_env": tev,
|
|
518
617
|
})
|
|
519
618
|
return await self._get(
|
|
520
619
|
f"/api/authority/companies/{quote(company_slug, safe='')}{qs}",
|
|
@@ -534,11 +633,12 @@ class AuthorityNamespace:
|
|
|
534
633
|
timeout: Optional[float] = None,
|
|
535
634
|
) -> Dict[str, Any]:
|
|
536
635
|
"""List Authority companies. ``GET /api/authority/companies``."""
|
|
636
|
+
tid, tev = self._target_query_params(target_org_id, target_env)
|
|
537
637
|
qs = _query_string({
|
|
538
|
-
"
|
|
539
|
-
"
|
|
540
|
-
"
|
|
541
|
-
"
|
|
638
|
+
"app_slug": app_slug,
|
|
639
|
+
"env": env,
|
|
640
|
+
"target_org_id": tid,
|
|
641
|
+
"target_env": tev,
|
|
542
642
|
"status": status,
|
|
543
643
|
"limit": limit,
|
|
544
644
|
"offset": offset,
|
|
@@ -584,7 +684,7 @@ class AuthorityNamespace:
|
|
|
584
684
|
"action": action,
|
|
585
685
|
"run_id": run_id,
|
|
586
686
|
"reason": reason,
|
|
587
|
-
"
|
|
687
|
+
"shared_app_slug": shared_app_slug,
|
|
588
688
|
"region": region,
|
|
589
689
|
"system": system,
|
|
590
690
|
"github_mode": github_mode,
|
|
@@ -625,8 +725,8 @@ class AuthorityNamespace:
|
|
|
625
725
|
if not company_slug:
|
|
626
726
|
raise ValueError("company_slug is required")
|
|
627
727
|
qs = _query_string({
|
|
628
|
-
"
|
|
629
|
-
"
|
|
728
|
+
"app_slug": app_slug,
|
|
729
|
+
"env": env,
|
|
630
730
|
"run_id": run_id,
|
|
631
731
|
})
|
|
632
732
|
return await self._get(
|
|
@@ -647,11 +747,12 @@ class AuthorityNamespace:
|
|
|
647
747
|
"""Get full Authority dossier for a company. ``GET /api/authority/dossiers/company/{company}``."""
|
|
648
748
|
if not company_slug:
|
|
649
749
|
raise ValueError("company_slug is required")
|
|
750
|
+
tid, tev = self._target_query_params(target_org_id, target_env)
|
|
650
751
|
qs = _query_string({
|
|
651
|
-
"
|
|
652
|
-
"
|
|
653
|
-
"
|
|
654
|
-
"
|
|
752
|
+
"app_slug": app_slug,
|
|
753
|
+
"env": env,
|
|
754
|
+
"target_org_id": tid,
|
|
755
|
+
"target_env": tev,
|
|
655
756
|
})
|
|
656
757
|
return await self._get(
|
|
657
758
|
f"/api/authority/dossiers/company/{quote(company_slug, safe='')}{qs}",
|
|
@@ -726,11 +827,12 @@ class AuthorityNamespace:
|
|
|
726
827
|
timeout: Optional[float] = None,
|
|
727
828
|
) -> Dict[str, Any]:
|
|
728
829
|
"""List deploys. ``GET /api/authority/deploys``."""
|
|
830
|
+
tid, tev = self._target_query_params(target_org_id, target_env)
|
|
729
831
|
qs = _query_string({
|
|
730
|
-
"
|
|
731
|
-
"
|
|
732
|
-
"
|
|
733
|
-
"
|
|
832
|
+
"app_slug": app_slug,
|
|
833
|
+
"env": env,
|
|
834
|
+
"target_org_id": tid,
|
|
835
|
+
"target_env": tev,
|
|
734
836
|
"repo_full_name": repo_full_name,
|
|
735
837
|
"status": status,
|
|
736
838
|
"limit": limit,
|
|
@@ -753,6 +855,8 @@ class AuthorityNamespace:
|
|
|
753
855
|
company: Optional[str] = None,
|
|
754
856
|
subject: Optional[str] = None,
|
|
755
857
|
metadata: Optional[Dict[str, Any]] = None,
|
|
858
|
+
force: Optional[bool] = None,
|
|
859
|
+
allow_duplicate_sha: Optional[bool] = None,
|
|
756
860
|
app_slug: Optional[str] = None,
|
|
757
861
|
env: Optional[str] = None,
|
|
758
862
|
target_org_id: Optional[str] = None,
|
|
@@ -774,6 +878,8 @@ class AuthorityNamespace:
|
|
|
774
878
|
"company": company,
|
|
775
879
|
"subject": subject,
|
|
776
880
|
"metadata": metadata,
|
|
881
|
+
"force": force,
|
|
882
|
+
"allow_duplicate_sha": allow_duplicate_sha,
|
|
777
883
|
**self._initiator(initiator_type, initiator_id, idempotency_key),
|
|
778
884
|
**self._scope(app_slug, env, target_org_id, target_env),
|
|
779
885
|
})
|
|
@@ -882,7 +988,7 @@ class AuthorityNamespace:
|
|
|
882
988
|
*,
|
|
883
989
|
variant_slug: str,
|
|
884
990
|
version: str,
|
|
885
|
-
manifest_path: str,
|
|
991
|
+
manifest_path: Optional[str] = None,
|
|
886
992
|
status: str = "published",
|
|
887
993
|
storage_app_slug: Optional[str] = None,
|
|
888
994
|
storage_env: Optional[str] = None,
|
|
@@ -898,19 +1004,29 @@ class AuthorityNamespace:
|
|
|
898
1004
|
idempotency_key: Optional[str] = None,
|
|
899
1005
|
timeout: Optional[float] = None,
|
|
900
1006
|
) -> Dict[str, Any]:
|
|
901
|
-
"""
|
|
1007
|
+
"""
|
|
1008
|
+
Create or upsert a managed-client release.
|
|
1009
|
+
|
|
1010
|
+
``POST /api/authority/clients/releases``.
|
|
1011
|
+
|
|
1012
|
+
Use ``status="proposed"`` to start the release FSM without publishing;
|
|
1013
|
+
``manifest_path`` may be omitted for proposed releases. Use
|
|
1014
|
+
``approve_client_release`` → ``publish_approved_client_release`` →
|
|
1015
|
+
``distribute_client_release`` for staged rollout.
|
|
1016
|
+
"""
|
|
902
1017
|
if not variant_slug:
|
|
903
1018
|
raise ValueError("publish_client_release requires variant_slug")
|
|
904
1019
|
if not version:
|
|
905
1020
|
raise ValueError("publish_client_release requires version")
|
|
906
|
-
|
|
907
|
-
|
|
1021
|
+
status_eff = str(status or "published").strip().lower()
|
|
1022
|
+
if not manifest_path and status_eff != "proposed":
|
|
1023
|
+
raise ValueError("publish_client_release requires manifest_path unless status is proposed")
|
|
908
1024
|
body = _compact({
|
|
909
1025
|
"variant_slug": variant_slug,
|
|
910
1026
|
"version": version,
|
|
911
1027
|
"status": status,
|
|
912
|
-
"
|
|
913
|
-
"
|
|
1028
|
+
"storage_app_slug": storage_app_slug,
|
|
1029
|
+
"storage_env": storage_env,
|
|
914
1030
|
"storage_category": storage_category,
|
|
915
1031
|
"manifest_path": manifest_path,
|
|
916
1032
|
"bootstrapper_path": bootstrapper_path,
|
|
@@ -926,6 +1042,95 @@ class AuthorityNamespace:
|
|
|
926
1042
|
timeout=self._http_timeout(timeout, 30.0),
|
|
927
1043
|
)
|
|
928
1044
|
|
|
1045
|
+
async def get_client_release(
|
|
1046
|
+
self,
|
|
1047
|
+
release_id: str,
|
|
1048
|
+
*,
|
|
1049
|
+
app_slug: Optional[str] = None,
|
|
1050
|
+
env: Optional[str] = None,
|
|
1051
|
+
timeout: Optional[float] = None,
|
|
1052
|
+
) -> Dict[str, Any]:
|
|
1053
|
+
"""Fetch one release by id. ``GET /api/authority/clients/releases/{release_id}``."""
|
|
1054
|
+
if not release_id:
|
|
1055
|
+
raise ValueError("get_client_release requires release_id")
|
|
1056
|
+
qs = _query_string({"app_slug": app_slug, "env": env})
|
|
1057
|
+
return await self._get(
|
|
1058
|
+
f"/api/authority/clients/releases/{quote(release_id, safe='')}{qs}",
|
|
1059
|
+
timeout=self._http_timeout(timeout, 30.0),
|
|
1060
|
+
)
|
|
1061
|
+
|
|
1062
|
+
async def approve_client_release(
|
|
1063
|
+
self,
|
|
1064
|
+
release_id: str,
|
|
1065
|
+
*,
|
|
1066
|
+
app_slug: Optional[str] = None,
|
|
1067
|
+
env: Optional[str] = None,
|
|
1068
|
+
initiator_type: Optional[str] = None,
|
|
1069
|
+
initiator_id: Optional[str] = None,
|
|
1070
|
+
idempotency_key: Optional[str] = None,
|
|
1071
|
+
timeout: Optional[float] = None,
|
|
1072
|
+
) -> Dict[str, Any]:
|
|
1073
|
+
"""Approve a proposed release. ``POST /api/authority/clients/releases/{id}/approve``."""
|
|
1074
|
+
if not release_id:
|
|
1075
|
+
raise ValueError("approve_client_release requires release_id")
|
|
1076
|
+
body = _compact({
|
|
1077
|
+
**self._initiator(initiator_type, initiator_id, idempotency_key),
|
|
1078
|
+
**self._scope(app_slug, env, None, None),
|
|
1079
|
+
})
|
|
1080
|
+
return await self._post(
|
|
1081
|
+
f"/api/authority/clients/releases/{quote(release_id, safe='')}/approve",
|
|
1082
|
+
body,
|
|
1083
|
+
timeout=self._http_timeout(timeout, 30.0),
|
|
1084
|
+
)
|
|
1085
|
+
|
|
1086
|
+
async def publish_approved_client_release(
|
|
1087
|
+
self,
|
|
1088
|
+
release_id: str,
|
|
1089
|
+
*,
|
|
1090
|
+
app_slug: Optional[str] = None,
|
|
1091
|
+
env: Optional[str] = None,
|
|
1092
|
+
initiator_type: Optional[str] = None,
|
|
1093
|
+
initiator_id: Optional[str] = None,
|
|
1094
|
+
idempotency_key: Optional[str] = None,
|
|
1095
|
+
timeout: Optional[float] = None,
|
|
1096
|
+
) -> Dict[str, Any]:
|
|
1097
|
+
"""Publish an approved release (gateway health handshake). ``POST .../publish``."""
|
|
1098
|
+
if not release_id:
|
|
1099
|
+
raise ValueError("publish_approved_client_release requires release_id")
|
|
1100
|
+
body = _compact({
|
|
1101
|
+
**self._initiator(initiator_type, initiator_id, idempotency_key),
|
|
1102
|
+
**self._scope(app_slug, env, None, None),
|
|
1103
|
+
})
|
|
1104
|
+
return await self._post(
|
|
1105
|
+
f"/api/authority/clients/releases/{quote(release_id, safe='')}/publish",
|
|
1106
|
+
body,
|
|
1107
|
+
timeout=self._http_timeout(timeout, 30.0),
|
|
1108
|
+
)
|
|
1109
|
+
|
|
1110
|
+
async def distribute_client_release(
|
|
1111
|
+
self,
|
|
1112
|
+
release_id: str,
|
|
1113
|
+
*,
|
|
1114
|
+
app_slug: Optional[str] = None,
|
|
1115
|
+
env: Optional[str] = None,
|
|
1116
|
+
initiator_type: Optional[str] = None,
|
|
1117
|
+
initiator_id: Optional[str] = None,
|
|
1118
|
+
idempotency_key: Optional[str] = None,
|
|
1119
|
+
timeout: Optional[float] = None,
|
|
1120
|
+
) -> Dict[str, Any]:
|
|
1121
|
+
"""Mark a published release as distributed. ``POST .../distribute``."""
|
|
1122
|
+
if not release_id:
|
|
1123
|
+
raise ValueError("distribute_client_release requires release_id")
|
|
1124
|
+
body = _compact({
|
|
1125
|
+
**self._initiator(initiator_type, initiator_id, idempotency_key),
|
|
1126
|
+
**self._scope(app_slug, env, None, None),
|
|
1127
|
+
})
|
|
1128
|
+
return await self._post(
|
|
1129
|
+
f"/api/authority/clients/releases/{quote(release_id, safe='')}/distribute",
|
|
1130
|
+
body,
|
|
1131
|
+
timeout=self._http_timeout(timeout, 30.0),
|
|
1132
|
+
)
|
|
1133
|
+
|
|
929
1134
|
async def create_client_bootstrap_session(
|
|
930
1135
|
self,
|
|
931
1136
|
*,
|
|
@@ -987,8 +1192,8 @@ class AuthorityNamespace:
|
|
|
987
1192
|
) -> Dict[str, Any]:
|
|
988
1193
|
"""List managed client installations. ``GET /api/authority/clients/installations``."""
|
|
989
1194
|
qs = _query_string({
|
|
990
|
-
"
|
|
991
|
-
"
|
|
1195
|
+
"app_slug": app_slug,
|
|
1196
|
+
"env": env,
|
|
992
1197
|
"status": status,
|
|
993
1198
|
"variant_slug": variant_slug,
|
|
994
1199
|
"company": company,
|
|
@@ -449,7 +449,7 @@ class DbNamespace:
|
|
|
449
449
|
async def provision_neon_complete(
|
|
450
450
|
self,
|
|
451
451
|
*,
|
|
452
|
-
|
|
452
|
+
app_slug: str,
|
|
453
453
|
region: Optional[str] = None,
|
|
454
454
|
timeout: float = 300.0,
|
|
455
455
|
) -> Dict[str, Any]:
|
|
@@ -459,7 +459,7 @@ class DbNamespace:
|
|
|
459
459
|
endpoint="/api/provision/complete",
|
|
460
460
|
method="POST",
|
|
461
461
|
body={
|
|
462
|
-
"
|
|
462
|
+
"app_slug": app_slug,
|
|
463
463
|
"region": region or "aws-us-east-1",
|
|
464
464
|
},
|
|
465
465
|
use_gateway=True,
|
|
@@ -469,7 +469,7 @@ class DbNamespace:
|
|
|
469
469
|
async def provision_neon_delete(
|
|
470
470
|
self,
|
|
471
471
|
*,
|
|
472
|
-
|
|
472
|
+
app_slug: str,
|
|
473
473
|
timeout: float = 120.0,
|
|
474
474
|
) -> Dict[str, Any]:
|
|
475
475
|
"""Neon teardown via ``DELETE /api/provision/delete``."""
|
|
@@ -477,7 +477,7 @@ class DbNamespace:
|
|
|
477
477
|
return await self._client._request(
|
|
478
478
|
endpoint="/api/provision/delete",
|
|
479
479
|
method="DELETE",
|
|
480
|
-
body={"
|
|
480
|
+
body={"app_slug": app_slug},
|
|
481
481
|
use_gateway=True,
|
|
482
482
|
timeout=cap,
|
|
483
483
|
)
|
|
@@ -246,9 +246,9 @@ class WorkflowNamespace:
|
|
|
246
246
|
if instance_id:
|
|
247
247
|
body["instance_id"] = instance_id
|
|
248
248
|
if target_project_id:
|
|
249
|
-
body["
|
|
249
|
+
body["target_org_id"] = target_project_id
|
|
250
250
|
if target_environment:
|
|
251
|
-
body["
|
|
251
|
+
body["target_env"] = target_environment
|
|
252
252
|
return self._authority_mutation_body(
|
|
253
253
|
body,
|
|
254
254
|
idempotency_key=idempotency_key,
|
|
@@ -1035,9 +1035,9 @@ class WorkflowNamespace:
|
|
|
1035
1035
|
if status:
|
|
1036
1036
|
params.append(f"status={status}")
|
|
1037
1037
|
if target_project_id:
|
|
1038
|
-
params.append(f"
|
|
1038
|
+
params.append(f"target_org_id={target_project_id}")
|
|
1039
1039
|
if target_environment:
|
|
1040
|
-
params.append(f"
|
|
1040
|
+
params.append(f"target_env={target_environment}")
|
|
1041
1041
|
|
|
1042
1042
|
result = await self._api(
|
|
1043
1043
|
endpoint=f"/api/authority/runs?{'&'.join(params)}",
|
|
@@ -1114,9 +1114,9 @@ class WorkflowNamespace:
|
|
|
1114
1114
|
if trigger_artifact:
|
|
1115
1115
|
body["trigger_artifact"] = trigger_artifact
|
|
1116
1116
|
if target_project_id:
|
|
1117
|
-
body["
|
|
1117
|
+
body["target_org_id"] = target_project_id
|
|
1118
1118
|
if target_environment:
|
|
1119
|
-
body["
|
|
1119
|
+
body["target_env"] = target_environment
|
|
1120
1120
|
return await self._api(
|
|
1121
1121
|
endpoint=f"/api/authority/runs/{workflow_id}/nudge",
|
|
1122
1122
|
body=self._authority_mutation_body(
|
|
@@ -1202,9 +1202,9 @@ class WorkflowNamespace:
|
|
|
1202
1202
|
if trigger_artifact:
|
|
1203
1203
|
body["trigger_artifact"] = trigger_artifact
|
|
1204
1204
|
if target_project_id:
|
|
1205
|
-
body["
|
|
1205
|
+
body["target_org_id"] = target_project_id
|
|
1206
1206
|
if target_environment:
|
|
1207
|
-
body["
|
|
1207
|
+
body["target_env"] = target_environment
|
|
1208
1208
|
return await self._api(
|
|
1209
1209
|
endpoint=f"/api/authority/runs/{workflow_id}/retry",
|
|
1210
1210
|
body=self._authority_mutation_body(
|
|
@@ -1385,9 +1385,9 @@ class WorkflowNamespace:
|
|
|
1385
1385
|
if self._is_authority_run_id(execution_id):
|
|
1386
1386
|
body: Dict[str, Any] = {}
|
|
1387
1387
|
if target_project_id:
|
|
1388
|
-
body["
|
|
1388
|
+
body["target_org_id"] = target_project_id
|
|
1389
1389
|
if target_environment:
|
|
1390
|
-
body["
|
|
1390
|
+
body["target_env"] = target_environment
|
|
1391
1391
|
return await self._api(
|
|
1392
1392
|
endpoint=f"/api/authority/runs/{execution_id}/cancel",
|
|
1393
1393
|
body=self._authority_mutation_body(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dominus-sdk-python
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.3
|
|
4
4
|
Summary: Python SDK for the Dominus gateway-first platform
|
|
5
5
|
Author-email: CareBridge Systems <dev@carebridge.io>
|
|
6
6
|
License: Proprietary
|
|
@@ -95,6 +95,7 @@ JWT and selected scope headers directly through Gateway.
|
|
|
95
95
|
|
|
96
96
|
## Transport Model
|
|
97
97
|
|
|
98
|
+
- Default HTTP targets are the production gateway (`https://gateway.getdominus.app`); they do not change based on your app’s git branch or PyPI package variant. Set `DOMINUS_GATEWAY_URL` (or `DOMINUS_BASE_URL` / `DOMINUS_JWT_URL`) only for local or custom routing.
|
|
98
99
|
- `DOMINUS_TOKEN` is exchanged for a JWT through `POST /jwt/mint`
|
|
99
100
|
- Service JWTs are cached for 14 minutes with a 60-second refresh window
|
|
100
101
|
- Auth-required worker routes still send base64-encoded JSON bodies as `text/plain`
|
{dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/tests/test_authority_public_vocabulary.py
RENAMED
|
@@ -78,7 +78,7 @@ def test_authority_scope_signatures_use_new_public_vocabulary():
|
|
|
78
78
|
context_sig = inspect.signature(AuthorityNamespace.context_resolve)
|
|
79
79
|
mint_sig = inspect.signature(core_helpers.mint_selected_scope_jwt)
|
|
80
80
|
|
|
81
|
-
for name in ("app_slug", "env", "target_org_id", "target_env"):
|
|
81
|
+
for name in ("app_slug", "env", "target_org_id", "target_env", "run_kind", "target_app_slug"):
|
|
82
82
|
assert name in ensure_sig.parameters
|
|
83
83
|
for legacy in ("project_slug", "environment", "target_project_id", "target_environment"):
|
|
84
84
|
assert legacy not in ensure_sig.parameters
|
|
@@ -142,21 +142,21 @@ async def test_authority_scope_methods_use_canonical_context_wire_names():
|
|
|
142
142
|
)
|
|
143
143
|
|
|
144
144
|
ensure_body = client.calls[0]["body"]
|
|
145
|
-
assert ensure_body["
|
|
146
|
-
assert ensure_body["
|
|
147
|
-
assert ensure_body["
|
|
148
|
-
assert ensure_body["
|
|
145
|
+
assert ensure_body["app_slug"] == "carebridge"
|
|
146
|
+
assert ensure_body["env"] == "production"
|
|
147
|
+
assert ensure_body["target_org_id"] == "org-123"
|
|
148
|
+
assert ensure_body["target_env"] == "production"
|
|
149
149
|
|
|
150
150
|
bootstrap_body = client.calls[1]["body"]
|
|
151
|
-
assert bootstrap_body["
|
|
152
|
-
assert bootstrap_body["
|
|
153
|
-
assert bootstrap_body["
|
|
154
|
-
assert bootstrap_body["
|
|
151
|
+
assert bootstrap_body["shared_app_slug"] == "shared-core"
|
|
152
|
+
assert bootstrap_body["app_slug"] == "carebridge"
|
|
153
|
+
assert bootstrap_body["target_app_slug"] == "carebridge"
|
|
154
|
+
assert bootstrap_body["target_env"] == "production"
|
|
155
155
|
|
|
156
156
|
release_body = client.calls[2]["body"]
|
|
157
|
-
assert release_body["
|
|
158
|
-
assert release_body["
|
|
159
|
-
assert release_body["
|
|
157
|
+
assert release_body["storage_app_slug"] == "storage-core"
|
|
158
|
+
assert release_body["storage_env"] == "production"
|
|
159
|
+
assert release_body["app_slug"] == "carebridge"
|
|
160
160
|
|
|
161
161
|
context_body = client.calls[3]["body"]
|
|
162
162
|
assert context_body["org_id"] == "org-123"
|
|
@@ -190,3 +190,74 @@ async def test_selected_scope_mint_helper_uses_new_public_names_and_route_canoni
|
|
|
190
190
|
"target_org_id": "org-123",
|
|
191
191
|
"target_env": "production",
|
|
192
192
|
}
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@pytest.mark.asyncio
|
|
196
|
+
async def test_list_runs_drops_target_query_when_matching_gateway_scope():
|
|
197
|
+
client = FakeClient()
|
|
198
|
+
client._gateway_org_id = "a73627b4-071f-4d27-b964-d220464deb6e"
|
|
199
|
+
client._gateway_env = "production"
|
|
200
|
+
ns = AuthorityNamespace(client)
|
|
201
|
+
await ns.list_runs(
|
|
202
|
+
app_slug="dominus-authority",
|
|
203
|
+
env="production",
|
|
204
|
+
target_org_id="a73627b4-071f-4d27-b964-d220464deb6e",
|
|
205
|
+
target_env="production",
|
|
206
|
+
limit=5,
|
|
207
|
+
offset=0,
|
|
208
|
+
)
|
|
209
|
+
ep = client.calls[0]["endpoint"]
|
|
210
|
+
assert "target_org_id" not in ep
|
|
211
|
+
assert "target_env" not in ep
|
|
212
|
+
assert "app_slug=dominus-authority" in ep
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@pytest.mark.asyncio
|
|
216
|
+
async def test_list_runs_keeps_target_query_when_org_differs_from_gateway():
|
|
217
|
+
client = FakeClient()
|
|
218
|
+
client._gateway_org_id = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
|
219
|
+
client._gateway_env = "production"
|
|
220
|
+
ns = AuthorityNamespace(client)
|
|
221
|
+
await ns.list_runs(
|
|
222
|
+
app_slug="dominus-authority",
|
|
223
|
+
env="production",
|
|
224
|
+
target_org_id="bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
|
|
225
|
+
target_env="production",
|
|
226
|
+
limit=3,
|
|
227
|
+
)
|
|
228
|
+
ep = client.calls[0]["endpoint"]
|
|
229
|
+
assert "target_org_id=bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb" in ep
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
@pytest.mark.asyncio
|
|
233
|
+
async def test_authority_ensure_run_company_bootstrap_omits_workflow_mode():
|
|
234
|
+
client = FakeClient()
|
|
235
|
+
namespace = AuthorityNamespace(client)
|
|
236
|
+
await namespace.ensure_run(
|
|
237
|
+
run_kind="company.bootstrap",
|
|
238
|
+
company="acme-corp",
|
|
239
|
+
app_slug="carebridge",
|
|
240
|
+
env="production",
|
|
241
|
+
target_org_id="org-1",
|
|
242
|
+
execution_mode="async",
|
|
243
|
+
shared_app_slug="shared-core",
|
|
244
|
+
)
|
|
245
|
+
body = client.calls[0]["body"]
|
|
246
|
+
assert body["run_kind"] == "company.bootstrap"
|
|
247
|
+
assert body["company"] == "acme-corp"
|
|
248
|
+
assert body["execution_mode"] == "async"
|
|
249
|
+
assert body["shared_app_slug"] == "shared-core"
|
|
250
|
+
assert "mode" not in body
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@pytest.mark.asyncio
|
|
254
|
+
async def test_authority_ensure_run_bootstrap_requires_company_slug():
|
|
255
|
+
client = FakeClient()
|
|
256
|
+
namespace = AuthorityNamespace(client)
|
|
257
|
+
with pytest.raises(ValueError, match="company, company_slug, or slug"):
|
|
258
|
+
await namespace.ensure_run(
|
|
259
|
+
run_kind="company_bootstrap",
|
|
260
|
+
app_slug="carebridge",
|
|
261
|
+
env="production",
|
|
262
|
+
)
|
|
263
|
+
assert client.calls == []
|
|
@@ -65,8 +65,8 @@ async def test_provision_neon_delete_uses_delete_with_body():
|
|
|
65
65
|
return {"deleted": True}
|
|
66
66
|
|
|
67
67
|
with patch.object(dominus, "_request", side_effect=fake_request):
|
|
68
|
-
await dominus.db.provision_neon_delete(
|
|
68
|
+
await dominus.db.provision_neon_delete(app_slug="proj-x", timeout=90.0)
|
|
69
69
|
assert len(calls) == 1
|
|
70
70
|
assert calls[0]["method"] == "DELETE"
|
|
71
|
-
assert calls[0]["body"] == {"
|
|
71
|
+
assert calls[0]["body"] == {"app_slug": "proj-x"}
|
|
72
72
|
assert calls[0]["endpoint"] == "/api/provision/delete"
|
|
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-3.0.2 → dominus_sdk_python-3.0.3}/dominus_sdk_python.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus_sdk_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{dominus_sdk_python-3.0.2 → dominus_sdk_python-3.0.3}/dominus_sdk_python.egg-info/top_level.txt
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
|
|
File without changes
|
|
File without changes
|