codecraftai-restclient-pychestrate 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ccai/pychestrate/py.typed +0 -0
- ccai/pychestrate/rest/client/__init__.py +0 -0
- ccai/pychestrate/rest/client/generation/__init__.py +0 -0
- ccai/pychestrate/rest/client/generation/pychestraterestclientgenerator.py +98 -0
- ccai/pychestrate/rest/client/generation/specs/pychestrate.yaml +3757 -0
- ccai/pychestrate/rest/client/groups/__init__.py +0 -0
- ccai/pychestrate/rest/client/groups/agents.py +171 -0
- ccai/pychestrate/rest/client/groups/artifacts.py +103 -0
- ccai/pychestrate/rest/client/groups/audit.py +99 -0
- ccai/pychestrate/rest/client/groups/auth.py +55 -0
- ccai/pychestrate/rest/client/groups/clients.py +287 -0
- ccai/pychestrate/rest/client/groups/dispatch.py +118 -0
- ccai/pychestrate/rest/client/groups/enrollment.py +212 -0
- ccai/pychestrate/rest/client/groups/flags.py +332 -0
- ccai/pychestrate/rest/client/groups/me.py +55 -0
- ccai/pychestrate/rest/client/groups/notifications.py +128 -0
- ccai/pychestrate/rest/client/groups/pluginapi.py +128 -0
- ccai/pychestrate/rest/client/groups/pods.py +558 -0
- ccai/pychestrate/rest/client/groups/progress.py +64 -0
- ccai/pychestrate/rest/client/groups/projects.py +420 -0
- ccai/pychestrate/rest/client/groups/projecttemplates.py +91 -0
- ccai/pychestrate/rest/client/groups/rbac.py +243 -0
- ccai/pychestrate/rest/client/groups/results.py +193 -0
- ccai/pychestrate/rest/client/groups/retention.py +169 -0
- ccai/pychestrate/rest/client/groups/runs.py +152 -0
- ccai/pychestrate/rest/client/groups/secrets.py +91 -0
- ccai/pychestrate/rest/client/groups/tagging.py +216 -0
- ccai/pychestrate/rest/client/groups/testcatalog.py +152 -0
- ccai/pychestrate/rest/client/groups/testruns.py +58 -0
- ccai/pychestrate/rest/client/groups/users.py +91 -0
- ccai/pychestrate/rest/client/groups/variables.py +228 -0
- ccai/pychestrate/rest/client/models/__init__.py +0 -0
- ccai/pychestrate/rest/client/models/agents.py +34 -0
- ccai/pychestrate/rest/client/models/artifactlocaluploadresult.py +18 -0
- ccai/pychestrate/rest/client/models/artifacts.py +24 -0
- ccai/pychestrate/rest/client/models/artifactuploadtarget.py +20 -0
- ccai/pychestrate/rest/client/models/audit.py +18 -0
- ccai/pychestrate/rest/client/models/auth.py +15 -0
- ccai/pychestrate/rest/client/models/capabilityentry.py +15 -0
- ccai/pychestrate/rest/client/models/client.py +19 -0
- ccai/pychestrate/rest/client/models/clients.py +40 -0
- ccai/pychestrate/rest/client/models/dispatch.py +26 -0
- ccai/pychestrate/rest/client/models/enrollment.py +39 -0
- ccai/pychestrate/rest/client/models/flags.py +55 -0
- ccai/pychestrate/rest/client/models/jobdeadline.py +11 -0
- ccai/pychestrate/rest/client/models/jobenvelope.py +38 -0
- ccai/pychestrate/rest/client/models/jobforwardinginfo.py +12 -0
- ccai/pychestrate/rest/client/models/jobpipelineref.py +11 -0
- ccai/pychestrate/rest/client/models/jobrefs.py +14 -0
- ccai/pychestrate/rest/client/models/jobresultslocator.py +11 -0
- ccai/pychestrate/rest/client/models/me.py +14 -0
- ccai/pychestrate/rest/client/models/notifications.py +24 -0
- ccai/pychestrate/rest/client/models/pagemeta.py +18 -0
- ccai/pychestrate/rest/client/models/pluginapi.py +21 -0
- ccai/pychestrate/rest/client/models/podmember.py +14 -0
- ccai/pychestrate/rest/client/models/pods.py +75 -0
- ccai/pychestrate/rest/client/models/podtopologylink.py +15 -0
- ccai/pychestrate/rest/client/models/problem.py +19 -0
- ccai/pychestrate/rest/client/models/progress.py +18 -0
- ccai/pychestrate/rest/client/models/progressrecord.py +26 -0
- ccai/pychestrate/rest/client/models/progresssummary.py +29 -0
- ccai/pychestrate/rest/client/models/projects.py +49 -0
- ccai/pychestrate/rest/client/models/projecttemplates.py +14 -0
- ccai/pychestrate/rest/client/models/rbac.py +46 -0
- ccai/pychestrate/rest/client/models/results.py +56 -0
- ccai/pychestrate/rest/client/models/retention.py +26 -0
- ccai/pychestrate/rest/client/models/runevent.py +25 -0
- ccai/pychestrate/rest/client/models/runs.py +32 -0
- ccai/pychestrate/rest/client/models/scopedsecret.py +13 -0
- ccai/pychestrate/rest/client/models/secrets.py +16 -0
- ccai/pychestrate/rest/client/models/signingkey.py +19 -0
- ccai/pychestrate/rest/client/models/tagging.py +24 -0
- ccai/pychestrate/rest/client/models/testcatalog.py +50 -0
- ccai/pychestrate/rest/client/models/testcatalogimportsummary.py +16 -0
- ccai/pychestrate/rest/client/models/testruns.py +25 -0
- ccai/pychestrate/rest/client/models/users.py +23 -0
- ccai/pychestrate/rest/client/models/variableeffectiveentry.py +13 -0
- ccai/pychestrate/rest/client/models/variables.py +30 -0
- ccai/pychestrate/rest/client/pychestraterestclient.py +166 -0
- ccai/pychestrate/rest/client/pychestraterestclientbase.py +147 -0
- codecraftai_restclient_pychestrate-1.2.0.dist-info/METADATA +96 -0
- codecraftai_restclient_pychestrate-1.2.0.dist-info/RECORD +84 -0
- codecraftai_restclient_pychestrate-1.2.0.dist-info/WHEEL +4 -0
- codecraftai_restclient_pychestrate-1.2.0.dist-info/licenses/LICENSE.md +204 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# Auto-generated by RestClientGenerator. DO NOT EDIT.
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
from ccai.pychestrate.rest.client.models.client import Client
|
|
6
|
+
from ccai.pychestrate.rest.client.models.clients import Clientattributesupdaterequest
|
|
7
|
+
from ccai.pychestrate.rest.client.models.clients import Clientrevokerequest
|
|
8
|
+
from ccai.pychestrate.rest.client.models.clients import Pendingdispatch
|
|
9
|
+
from ccai.restclient.base.aspectsrest import AspectsRest
|
|
10
|
+
from ccai.restclient.base.restapigroup import RestApiGroup
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ClientsApiGroup(RestApiGroup):
|
|
14
|
+
"""
|
|
15
|
+
Registered pod client agents.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def clients_dispatches_next(self, client_id: str, *, timeout_seconds: Optional[int] = 30, exp_status: Optional[List[int]] = None, headers: Optional[Dict[str, str]] = None, aspects: Optional[AspectsRest] = None) -> Pendingdispatch:
|
|
19
|
+
"""
|
|
20
|
+
Long-poll for the next signed dispatch envelope.
|
|
21
|
+
|
|
22
|
+
Long-polling pull endpoint the pod-client calls to fetch
|
|
23
|
+
the next signed envelope queued for it by the server
|
|
24
|
+
dispatcher.
|
|
25
|
+
|
|
26
|
+
The server blocks the request for up to `timeout_seconds`
|
|
27
|
+
(default 30, hard cap 60). On a queued dispatch the server
|
|
28
|
+
returns 200 with a `PendingDispatch` body and the record
|
|
29
|
+
is dequeued — the client MUST then POST
|
|
30
|
+
`/runs/{run_id}/dispatch-ack` before the embedded
|
|
31
|
+
`ack_deadline_at`, otherwise the dispatch reconciler will
|
|
32
|
+
roll the attempt back. On a timeout the server returns 204
|
|
33
|
+
and the client immediately re-polls.
|
|
34
|
+
|
|
35
|
+
The cert common-name nginx forwards must match the path
|
|
36
|
+
`client_id` — a mismatch returns 403.
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
client = self.client
|
|
40
|
+
if aspects is None:
|
|
41
|
+
aspects = client.aspects
|
|
42
|
+
|
|
43
|
+
header_params = client.headers
|
|
44
|
+
if headers is not None:
|
|
45
|
+
header_params = headers
|
|
46
|
+
|
|
47
|
+
leaf_template = "/clients/{client_id}/dispatches:next"
|
|
48
|
+
path_params = {
|
|
49
|
+
'client_id': client_id,
|
|
50
|
+
}
|
|
51
|
+
call_leaf = leaf_template.format(**path_params)
|
|
52
|
+
|
|
53
|
+
query_params = {}
|
|
54
|
+
if timeout_seconds is not None:
|
|
55
|
+
query_params['timeout_seconds'] = timeout_seconds
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if exp_status is None:
|
|
59
|
+
exp_status = [200, 204]
|
|
60
|
+
|
|
61
|
+
resp = client.perform_call(
|
|
62
|
+
leaf=call_leaf,
|
|
63
|
+
method="GET",
|
|
64
|
+
params=query_params if query_params else None,
|
|
65
|
+
body=None,
|
|
66
|
+
exp_status=exp_status,
|
|
67
|
+
headers=header_params if header_params else None,
|
|
68
|
+
context_msg=None,
|
|
69
|
+
aspects=aspects,
|
|
70
|
+
)
|
|
71
|
+
if resp.status_code in (204, 205) or (resp.status_code == 202 and len(resp.content) == 0):
|
|
72
|
+
rtnobj = None
|
|
73
|
+
else:
|
|
74
|
+
raw_data = resp.json()
|
|
75
|
+
rtnobj = Pendingdispatch.from_dict(raw_data)
|
|
76
|
+
return rtnobj
|
|
77
|
+
|
|
78
|
+
def clients_get_by_id(self, client_id: str, *, exp_status: Optional[List[int]] = None, headers: Optional[Dict[str, str]] = None, aspects: Optional[AspectsRest] = None) -> Client:
|
|
79
|
+
"""
|
|
80
|
+
Read a client.
|
|
81
|
+
"""
|
|
82
|
+
client = self.client
|
|
83
|
+
if aspects is None:
|
|
84
|
+
aspects = client.aspects
|
|
85
|
+
|
|
86
|
+
header_params = client.headers
|
|
87
|
+
if headers is not None:
|
|
88
|
+
header_params = headers
|
|
89
|
+
|
|
90
|
+
leaf_template = "/clients/{client_id}"
|
|
91
|
+
path_params = {
|
|
92
|
+
'client_id': client_id,
|
|
93
|
+
}
|
|
94
|
+
call_leaf = leaf_template.format(**path_params)
|
|
95
|
+
|
|
96
|
+
query_params = None
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
if exp_status is None:
|
|
100
|
+
exp_status = [200]
|
|
101
|
+
|
|
102
|
+
resp = client.perform_call(
|
|
103
|
+
leaf=call_leaf,
|
|
104
|
+
method="GET",
|
|
105
|
+
params=query_params if query_params else None,
|
|
106
|
+
body=None,
|
|
107
|
+
exp_status=exp_status,
|
|
108
|
+
headers=header_params if header_params else None,
|
|
109
|
+
context_msg=None,
|
|
110
|
+
aspects=aspects,
|
|
111
|
+
)
|
|
112
|
+
if resp.status_code in (204, 205) or (resp.status_code == 202 and len(resp.content) == 0):
|
|
113
|
+
rtnobj = None
|
|
114
|
+
else:
|
|
115
|
+
raw_data = resp.json()
|
|
116
|
+
rtnobj = Client.from_dict(raw_data)
|
|
117
|
+
return rtnobj
|
|
118
|
+
|
|
119
|
+
def clients_heartbeat(self, client_id: str, *, exp_status: Optional[List[int]] = None, headers: Optional[Dict[str, str]] = None, aspects: Optional[AspectsRest] = None) -> Any:
|
|
120
|
+
"""
|
|
121
|
+
Pod-client liveness ping.
|
|
122
|
+
|
|
123
|
+
Lightweight ping the pod-client calls between long-poll
|
|
124
|
+
cycles to keep its registry row `last_seen` current.
|
|
125
|
+
Returns 204 unconditionally on a successful mTLS
|
|
126
|
+
handshake; rows missing from the registry are logged
|
|
127
|
+
server-side and still answered 204.
|
|
128
|
+
|
|
129
|
+
"""
|
|
130
|
+
client = self.client
|
|
131
|
+
if aspects is None:
|
|
132
|
+
aspects = client.aspects
|
|
133
|
+
|
|
134
|
+
header_params = client.headers
|
|
135
|
+
if headers is not None:
|
|
136
|
+
header_params = headers
|
|
137
|
+
|
|
138
|
+
leaf_template = "/clients/{client_id}/heartbeat"
|
|
139
|
+
path_params = {
|
|
140
|
+
'client_id': client_id,
|
|
141
|
+
}
|
|
142
|
+
call_leaf = leaf_template.format(**path_params)
|
|
143
|
+
|
|
144
|
+
query_params = None
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
if exp_status is None:
|
|
148
|
+
exp_status = [204]
|
|
149
|
+
|
|
150
|
+
resp = client.perform_call(
|
|
151
|
+
leaf=call_leaf,
|
|
152
|
+
method="GET",
|
|
153
|
+
params=query_params if query_params else None,
|
|
154
|
+
body=None,
|
|
155
|
+
exp_status=exp_status,
|
|
156
|
+
headers=header_params if header_params else None,
|
|
157
|
+
context_msg=None,
|
|
158
|
+
aspects=aspects,
|
|
159
|
+
)
|
|
160
|
+
if resp.status_code in (204, 205) or (resp.status_code == 202 and len(resp.content) == 0):
|
|
161
|
+
rtnval = None
|
|
162
|
+
else:
|
|
163
|
+
rtnval = resp.json()
|
|
164
|
+
return rtnval
|
|
165
|
+
|
|
166
|
+
def clients_list(self, *, page: Optional[int] = 1, per_page: Optional[int] = 50, exp_status: Optional[List[int]] = None, headers: Optional[Dict[str, str]] = None, aspects: Optional[AspectsRest] = None) -> Dict[str, Any]:
|
|
167
|
+
"""
|
|
168
|
+
List enrolled clients.
|
|
169
|
+
"""
|
|
170
|
+
client = self.client
|
|
171
|
+
if aspects is None:
|
|
172
|
+
aspects = client.aspects
|
|
173
|
+
|
|
174
|
+
header_params = client.headers
|
|
175
|
+
if headers is not None:
|
|
176
|
+
header_params = headers
|
|
177
|
+
|
|
178
|
+
call_leaf = "/clients"
|
|
179
|
+
|
|
180
|
+
query_params = {}
|
|
181
|
+
if page is not None:
|
|
182
|
+
query_params['page'] = page
|
|
183
|
+
if per_page is not None:
|
|
184
|
+
query_params['per_page'] = per_page
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
if exp_status is None:
|
|
188
|
+
exp_status = [200]
|
|
189
|
+
|
|
190
|
+
resp = client.perform_call(
|
|
191
|
+
leaf=call_leaf,
|
|
192
|
+
method="GET",
|
|
193
|
+
params=query_params if query_params else None,
|
|
194
|
+
body=None,
|
|
195
|
+
exp_status=exp_status,
|
|
196
|
+
headers=header_params if header_params else None,
|
|
197
|
+
context_msg=None,
|
|
198
|
+
aspects=aspects,
|
|
199
|
+
)
|
|
200
|
+
if resp.status_code in (204, 205) or (resp.status_code == 202 and len(resp.content) == 0):
|
|
201
|
+
rtnval = None
|
|
202
|
+
else:
|
|
203
|
+
raw_data = resp.json()
|
|
204
|
+
rtnval = self._parse_item(raw_data, Dict[str, Any])
|
|
205
|
+
return rtnval
|
|
206
|
+
|
|
207
|
+
def clients_revoke(self, client_id: str, body: Clientrevokerequest, *, exp_status: Optional[List[int]] = None, headers: Optional[Dict[str, str]] = None, aspects: Optional[AspectsRest] = None) -> Client:
|
|
208
|
+
"""
|
|
209
|
+
Revoke a client's enrollment.
|
|
210
|
+
"""
|
|
211
|
+
client = self.client
|
|
212
|
+
if aspects is None:
|
|
213
|
+
aspects = client.aspects
|
|
214
|
+
|
|
215
|
+
header_params = client.headers
|
|
216
|
+
if headers is not None:
|
|
217
|
+
header_params = headers
|
|
218
|
+
|
|
219
|
+
leaf_template = "/clients/{client_id}/revoke"
|
|
220
|
+
path_params = {
|
|
221
|
+
'client_id': client_id,
|
|
222
|
+
}
|
|
223
|
+
call_leaf = leaf_template.format(**path_params)
|
|
224
|
+
|
|
225
|
+
query_params = None
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
if exp_status is None:
|
|
229
|
+
exp_status = [200]
|
|
230
|
+
|
|
231
|
+
resp = client.perform_call(
|
|
232
|
+
leaf=call_leaf,
|
|
233
|
+
method="POST",
|
|
234
|
+
params=query_params if query_params else None,
|
|
235
|
+
body=body,
|
|
236
|
+
exp_status=exp_status,
|
|
237
|
+
headers=header_params if header_params else None,
|
|
238
|
+
context_msg=None,
|
|
239
|
+
aspects=aspects,
|
|
240
|
+
)
|
|
241
|
+
if resp.status_code in (204, 205) or (resp.status_code == 202 and len(resp.content) == 0):
|
|
242
|
+
rtnobj = None
|
|
243
|
+
else:
|
|
244
|
+
raw_data = resp.json()
|
|
245
|
+
rtnobj = Client.from_dict(raw_data)
|
|
246
|
+
return rtnobj
|
|
247
|
+
|
|
248
|
+
def clients_update_attributes(self, client_id: str, body: Clientattributesupdaterequest, *, exp_status: Optional[List[int]] = None, headers: Optional[Dict[str, str]] = None, aspects: Optional[AspectsRest] = None) -> Client:
|
|
249
|
+
"""
|
|
250
|
+
Replace a client's attributes.
|
|
251
|
+
"""
|
|
252
|
+
client = self.client
|
|
253
|
+
if aspects is None:
|
|
254
|
+
aspects = client.aspects
|
|
255
|
+
|
|
256
|
+
header_params = client.headers
|
|
257
|
+
if headers is not None:
|
|
258
|
+
header_params = headers
|
|
259
|
+
|
|
260
|
+
leaf_template = "/clients/{client_id}/attributes"
|
|
261
|
+
path_params = {
|
|
262
|
+
'client_id': client_id,
|
|
263
|
+
}
|
|
264
|
+
call_leaf = leaf_template.format(**path_params)
|
|
265
|
+
|
|
266
|
+
query_params = None
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
if exp_status is None:
|
|
270
|
+
exp_status = [200]
|
|
271
|
+
|
|
272
|
+
resp = client.perform_call(
|
|
273
|
+
leaf=call_leaf,
|
|
274
|
+
method="PUT",
|
|
275
|
+
params=query_params if query_params else None,
|
|
276
|
+
body=body,
|
|
277
|
+
exp_status=exp_status,
|
|
278
|
+
headers=header_params if header_params else None,
|
|
279
|
+
context_msg=None,
|
|
280
|
+
aspects=aspects,
|
|
281
|
+
)
|
|
282
|
+
if resp.status_code in (204, 205) or (resp.status_code == 202 and len(resp.content) == 0):
|
|
283
|
+
rtnobj = None
|
|
284
|
+
else:
|
|
285
|
+
raw_data = resp.json()
|
|
286
|
+
rtnobj = Client.from_dict(raw_data)
|
|
287
|
+
return rtnobj
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Auto-generated by RestClientGenerator. DO NOT EDIT.
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
from ccai.pychestrate.rest.client.models.dispatch import Dispatchack
|
|
6
|
+
from ccai.pychestrate.rest.client.models.dispatch import Signingkeyset
|
|
7
|
+
from ccai.restclient.base.aspectsrest import AspectsRest
|
|
8
|
+
from ccai.restclient.base.restapigroup import RestApiGroup
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DispatchApiGroup(RestApiGroup):
|
|
12
|
+
"""
|
|
13
|
+
Pod-client → server dispatch acknowledgements.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def dispatch_ack_run(self, run_id: str, body: Dispatchack, *, exp_status: Optional[List[int]] = None, headers: Optional[Dict[str, str]] = None, aspects: Optional[AspectsRest] = None) -> Any:
|
|
17
|
+
"""
|
|
18
|
+
Client agent acknowledges receipt of a dispatched envelope.
|
|
19
|
+
|
|
20
|
+
Posted by the pod client agent over mTLS after it has accepted
|
|
21
|
+
a dispatch and minted a local run identifier. Signals that the
|
|
22
|
+
envelope was received and is being prepared for execution; the
|
|
23
|
+
server transitions the run's state from `DISPATCHING` to
|
|
24
|
+
`DISPATCHED` on success.
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
client = self.client
|
|
28
|
+
if aspects is None:
|
|
29
|
+
aspects = client.aspects
|
|
30
|
+
|
|
31
|
+
header_params = client.headers
|
|
32
|
+
if headers is not None:
|
|
33
|
+
header_params = headers
|
|
34
|
+
|
|
35
|
+
leaf_template = "/runs/{run_id}/dispatch-ack"
|
|
36
|
+
path_params = {
|
|
37
|
+
'run_id': run_id,
|
|
38
|
+
}
|
|
39
|
+
call_leaf = leaf_template.format(**path_params)
|
|
40
|
+
|
|
41
|
+
query_params = None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
if exp_status is None:
|
|
45
|
+
exp_status = [204]
|
|
46
|
+
|
|
47
|
+
resp = client.perform_call(
|
|
48
|
+
leaf=call_leaf,
|
|
49
|
+
method="POST",
|
|
50
|
+
params=query_params if query_params else None,
|
|
51
|
+
body=body,
|
|
52
|
+
exp_status=exp_status,
|
|
53
|
+
headers=header_params if header_params else None,
|
|
54
|
+
context_msg=None,
|
|
55
|
+
aspects=aspects,
|
|
56
|
+
)
|
|
57
|
+
if resp.status_code in (204, 205) or (resp.status_code == 202 and len(resp.content) == 0):
|
|
58
|
+
rtnval = None
|
|
59
|
+
else:
|
|
60
|
+
rtnval = resp.json()
|
|
61
|
+
return rtnval
|
|
62
|
+
|
|
63
|
+
def envelope_signing_keys_list(self, *, exp_status: Optional[List[int]] = None, headers: Optional[Dict[str, str]] = None, aspects: Optional[AspectsRest] = None) -> Signingkeyset:
|
|
64
|
+
"""
|
|
65
|
+
List the Ed25519 public keys used to sign job envelopes.
|
|
66
|
+
|
|
67
|
+
A JWKS-style public-key distribution endpoint. The pod-client
|
|
68
|
+
agent calls this to obtain the Ed25519 public key(s) it must
|
|
69
|
+
verify signed job envelopes against — without the operator
|
|
70
|
+
installing the key out-of-band.
|
|
71
|
+
|
|
72
|
+
Auth: a signing *public* key is not a secret, so the endpoint
|
|
73
|
+
accepts **any authenticated principal** — a cookie session, an
|
|
74
|
+
API key, OR a verified mTLS client certificate. A
|
|
75
|
+
freshly-enrolled pod client already holds its mTLS identity, so
|
|
76
|
+
the mTLS path covers the client's use case. Anonymous requests
|
|
77
|
+
get a 401. The endpoint returns 503 when no signing key has
|
|
78
|
+
been provisioned.
|
|
79
|
+
|
|
80
|
+
The response carries one or more keys to support rotation: at
|
|
81
|
+
most one key is `active` and any others are `retiring`
|
|
82
|
+
(grace-window verify keys). The same key set is also bundled in
|
|
83
|
+
the `POST /enrollment-tokens/redeem` response so the happy path
|
|
84
|
+
needs zero extra calls.
|
|
85
|
+
|
|
86
|
+
"""
|
|
87
|
+
client = self.client
|
|
88
|
+
if aspects is None:
|
|
89
|
+
aspects = client.aspects
|
|
90
|
+
|
|
91
|
+
header_params = client.headers
|
|
92
|
+
if headers is not None:
|
|
93
|
+
header_params = headers
|
|
94
|
+
|
|
95
|
+
call_leaf = "/envelope-signing-keys"
|
|
96
|
+
|
|
97
|
+
query_params = None
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if exp_status is None:
|
|
101
|
+
exp_status = [200]
|
|
102
|
+
|
|
103
|
+
resp = client.perform_call(
|
|
104
|
+
leaf=call_leaf,
|
|
105
|
+
method="GET",
|
|
106
|
+
params=query_params if query_params else None,
|
|
107
|
+
body=None,
|
|
108
|
+
exp_status=exp_status,
|
|
109
|
+
headers=header_params if header_params else None,
|
|
110
|
+
context_msg=None,
|
|
111
|
+
aspects=aspects,
|
|
112
|
+
)
|
|
113
|
+
if resp.status_code in (204, 205) or (resp.status_code == 202 and len(resp.content) == 0):
|
|
114
|
+
rtnobj = None
|
|
115
|
+
else:
|
|
116
|
+
raw_data = resp.json()
|
|
117
|
+
rtnobj = Signingkeyset.from_dict(raw_data)
|
|
118
|
+
return rtnobj
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Auto-generated by RestClientGenerator. DO NOT EDIT.
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
from ccai.pychestrate.rest.client.models.client import Client
|
|
6
|
+
from ccai.pychestrate.rest.client.models.enrollment import Enrollmentredeemrequest
|
|
7
|
+
from ccai.pychestrate.rest.client.models.enrollment import Enrollmentredeemresponse
|
|
8
|
+
from ccai.pychestrate.rest.client.models.enrollment import Enrollmenttokencreaterequest
|
|
9
|
+
from ccai.restclient.base.aspectsrest import AspectsRest
|
|
10
|
+
from ccai.restclient.base.restapigroup import RestApiGroup
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class EnrollmentApiGroup(RestApiGroup):
|
|
14
|
+
"""
|
|
15
|
+
Client-enrollment bootstrap tokens (mTLS issuance).
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def enrollment_create_token(self, body: Enrollmenttokencreaterequest, *, exp_status: Optional[List[int]] = None, headers: Optional[Dict[str, str]] = None, aspects: Optional[AspectsRest] = None) -> Any:
|
|
19
|
+
"""
|
|
20
|
+
Issue a new enrollment token.
|
|
21
|
+
"""
|
|
22
|
+
client = self.client
|
|
23
|
+
if aspects is None:
|
|
24
|
+
aspects = client.aspects
|
|
25
|
+
|
|
26
|
+
header_params = client.headers
|
|
27
|
+
if headers is not None:
|
|
28
|
+
header_params = headers
|
|
29
|
+
|
|
30
|
+
call_leaf = "/enrollment-tokens"
|
|
31
|
+
|
|
32
|
+
query_params = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if exp_status is None:
|
|
36
|
+
exp_status = [201]
|
|
37
|
+
|
|
38
|
+
resp = client.perform_call(
|
|
39
|
+
leaf=call_leaf,
|
|
40
|
+
method="POST",
|
|
41
|
+
params=query_params if query_params else None,
|
|
42
|
+
body=body,
|
|
43
|
+
exp_status=exp_status,
|
|
44
|
+
headers=header_params if header_params else None,
|
|
45
|
+
context_msg=None,
|
|
46
|
+
aspects=aspects,
|
|
47
|
+
)
|
|
48
|
+
if resp.status_code in (204, 205) or (resp.status_code == 202 and len(resp.content) == 0):
|
|
49
|
+
rtnval = None
|
|
50
|
+
else:
|
|
51
|
+
rtnval = resp.json()
|
|
52
|
+
return rtnval
|
|
53
|
+
|
|
54
|
+
def enrollment_delete_token(self, token_id: str, *, exp_status: Optional[List[int]] = None, headers: Optional[Dict[str, str]] = None, aspects: Optional[AspectsRest] = None) -> Any:
|
|
55
|
+
"""
|
|
56
|
+
Revoke an enrollment token.
|
|
57
|
+
"""
|
|
58
|
+
client = self.client
|
|
59
|
+
if aspects is None:
|
|
60
|
+
aspects = client.aspects
|
|
61
|
+
|
|
62
|
+
header_params = client.headers
|
|
63
|
+
if headers is not None:
|
|
64
|
+
header_params = headers
|
|
65
|
+
|
|
66
|
+
leaf_template = "/enrollment-tokens/{token_id}"
|
|
67
|
+
path_params = {
|
|
68
|
+
'token_id': token_id,
|
|
69
|
+
}
|
|
70
|
+
call_leaf = leaf_template.format(**path_params)
|
|
71
|
+
|
|
72
|
+
query_params = None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
if exp_status is None:
|
|
76
|
+
exp_status = [204]
|
|
77
|
+
|
|
78
|
+
resp = client.perform_call(
|
|
79
|
+
leaf=call_leaf,
|
|
80
|
+
method="DELETE",
|
|
81
|
+
params=query_params if query_params else None,
|
|
82
|
+
body=None,
|
|
83
|
+
exp_status=exp_status,
|
|
84
|
+
headers=header_params if header_params else None,
|
|
85
|
+
context_msg=None,
|
|
86
|
+
aspects=aspects,
|
|
87
|
+
)
|
|
88
|
+
if resp.status_code in (204, 205) or (resp.status_code == 202 and len(resp.content) == 0):
|
|
89
|
+
rtnval = None
|
|
90
|
+
else:
|
|
91
|
+
rtnval = resp.json()
|
|
92
|
+
return rtnval
|
|
93
|
+
|
|
94
|
+
def enrollment_list_tokens(self, *, exp_status: Optional[List[int]] = None, headers: Optional[Dict[str, str]] = None, aspects: Optional[AspectsRest] = None) -> Dict[str, Any]:
|
|
95
|
+
"""
|
|
96
|
+
List enrollment tokens.
|
|
97
|
+
"""
|
|
98
|
+
client = self.client
|
|
99
|
+
if aspects is None:
|
|
100
|
+
aspects = client.aspects
|
|
101
|
+
|
|
102
|
+
header_params = client.headers
|
|
103
|
+
if headers is not None:
|
|
104
|
+
header_params = headers
|
|
105
|
+
|
|
106
|
+
call_leaf = "/enrollment-tokens"
|
|
107
|
+
|
|
108
|
+
query_params = None
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
if exp_status is None:
|
|
112
|
+
exp_status = [200]
|
|
113
|
+
|
|
114
|
+
resp = client.perform_call(
|
|
115
|
+
leaf=call_leaf,
|
|
116
|
+
method="GET",
|
|
117
|
+
params=query_params if query_params else None,
|
|
118
|
+
body=None,
|
|
119
|
+
exp_status=exp_status,
|
|
120
|
+
headers=header_params if header_params else None,
|
|
121
|
+
context_msg=None,
|
|
122
|
+
aspects=aspects,
|
|
123
|
+
)
|
|
124
|
+
if resp.status_code in (204, 205) or (resp.status_code == 202 and len(resp.content) == 0):
|
|
125
|
+
rtnval = None
|
|
126
|
+
else:
|
|
127
|
+
raw_data = resp.json()
|
|
128
|
+
rtnval = self._parse_item(raw_data, Dict[str, Any])
|
|
129
|
+
return rtnval
|
|
130
|
+
|
|
131
|
+
def enrollment_redeem(self, body: Enrollmentredeemrequest, *, exp_status: Optional[List[int]] = None, headers: Optional[Dict[str, str]] = None, aspects: Optional[AspectsRest] = None) -> Enrollmentredeemresponse:
|
|
132
|
+
"""
|
|
133
|
+
Redeem an enrollment token for an mTLS identity.
|
|
134
|
+
|
|
135
|
+
The client agent calls this endpoint with the bootstrap token it
|
|
136
|
+
received out-of-band and a CSR; the response carries the signed
|
|
137
|
+
client certificate plus the issued client_id.
|
|
138
|
+
|
|
139
|
+
"""
|
|
140
|
+
client = self.client
|
|
141
|
+
if aspects is None:
|
|
142
|
+
aspects = client.aspects
|
|
143
|
+
|
|
144
|
+
header_params = client.headers
|
|
145
|
+
if headers is not None:
|
|
146
|
+
header_params = headers
|
|
147
|
+
|
|
148
|
+
call_leaf = "/enrollment-tokens/redeem"
|
|
149
|
+
|
|
150
|
+
query_params = None
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
if exp_status is None:
|
|
154
|
+
exp_status = [200]
|
|
155
|
+
|
|
156
|
+
resp = client.perform_call(
|
|
157
|
+
leaf=call_leaf,
|
|
158
|
+
method="POST",
|
|
159
|
+
params=query_params if query_params else None,
|
|
160
|
+
body=body,
|
|
161
|
+
exp_status=exp_status,
|
|
162
|
+
headers=header_params if header_params else None,
|
|
163
|
+
context_msg=None,
|
|
164
|
+
aspects=aspects,
|
|
165
|
+
)
|
|
166
|
+
if resp.status_code in (204, 205) or (resp.status_code == 202 and len(resp.content) == 0):
|
|
167
|
+
rtnobj = None
|
|
168
|
+
else:
|
|
169
|
+
raw_data = resp.json()
|
|
170
|
+
rtnobj = Enrollmentredeemresponse.from_dict(raw_data)
|
|
171
|
+
return rtnobj
|
|
172
|
+
|
|
173
|
+
def enrollment_revoke_client(self, client_id: str, *, exp_status: Optional[List[int]] = None, headers: Optional[Dict[str, str]] = None, aspects: Optional[AspectsRest] = None) -> Client:
|
|
174
|
+
"""
|
|
175
|
+
Revoke an enrolled client's mTLS identity.
|
|
176
|
+
"""
|
|
177
|
+
client = self.client
|
|
178
|
+
if aspects is None:
|
|
179
|
+
aspects = client.aspects
|
|
180
|
+
|
|
181
|
+
header_params = client.headers
|
|
182
|
+
if headers is not None:
|
|
183
|
+
header_params = headers
|
|
184
|
+
|
|
185
|
+
leaf_template = "/enrollment-tokens/clients/{client_id}/revoke"
|
|
186
|
+
path_params = {
|
|
187
|
+
'client_id': client_id,
|
|
188
|
+
}
|
|
189
|
+
call_leaf = leaf_template.format(**path_params)
|
|
190
|
+
|
|
191
|
+
query_params = None
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
if exp_status is None:
|
|
195
|
+
exp_status = [200]
|
|
196
|
+
|
|
197
|
+
resp = client.perform_call(
|
|
198
|
+
leaf=call_leaf,
|
|
199
|
+
method="POST",
|
|
200
|
+
params=query_params if query_params else None,
|
|
201
|
+
body=None,
|
|
202
|
+
exp_status=exp_status,
|
|
203
|
+
headers=header_params if header_params else None,
|
|
204
|
+
context_msg=None,
|
|
205
|
+
aspects=aspects,
|
|
206
|
+
)
|
|
207
|
+
if resp.status_code in (204, 205) or (resp.status_code == 202 and len(resp.content) == 0):
|
|
208
|
+
rtnobj = None
|
|
209
|
+
else:
|
|
210
|
+
raw_data = resp.json()
|
|
211
|
+
rtnobj = Client.from_dict(raw_data)
|
|
212
|
+
return rtnobj
|