@kici-dev/orchestrator 0.9.1 → 0.11.0
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.
- package/dist/__test-helpers__/test-db.d.ts +14 -1
- package/dist/agent/dispatcher.d.ts +137 -41
- package/dist/agent/registry.d.ts +79 -2
- package/dist/app.d.ts +2 -0
- package/dist/cancel/cancel-held-run.d.ts +68 -0
- package/dist/cancel/cancel-route-answer.d.ts +21 -0
- package/dist/cancel/cancel-run.d.ts +32 -0
- package/dist/cli/api-client.d.ts +23 -1
- package/dist/cli/commands/attestations.d.ts +10 -0
- package/dist/cli/commands/cold-store-impl.d.ts +3 -3
- package/dist/cli/commands/cold-store.d.ts +6 -3
- package/dist/cli/commands/context.d.ts +6 -2
- package/dist/cli/commands/dashboard-encryption-key.d.ts +18 -0
- package/dist/cli/commands/event-dlq.d.ts +2 -2
- package/dist/cli/commands/registration.d.ts +8 -4
- package/dist/cli/commands/runs.d.ts +7 -0
- package/dist/cli/commands/secret.d.ts +1 -0
- package/dist/cli/commands/shared/confirm.d.ts +19 -0
- package/dist/cli/commands/shared/unbound-context-warning.d.ts +43 -0
- package/dist/cli/commands/signing-key.d.ts +22 -1
- package/dist/cli.js +1522 -871
- package/dist/cluster/cluster-settings-reader.d.ts +1 -1
- package/dist/cluster/coordinator.d.ts +2 -0
- package/dist/cluster/live-coordinator-peer.d.ts +13 -0
- package/dist/config.d.ts +9 -0
- package/dist/contexts/context-store.d.ts +3 -2
- package/dist/contexts/protection/satisfiability.d.ts +6 -3
- package/dist/contexts/variable-store.d.ts +2 -0
- package/dist/db/migrations/145_execution_runs_workflow_provenance.d.ts +4 -0
- package/dist/db/migrations/146_pending_job_contexts_context_resolution.d.ts +4 -0
- package/dist/db/migrations/147_sealed_job_secrets.d.ts +19 -0
- package/dist/db/migrations/148_cluster_settings_sealed_secrets_retry_backoff_ms.d.ts +21 -0
- package/dist/db/migrations/149_workflow_registrations_dep_cache_key.d.ts +4 -0
- package/dist/db/migrations/150_execution_runs_status_epoch.d.ts +18 -0
- package/dist/db/migrations/151_workflow_registrations_dep_cache_key_sha.d.ts +4 -0
- package/dist/db/repos/signing-keys-repo.d.ts +48 -3
- package/dist/db/types.d.ts +81 -1
- package/dist/git/clone-token-auth.d.ts +7 -0
- package/dist/git/dispatch-git-auth.d.ts +63 -0
- package/dist/index.js +26 -0
- package/dist/lockfile-validate.d.ts +4 -2
- package/dist/metrics/prometheus.d.ts +1 -1
- package/dist/oidc/id-token-claims.d.ts +10 -0
- package/dist/oidc/oidc-mint-registration.d.ts +2 -0
- package/dist/oidc/orchestrator-mint.d.ts +25 -4
- package/dist/oidc/reconcile-signing-key.d.ts +31 -6
- package/dist/oidc/resolve-signer.d.ts +12 -6
- package/dist/pipeline/decorating-secret-resolver.d.ts +5 -3
- package/dist/pipeline/dispatch-matched-workflow.d.ts +105 -13
- package/dist/pipeline/dispatch-matched-workflow.test-helpers.d.ts +121 -0
- package/dist/pipeline/global-dispatch-identity.d.ts +76 -0
- package/dist/pipeline/global-dispatch.d.ts +91 -0
- package/dist/pipeline/global-eval-round.d.ts +56 -4
- package/dist/pipeline/global-round-hold.d.ts +41 -0
- package/dist/pipeline/held-context-data.d.ts +143 -0
- package/dist/pipeline/held-round-registrations.d.ts +40 -0
- package/dist/pipeline/install-gate.d.ts +93 -0
- package/dist/pipeline/install-secrets-resolver.d.ts +28 -13
- package/dist/pipeline/job-contexts.d.ts +21 -6
- package/dist/pipeline/pending-workflow-context.d.ts +15 -3
- package/dist/pipeline/process-webhook.d.ts +38 -1
- package/dist/pipeline/processor.d.ts +20 -0
- package/dist/pipeline/rerun-global.d.ts +28 -0
- package/dist/pipeline/rerun-inputs.d.ts +88 -0
- package/dist/pipeline/rerun.d.ts +25 -2
- package/dist/pipeline/resume-workflow.d.ts +36 -2
- package/dist/pipeline/unbound-job-context.d.ts +34 -0
- package/dist/pipeline/workflow-lock-at-sha.d.ts +67 -0
- package/dist/provenance/backfill-run.d.ts +5 -0
- package/dist/providers/github/check-status-poster.d.ts +4 -16
- package/dist/queue/job-queue.d.ts +127 -10
- package/dist/queue/terminalize-unroutable.d.ts +37 -4
- package/dist/registration/registration-index.d.ts +13 -1
- package/dist/registration/registration-store.d.ts +10 -1
- package/dist/reporting/execution-tracker.d.ts +149 -8
- package/dist/reporting/log-chunk-sink.d.ts +1 -1
- package/dist/reporting/log-writer.d.ts +14 -0
- package/dist/reporting/step-log-path.d.ts +8 -0
- package/dist/reporting/step-log-reader.d.ts +21 -3
- package/dist/routes/admin-contexts.d.ts +6 -0
- package/dist/routes/admin-registrations.d.ts +2 -2
- package/dist/routes/admin-signing-keys.d.ts +33 -0
- package/dist/scaler/agent-fit.d.ts +159 -0
- package/dist/scaler/container-routing.d.ts +16 -16
- package/dist/scaler/manager.d.ts +23 -17
- package/dist/secrets/audit-logger.d.ts +1 -1
- package/dist/secrets/context-secret-resolver.d.ts +1 -1
- package/dist/secrets/index.d.ts +1 -1
- package/dist/secrets/job-secret-gate.d.ts +25 -3
- package/dist/secrets/job-secret-seal.d.ts +36 -0
- package/dist/secrets/master-key-rotation.d.ts +7 -3
- package/dist/secrets/secret-resolver.d.ts +42 -23
- package/dist/server.js +27611 -23219
- package/dist/standalone.js +58327 -53119
- package/dist/worker/in-memory-job-queue.d.ts +12 -3
- package/dist/worker/reroute-dispatch.d.ts +35 -0
- package/dist/ws/agent-handler.d.ts +23 -10
- package/dist/ws/git-credential-relay.d.ts +16 -3
- package/installer-image-digests.json +3 -3
- package/package.json +4 -4
- package/sbom.spdx.json +53 -53
|
@@ -2,9 +2,16 @@
|
|
|
2
2
|
* Teardown helper for tests that create their own PostgreSQL database.
|
|
3
3
|
*/
|
|
4
4
|
import type pg from 'pg';
|
|
5
|
+
/** Backends still hold the database after they were terminated and waited on. */
|
|
6
|
+
export declare class TestDbBackendsRemainError extends Error {
|
|
7
|
+
readonly dbName: string;
|
|
8
|
+
readonly remaining: number;
|
|
9
|
+
constructor(dbName: string, remaining: number);
|
|
10
|
+
}
|
|
5
11
|
/**
|
|
6
12
|
* Terminate whatever backends still hold `dbName`, after first waiting for
|
|
7
|
-
* the connections the test itself closed to finish closing
|
|
13
|
+
* the connections the test itself closed to finish closing, then wait for the
|
|
14
|
+
* terminated backends to exit.
|
|
8
15
|
*
|
|
9
16
|
* `pool.end()` — and Kysely's `destroy()`, which calls it — resolves as soon
|
|
10
17
|
* as every client has SENT its Terminate message, not when its socket has
|
|
@@ -14,8 +21,14 @@ import type pg from 'pg';
|
|
|
14
21
|
* test file after every test in it passed. So this polls `pg_stat_activity`
|
|
15
22
|
* until the database has no backend left (bounded by `timeoutMs`), and
|
|
16
23
|
* terminates only what is still there — a connection the test never closed.
|
|
24
|
+
*
|
|
25
|
+
* A terminated backend stays in `pg_stat_activity` until it has exited, and
|
|
26
|
+
* `DROP DATABASE` fails while it is listed. So after the terminate this polls
|
|
27
|
+
* again until the count is zero, bounded by `exitTimeoutMs`, and throws
|
|
28
|
+
* {@link TestDbBackendsRemainError} if the bound passes.
|
|
17
29
|
*/
|
|
18
30
|
export declare function terminateTestDbBackends(admin: pg.Pool, dbName: string, opts?: {
|
|
19
31
|
timeoutMs?: number;
|
|
32
|
+
exitTimeoutMs?: number;
|
|
20
33
|
}): Promise<void>;
|
|
21
34
|
//# sourceMappingURL=test-db.d.ts.map
|
|
@@ -2,6 +2,7 @@ import type { AgentRegistry } from './registry.js';
|
|
|
2
2
|
import { type JobQueue, type QueuedJob, type QueuedJobInput } from '../queue/job-queue.js';
|
|
3
3
|
import type { ScaleResult, ScalerRedispatchTrigger } from '../scaler/types.js';
|
|
4
4
|
import type { ResolvedContainerSpawn } from '../scaler/types.js';
|
|
5
|
+
import { type ScalerAgentView } from '../scaler/agent-fit.js';
|
|
5
6
|
import type { ResourceRequest } from '@kici-dev/engine';
|
|
6
7
|
/**
|
|
7
8
|
* Why a freed agent's queue drain claimed nothing.
|
|
@@ -63,6 +64,10 @@ export interface HostRosterRebootStore {
|
|
|
63
64
|
* released and onDispatch is NOT called). The reroute caller should treat the
|
|
64
65
|
* job as already handled. Only reachable on a reroute re-dispatch — first-
|
|
65
66
|
* dispatch paths use a fresh UUID that can never collide.
|
|
67
|
+
*
|
|
68
|
+
* `queued` also answers a direct dispatch refused because the job's run has
|
|
69
|
+
* stopped: the queue row is recorded `expired` and the job cancelled, the
|
|
70
|
+
* state a cancel leaves a queued job of its run in.
|
|
66
71
|
*/
|
|
67
72
|
type DispatchResult = {
|
|
68
73
|
status: 'dispatched';
|
|
@@ -89,6 +94,16 @@ export declare function containerSpawnFor(jobConfig: Record<string, unknown> | u
|
|
|
89
94
|
serveraddress: string;
|
|
90
95
|
} | undefined;
|
|
91
96
|
} | undefined;
|
|
97
|
+
/**
|
|
98
|
+
* What an `onDispatch` callback returns when it refuses to put a job on the
|
|
99
|
+
* wire. The dispatcher fails the job permanently with `refused` as the reason
|
|
100
|
+
* instead of arming an ack deadline for a message that was never sent.
|
|
101
|
+
*/
|
|
102
|
+
export interface DispatchRefusal {
|
|
103
|
+
refused: string;
|
|
104
|
+
}
|
|
105
|
+
/** The callback that sends a dispatched job to its agent. */
|
|
106
|
+
export type OnDispatch = (agentId: string, job: QueuedJob) => void | DispatchRefusal | Promise<void | DispatchRefusal>;
|
|
92
107
|
export declare class Dispatcher {
|
|
93
108
|
private readonly registry;
|
|
94
109
|
private readonly queue;
|
|
@@ -96,9 +111,7 @@ export declare class Dispatcher {
|
|
|
96
111
|
private readonly onDispatch;
|
|
97
112
|
private readonly onNoMatchingAgent?;
|
|
98
113
|
/** See the constructor dep of the same name. */
|
|
99
|
-
private readonly
|
|
100
|
-
/** See the constructor dep of the same name. */
|
|
101
|
-
private readonly isPrespawnedAgent?;
|
|
114
|
+
private readonly scalerAgentView?;
|
|
102
115
|
/**
|
|
103
116
|
* Single-flight guard for `retryPendingScaleRequests`. The capacity-freed
|
|
104
117
|
* hook and the leader-gated sweep can both fire concurrently; this prevents
|
|
@@ -189,11 +202,13 @@ export declare class Dispatcher {
|
|
|
189
202
|
/** Coordinator drain predicate; when true, new jobs queue Pending instead of
|
|
190
203
|
* dispatching. Defaults to never-draining. */
|
|
191
204
|
private readonly isDraining;
|
|
205
|
+
/** Whether another coordinator is live. Defaults to none (a single node). */
|
|
206
|
+
private readonly hasPeerCoordinators;
|
|
192
207
|
constructor(deps: {
|
|
193
208
|
registry: AgentRegistry;
|
|
194
209
|
queue: JobQueue;
|
|
195
210
|
metrics: DispatchMetrics;
|
|
196
|
-
onDispatch:
|
|
211
|
+
onDispatch: OnDispatch;
|
|
197
212
|
/** Optional hook called when no agent matches the job's labels.
|
|
198
213
|
* When set, receives the per-job `resources` so the scaler can apply
|
|
199
214
|
* per-scaler / per-orchestrator / per-machine caps before spawning. */
|
|
@@ -205,26 +220,14 @@ export declare class Dispatcher {
|
|
|
205
220
|
*/
|
|
206
221
|
containerSpawn?: ResolvedContainerSpawn) => Promise<ScaleResult>;
|
|
207
222
|
/**
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*/
|
|
215
|
-
canPrespawnedAgentServe?: (agentId: string, job: {
|
|
216
|
-
resources?: ResourceRequest;
|
|
217
|
-
hasOwnContainerImage: boolean;
|
|
218
|
-
}) => boolean;
|
|
219
|
-
/**
|
|
220
|
-
* Whether this scaler pre-spawned the agent, i.e. whether
|
|
221
|
-
* `canPrespawnedAgentServe` can ever answer false for it. The queue drain
|
|
222
|
-
* (agent asks for work, rather than job looks for an agent) uses it to
|
|
223
|
-
* decide whether the suitability predicate is worth carrying into the
|
|
224
|
-
* claim: for every ordinary agent it is not, and the drain keeps its
|
|
225
|
-
* single-statement fast path.
|
|
223
|
+
* What the scaler knows about an agent it started
|
|
224
|
+
* (`ScalerManager.agentView`), or undefined for one it did not. It feeds
|
|
225
|
+
* `canAgentRunJob`: the job the agent was started for, whether it runs in
|
|
226
|
+
* that job's image, and a warm agent's fixed shape. Absent when no scaler
|
|
227
|
+
* is configured; the predicate then judges every agent on its own
|
|
228
|
+
* registration.
|
|
226
229
|
*/
|
|
227
|
-
|
|
230
|
+
scalerAgentView?: (agentId: string) => ScalerAgentView | undefined;
|
|
228
231
|
/** Max reconnection delay from agent config (default 60s). Used to derive grace period. */
|
|
229
232
|
maxReconnectDelayMs?: number;
|
|
230
233
|
/** Callback fired when a job is permanently failed before/outside agent execution. */
|
|
@@ -247,6 +250,13 @@ export declare class Dispatcher {
|
|
|
247
250
|
* Pending and onAgentAvailable() claims nothing — jobs already on agents
|
|
248
251
|
* finish. Defaults to never-draining. */
|
|
249
252
|
isDraining?: () => boolean;
|
|
253
|
+
/**
|
|
254
|
+
* Whether another coordinator is live: connected, or disconnected for less
|
|
255
|
+
* than the peer flap grace. A job whose sealed secrets this coordinator
|
|
256
|
+
* cannot open is put back for such a peer; with none, no coordinator can
|
|
257
|
+
* open it, so it fails at once. Defaults to none.
|
|
258
|
+
*/
|
|
259
|
+
hasPeerCoordinators?: () => boolean | Promise<boolean>;
|
|
250
260
|
});
|
|
251
261
|
/**
|
|
252
262
|
* Dispatch a job to a matching agent, or queue it if none available.
|
|
@@ -273,9 +283,20 @@ export declare class Dispatcher {
|
|
|
273
283
|
* overlapping hook+sweep cannot double-offer the same jobs. Bounded by
|
|
274
284
|
* `maxJobs` so one free event cannot storm the scaler.
|
|
275
285
|
*
|
|
286
|
+
* A job whose sealed secrets this coordinator cannot open is never scaled
|
|
287
|
+
* for: it is settled instead ({@link settleUnopenablePending}).
|
|
288
|
+
*
|
|
276
289
|
* @returns the number of jobs that entered `spawning`.
|
|
277
290
|
*/
|
|
278
291
|
retryPendingScaleRequests(maxJobs?: number, trigger?: ScalerRedispatchTrigger): Promise<number>;
|
|
292
|
+
/**
|
|
293
|
+
* Release the slot claimed for a direct dispatch the queue refused because
|
|
294
|
+
* the job's run has stopped. Nothing is sent to the agent. The queue already
|
|
295
|
+
* recorded the row `expired` and cancelled the job, so the job reads as a
|
|
296
|
+
* queued job of the run that the cancel expired, and the caller tracks it
|
|
297
|
+
* under `queued` exactly as it would that one.
|
|
298
|
+
*/
|
|
299
|
+
private refuseStoppedRunDispatch;
|
|
279
300
|
/**
|
|
280
301
|
* Dispatch a host-fanout pinned child. The job targets exactly
|
|
281
302
|
* `job.pinnedAgentId`: if that agent is locally connected, satisfies the
|
|
@@ -295,11 +316,16 @@ export declare class Dispatcher {
|
|
|
295
316
|
* still pending and the agent's labels still satisfy it), marks it
|
|
296
317
|
* dispatched, and sends it to the agent.
|
|
297
318
|
*
|
|
298
|
-
* Returns true
|
|
299
|
-
* elsewhere, expired, or the
|
|
300
|
-
*
|
|
319
|
+
* Returns true only when the job was sent to the agent. False when nothing
|
|
320
|
+
* was claimed (the bound job was already claimed elsewhere, expired, or the
|
|
321
|
+
* agent isn't registered, is full or the coordinator is draining), and also
|
|
322
|
+
* when the claimed job was not sent: its dispatch was refused and it failed,
|
|
323
|
+
* or this coordinator could not open its sealed secrets. The caller falls
|
|
324
|
+
* back to the generic onAgentAvailable() drain in every false case.
|
|
301
325
|
*/
|
|
302
326
|
dispatchBoundJob(agentId: string, jobId: string): Promise<boolean>;
|
|
327
|
+
/** {@link dispatchBoundJob}, reporting whether the job was claimed apart from whether it was sent. */
|
|
328
|
+
private claimBoundJob;
|
|
303
329
|
/**
|
|
304
330
|
* Try draining the queue for a specific agent.
|
|
305
331
|
* Called when an agent registers or completes a job.
|
|
@@ -314,19 +340,24 @@ export declare class Dispatcher {
|
|
|
314
340
|
*/
|
|
315
341
|
private filterRebootPending;
|
|
316
342
|
/**
|
|
317
|
-
* Drop
|
|
343
|
+
* Drop the agents that cannot run this job (`canAgentRunJob`). Sibling of
|
|
318
344
|
* {@link filterRebootPending}: both remove candidates `findAvailable` matched
|
|
319
345
|
* on labels but that are unusable for a reason labels cannot express.
|
|
320
346
|
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
347
|
+
* The reasons: an agent started inside another job's image, a container job
|
|
348
|
+
* on an agent that reports no container runtime, a warm agent of another
|
|
349
|
+
* shape. Dropping the candidate here is what sends the job down the ordinary
|
|
350
|
+
* `onNoMatchingAgent` scale path.
|
|
351
|
+
*
|
|
352
|
+
* `jobId` is the job's queue id when it has one: it is how the agent started
|
|
353
|
+
* for the job recognizes it.
|
|
325
354
|
*/
|
|
326
|
-
private
|
|
355
|
+
private filterUnservableAgents;
|
|
356
|
+
/** The registration facts, and the scaler's record, `canAgentRunJob` judges an agent on. */
|
|
357
|
+
private fitAgentFor;
|
|
327
358
|
/**
|
|
328
|
-
* The fit question for one job: the shape it declares, and
|
|
329
|
-
* its
|
|
359
|
+
* The fit question for one job: its queue id, the shape it declares, and
|
|
360
|
+
* what its `container:` asks of the agent's host.
|
|
330
361
|
*
|
|
331
362
|
* The shape comes from `jobConfig.resources` when the typed `resources`
|
|
332
363
|
* mirror is absent, because the mirror is optional and several dispatch paths
|
|
@@ -336,16 +367,16 @@ export declare class Dispatcher {
|
|
|
336
367
|
* declares nothing, which admits it onto a pre-spawned agent of some other
|
|
337
368
|
* size — the exact mismatch this gate exists to refuse.
|
|
338
369
|
*/
|
|
339
|
-
private
|
|
370
|
+
private agentFitFor;
|
|
340
371
|
/**
|
|
341
|
-
* The queue-drain half of {@link
|
|
372
|
+
* The queue-drain half of {@link filterUnservableAgents}: a per-job
|
|
342
373
|
* predicate for one agent, or undefined when this agent needs no check.
|
|
343
374
|
*
|
|
344
|
-
* Undefined is the common answer
|
|
345
|
-
*
|
|
346
|
-
*
|
|
375
|
+
* Undefined is the common answer for an agent that runs any job: the
|
|
376
|
+
* predicate could only ever say yes, and returning one would cost the drain
|
|
377
|
+
* its single-statement fast path for nothing.
|
|
347
378
|
*/
|
|
348
|
-
private
|
|
379
|
+
private agentFitFilterFor;
|
|
349
380
|
/**
|
|
350
381
|
* Release a reboot-pending host on its real reconnect (down-then-up). Clears
|
|
351
382
|
* the persisted flag so the very next `onAgentAvailable` drain dispatches the
|
|
@@ -361,8 +392,69 @@ export declare class Dispatcher {
|
|
|
361
392
|
* Returns the reason nothing was dispatched, or null when a job was.
|
|
362
393
|
*/
|
|
363
394
|
private drainForAgent;
|
|
395
|
+
/** {@link deliver} inside the job's own request context, restored for a queue-drained job. */
|
|
396
|
+
private deliverInRequestContext;
|
|
397
|
+
/**
|
|
398
|
+
* Hand a tracked job to `onDispatch`. Returns false when the job was not sent:
|
|
399
|
+
* either the callback refused it, and the job is failed permanently since the
|
|
400
|
+
* refusal is a fact about the job and another agent would refuse it too; or
|
|
401
|
+
* this coordinator cannot open its sealed secrets, and the job is put back so
|
|
402
|
+
* a coordinator holding the key can take it, or failed when none can
|
|
403
|
+
* ({@link releaseUnopenableDispatch}).
|
|
404
|
+
*/
|
|
405
|
+
private deliver;
|
|
406
|
+
/**
|
|
407
|
+
* Handle a claimed job whose sealed secrets this coordinator cannot open: it
|
|
408
|
+
* was sealed with a master key this coordinator does not hold.
|
|
409
|
+
*
|
|
410
|
+
* With another coordinator live this is not a permanent refusal: during a
|
|
411
|
+
* rolling master-key rotation that peer may already hold the new key, and if
|
|
412
|
+
* it does, its own drains can take the job. The row returns to pending,
|
|
413
|
+
* spending one dispatch attempt and recording the reason as the job's
|
|
414
|
+
* provisioning error (what an expiry reports), and this coordinator stops
|
|
415
|
+
* offering the job for the sealed-secrets back-off. Once the back-off lapses
|
|
416
|
+
* its drains and periodic re-drives offer the job again like any other, so a
|
|
417
|
+
* job no coordinator can open is claimed again and fails with the reason once
|
|
418
|
+
* {@link MAX_DISPATCH_ATTEMPTS} is reached. With no other coordinator live
|
|
419
|
+
* nobody can open it, so it fails at once.
|
|
420
|
+
*
|
|
421
|
+
* `agentId` is the agent the job was claimed for, or undefined when a re-drive
|
|
422
|
+
* claimed it for no agent ({@link settleUnopenablePending}).
|
|
423
|
+
*/
|
|
424
|
+
private releaseUnopenableDispatch;
|
|
425
|
+
/**
|
|
426
|
+
* Settle a pending job whose sealed secrets this coordinator cannot open,
|
|
427
|
+
* found by a re-drive that would otherwise scale for it.
|
|
428
|
+
*
|
|
429
|
+
* Scaling for the job is wrong twice over. The registry credentials of a
|
|
430
|
+
* private image are sealed with the job's other secrets, so a spawn of that
|
|
431
|
+
* image pulls without them and fails before any agent registers: the job is
|
|
432
|
+
* never claimed, never spends an attempt, and every re-drive spawns again.
|
|
433
|
+
* And any agent a spawn does start is one this coordinator would hand the job
|
|
434
|
+
* back from. So the job is claimed by id for no agent and gets the decision a
|
|
435
|
+
* drain that claimed it would give it ({@link releaseUnopenableDispatch}). A
|
|
436
|
+
* claim lost to another coordinator, or refused inside the back-off, leaves
|
|
437
|
+
* the job alone.
|
|
438
|
+
*/
|
|
439
|
+
private settleUnopenablePending;
|
|
440
|
+
/**
|
|
441
|
+
* Undo the dispatch accounting of a refused job and fail it with the refusal
|
|
442
|
+
* reason. `agentId` is undefined for a job claimed for no agent.
|
|
443
|
+
*/
|
|
444
|
+
private failRefusedDispatch;
|
|
445
|
+
/** Free the slot and tracking a claim took on its agent; a claim for no agent took none. */
|
|
446
|
+
private releaseClaimAccounting;
|
|
364
447
|
/** Record that a job began executing on its agent. */
|
|
365
448
|
markJobStarted(jobId: string): void;
|
|
449
|
+
/**
|
|
450
|
+
* The agent accepted `jobId` (a `job.ack`, or the `running` status that stands
|
|
451
|
+
* in for a lost one). Drop a busy hold that already ran out: a job accepted
|
|
452
|
+
* while it sits on the entry was dispatched after it expired, into a free
|
|
453
|
+
* slot, so the agent's job count is not stuck and its next teardown-window
|
|
454
|
+
* rejection must not spend an attempt. A hold still in force is kept — see
|
|
455
|
+
* {@link AgentRegistry.clearExpiredBusyHold}.
|
|
456
|
+
*/
|
|
457
|
+
private noteJobAccepted;
|
|
366
458
|
/**
|
|
367
459
|
* Arm the ack deadline for a just-sent dispatch (timer + persisted row).
|
|
368
460
|
*
|
|
@@ -400,7 +492,8 @@ export declare class Dispatcher {
|
|
|
400
492
|
/**
|
|
401
493
|
* Requeue a dispatched job for re-delivery, or fail it permanently when
|
|
402
494
|
* its attempt budget is exhausted. Returns the outcome so disconnect
|
|
403
|
-
* triage can surface failed job IDs to the caller.
|
|
495
|
+
* triage can surface failed job IDs to the caller. `countAttempt: false`
|
|
496
|
+
* requeues without spending the budget (a busy rejection).
|
|
404
497
|
*/
|
|
405
498
|
private requeueOrFail;
|
|
406
499
|
/**
|
|
@@ -443,6 +536,9 @@ export declare class Dispatcher {
|
|
|
443
536
|
* It never consults the scaler (that is `retryPendingScaleRequests`) and never
|
|
444
537
|
* spawns: it only places jobs onto agents already connected here.
|
|
445
538
|
*
|
|
539
|
+
* Returns the number of jobs sent. A job it claims but does not send (its
|
|
540
|
+
* dispatch refused, or its sealed secrets unopenable here) is not counted.
|
|
541
|
+
*
|
|
446
542
|
* A failure propagates to the caller rather than being swallowed here — the
|
|
447
543
|
* per-coord interval wrapper is the single error-log site, matching the
|
|
448
544
|
* sibling recovery/ack sweeps that share its cadence. The `finally` only
|
package/dist/agent/registry.d.ts
CHANGED
|
@@ -9,7 +9,28 @@
|
|
|
9
9
|
* No persistence needed -- agents re-register on reconnect.
|
|
10
10
|
*/
|
|
11
11
|
import { type CanonicalLabel, type LabelMatcher } from '@kici-dev/engine';
|
|
12
|
-
import type { WsLike } from '@kici-dev/engine';
|
|
12
|
+
import type { AgentCapabilities, WsLike } from '@kici-dev/engine';
|
|
13
|
+
/**
|
|
14
|
+
* The longest a busy rejection holds an agent out of routing when no evidence
|
|
15
|
+
* of a free slot lifts the hold first: an `agent.status` capacity report, or a
|
|
16
|
+
* job on the agent reaching a final status.
|
|
17
|
+
*/
|
|
18
|
+
export declare const BUSY_HOLD_MAX_MS = 30000;
|
|
19
|
+
/** What {@link AgentRegistry.markBusyHeld} found on the agent. */
|
|
20
|
+
export declare enum BusyHoldOutcome {
|
|
21
|
+
/** No hold was on the agent: it last reported an empty slot, or never rejected. */
|
|
22
|
+
Held = "held",
|
|
23
|
+
/** A hold that had run out was still on the agent: it never reported an empty slot. */
|
|
24
|
+
ReheldAfterExpiry = "reheld-after-expiry",
|
|
25
|
+
/** The agent is not in the registry. */
|
|
26
|
+
NotRegistered = "not-registered"
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Whether an agent can take one more job now: a free slot, and no busy hold
|
|
30
|
+
* in force ({@link AgentRegistry.markBusyHeld}). Draining is checked by the
|
|
31
|
+
* callers that route around it.
|
|
32
|
+
*/
|
|
33
|
+
export declare function agentHasFreeSlot(entry: AgentEntry, now?: number): boolean;
|
|
13
34
|
export type { WsLike } from '@kici-dev/engine';
|
|
14
35
|
/**
|
|
15
36
|
* A single tracked agent connection.
|
|
@@ -68,6 +89,11 @@ export interface AgentEntry {
|
|
|
68
89
|
* WebSocket close that removes the entry — there is nothing to outlive.
|
|
69
90
|
*/
|
|
70
91
|
draining: boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Epoch ms until which the agent is held out of routing after it rejected a
|
|
94
|
+
* dispatch as busy. Unset when no hold is in force. See {@link AgentRegistry.markBusyHeld}.
|
|
95
|
+
*/
|
|
96
|
+
busyHeldUntil?: number;
|
|
71
97
|
/** Number of jobs currently executing on this agent. */
|
|
72
98
|
activeJobs: number;
|
|
73
99
|
/** Maximum concurrent jobs this agent can handle (default 1). */
|
|
@@ -82,6 +108,11 @@ export interface AgentEntry {
|
|
|
82
108
|
registeredAt: number;
|
|
83
109
|
/** Self-reported agent version (e.g. "0.0.1"). Null if not reported. */
|
|
84
110
|
version: string | null;
|
|
111
|
+
/**
|
|
112
|
+
* Optional behaviours the agent advertised on `agent.register`. Null for an
|
|
113
|
+
* agent that advertised none, which is read as supporting none.
|
|
114
|
+
*/
|
|
115
|
+
capabilities: AgentCapabilities | null;
|
|
85
116
|
/**
|
|
86
117
|
* The `agent_tokens.id` row used to authenticate this connection, or
|
|
87
118
|
* `null` when auth mode is `none`. Indexed by `tokenIdIndex` so a
|
|
@@ -149,6 +180,8 @@ interface AgentMetadata {
|
|
|
149
180
|
* any operator-declared properties). Undefined ⇒ the agent reported none.
|
|
150
181
|
*/
|
|
151
182
|
properties?: Record<string, string | number | boolean>;
|
|
183
|
+
/** Optional behaviours the agent advertised on `agent.register`. */
|
|
184
|
+
capabilities?: AgentCapabilities;
|
|
152
185
|
}
|
|
153
186
|
/**
|
|
154
187
|
* Subset of `HostRosterStore` the registry reconciles into. Optional — when no
|
|
@@ -324,7 +357,13 @@ export declare class AgentRegistry {
|
|
|
324
357
|
* an off-gate gated agent as "matching but busy" and skip the peer
|
|
325
358
|
* reroute path even though the local agent can never accept the job.
|
|
326
359
|
*/
|
|
327
|
-
hasMatchingAgent(requiredLabels: string[], requiredPatterns?: LabelMatcher[], excludeLabels?: string[], excludePatterns?: LabelMatcher[]
|
|
360
|
+
hasMatchingAgent(requiredLabels: string[], requiredPatterns?: LabelMatcher[], excludeLabels?: string[], excludePatterns?: LabelMatcher[],
|
|
361
|
+
/**
|
|
362
|
+
* An extra test a label-matching agent must pass: whether it can run the
|
|
363
|
+
* job at all, which its labels cannot express. An agent that matches but
|
|
364
|
+
* never could is not a reason to keep the job here rather than reroute it.
|
|
365
|
+
*/
|
|
366
|
+
canRun?: (entry: AgentEntry) => boolean): boolean;
|
|
328
367
|
/**
|
|
329
368
|
* Internal helper: intersect the per-label candidate sets to find agentIds
|
|
330
369
|
* that satisfy `requiredLabels`. Returns `null` when any required label
|
|
@@ -387,6 +426,44 @@ export declare class AgentRegistry {
|
|
|
387
426
|
* @returns the agent's active-job count, or `undefined` when it is not registered
|
|
388
427
|
*/
|
|
389
428
|
markDraining(agentId: string): number | undefined;
|
|
429
|
+
/**
|
|
430
|
+
* Hold an agent out of routing after it rejected a dispatch as busy.
|
|
431
|
+
*
|
|
432
|
+
* A busy rejection means the agent still holds the slot of the job it is
|
|
433
|
+
* tearing down, while the registry already counts that slot free (the
|
|
434
|
+
* job reported completion first). Without the hold, the requeue re-picks the
|
|
435
|
+
* same agent at once and each rejection repeats within milliseconds. The hold
|
|
436
|
+
* lifts on evidence of a free slot ({@link clearBusyHeld}): the agent reports
|
|
437
|
+
* an empty slot on `agent.status`, or a job tracked to it reaches a final
|
|
438
|
+
* status. An expired hold is also dropped when the agent accepts a job
|
|
439
|
+
* ({@link clearExpiredBusyHold}). Otherwise the hold ends after
|
|
440
|
+
* {@link BUSY_HOLD_MAX_MS}, so a lost status report cannot strand the agent.
|
|
441
|
+
*
|
|
442
|
+
* An expired hold keeps its `busyHeldUntil` until that evidence arrives. So a
|
|
443
|
+
* hold still on the entry here means the agent was re-picked because its last
|
|
444
|
+
* hold ran out, and has neither reported a free slot nor accepted or finished
|
|
445
|
+
* a job since — an agent whose job count is stuck. The caller spends an
|
|
446
|
+
* attempt for that, which keeps such an agent from holding a job pending
|
|
447
|
+
* forever.
|
|
448
|
+
*/
|
|
449
|
+
markBusyHeld(agentId: string, now?: number): BusyHoldOutcome;
|
|
450
|
+
/**
|
|
451
|
+
* Lift a {@link markBusyHeld} hold: the agent reported an empty slot, or a
|
|
452
|
+
* job tracked to it reached a final status.
|
|
453
|
+
*/
|
|
454
|
+
clearBusyHeld(agentId: string): void;
|
|
455
|
+
/**
|
|
456
|
+
* Drop a {@link markBusyHeld} hold that has already run out: the agent
|
|
457
|
+
* accepted a job since.
|
|
458
|
+
*
|
|
459
|
+
* Every dispatch path skips an agent whose hold is in force, so a job the
|
|
460
|
+
* agent accepts while an expired hold is on its entry was dispatched after
|
|
461
|
+
* the hold ran out, into a slot that was free. That refutes the stuck job
|
|
462
|
+
* count the leftover hold stands for. A hold still in force is kept: the
|
|
463
|
+
* accepted job occupies the slot, so the acceptance says nothing about a
|
|
464
|
+
* free slot now.
|
|
465
|
+
*/
|
|
466
|
+
clearExpiredBusyHold(agentId: string, now?: number): void;
|
|
390
467
|
/** Undo {@link markDraining} — a destroy that was rejected leaves the agent alive. */
|
|
391
468
|
clearDraining(agentId: string): void;
|
|
392
469
|
get(agentId: string): AgentEntry | undefined;
|
package/dist/app.d.ts
CHANGED
|
@@ -208,6 +208,8 @@ export interface AppDependencies {
|
|
|
208
208
|
issuer: string;
|
|
209
209
|
resolveSigner: () => Promise<import('./oidc/signer.js').Signer | null>;
|
|
210
210
|
repo: import('./db/repos/signing-keys-repo.js').OrchestratorSigningKeyRepo;
|
|
211
|
+
/** Whether this node is the Raft leader; named when a mint defers for want of a key. */
|
|
212
|
+
isLeader?: () => boolean;
|
|
211
213
|
};
|
|
212
214
|
/**
|
|
213
215
|
* Dashboard-encryption (X25519) key custody. Present whenever KICI_SECRET_KEY
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cancel a run that sits `held` behind an approval request.
|
|
3
|
+
*
|
|
4
|
+
* A held run has no job and no dispatch yet: what it has is a pending
|
|
5
|
+
* `held_runs` row, the pending `KiCI Security` check a security hold posted,
|
|
6
|
+
* and the stored dispatch context an approve would replay. Cancelling it has to
|
|
7
|
+
* settle all three, or a later approve still finds its hold pending, replays
|
|
8
|
+
* the stored dispatch, and closes the check as approved for a run that was
|
|
9
|
+
* cancelled. So a cancel withdraws the approval request through the path a
|
|
10
|
+
* reject takes: each pending hold of the run is flipped `rejected` with the
|
|
11
|
+
* cancel reason, then handed to the workflow-hold rejection
|
|
12
|
+
* (`rejectWorkflow`), which cancels the run, completes the checks the held
|
|
13
|
+
* dispatch posted, settles the security check, and drops the stored context.
|
|
14
|
+
*/
|
|
15
|
+
import type { Kysely } from 'kysely';
|
|
16
|
+
import type { Database, HeldRun } from '../db/types.js';
|
|
17
|
+
import type { ExecutionTracker } from '../reporting/execution-tracker.js';
|
|
18
|
+
/** How a cancel of a held run's approval requests ended. */
|
|
19
|
+
export declare enum HeldRunWithdrawal {
|
|
20
|
+
/** The cancel rejected at least one pending hold itself. */
|
|
21
|
+
Withdrawn = "withdrawn",
|
|
22
|
+
/** An approve released the run first, so it is resuming. */
|
|
23
|
+
Approved = "approved",
|
|
24
|
+
/** A reject decided the hold first, and that rejection ends the run. */
|
|
25
|
+
Rejected = "rejected",
|
|
26
|
+
/** The hold expired first, and that expiry ends the run. */
|
|
27
|
+
Expired = "expired"
|
|
28
|
+
}
|
|
29
|
+
/** A decision on a held run that reached its holds before a cancel did. */
|
|
30
|
+
export type HeldRunDecidedFirst = Exclude<HeldRunWithdrawal, HeldRunWithdrawal.Withdrawn>;
|
|
31
|
+
/** Options for a workflow-hold rejection reached through a cancel. */
|
|
32
|
+
export interface RejectHeldWorkflowOptions {
|
|
33
|
+
/**
|
|
34
|
+
* False when the run is not `held`: the rejection then settles the checks
|
|
35
|
+
* and drops the stored context but leaves the run row to the job
|
|
36
|
+
* cancellation that follows. Defaults to true.
|
|
37
|
+
*/
|
|
38
|
+
runHeld?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/** Options for {@link cancelHeldRunWithReason}. */
|
|
41
|
+
export interface CancelHeldRunOptions {
|
|
42
|
+
/**
|
|
43
|
+
* False when the caller ends the run itself — a cancel of a run that is not
|
|
44
|
+
* `held`, whose jobs are cancelled next. The holds are still rejected and
|
|
45
|
+
* the checks settled, but no held-run terminal write is attempted: it would
|
|
46
|
+
* match no row and only report a missing held run. Defaults to true.
|
|
47
|
+
*/
|
|
48
|
+
terminalWrite?: boolean;
|
|
49
|
+
}
|
|
50
|
+
export interface CancelHeldRunDeps {
|
|
51
|
+
db: Kysely<Database>;
|
|
52
|
+
executionTracker: ExecutionTracker;
|
|
53
|
+
/**
|
|
54
|
+
* The workflow-hold rejection (`rejectWorkflow` bound to live processing
|
|
55
|
+
* deps). Undefined where no provider wiring exists: the run is then cancelled
|
|
56
|
+
* and its holds rejected, but no provider check is settled.
|
|
57
|
+
*/
|
|
58
|
+
rejectHeldWorkflow?: ((hold: HeldRun, reason: string, opts?: RejectHeldWorkflowOptions) => Promise<boolean>) | undefined;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Withdraw every pending approval request of a held run and cancel the run.
|
|
62
|
+
* Returns {@link HeldRunWithdrawal.Withdrawn} when this call withdrew the run.
|
|
63
|
+
* Otherwise a decision reached every hold first — an approve, a reject or an
|
|
64
|
+
* expiry, which the result names — the call writes nothing, and the caller
|
|
65
|
+
* refuses the cancel.
|
|
66
|
+
*/
|
|
67
|
+
export declare function cancelHeldRunWithReason(deps: CancelHeldRunDeps, runId: string, reason: string, opts?: CancelHeldRunOptions): Promise<HeldRunWithdrawal>;
|
|
68
|
+
//# sourceMappingURL=cancel-held-run.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The admin cancel route's answer for a cancel that did not find the run
|
|
3
|
+
* already terminal. Kept apart from the route so the mapping is testable
|
|
4
|
+
* without assembling the whole app.
|
|
5
|
+
*/
|
|
6
|
+
import { ExecutionRunStatus } from '@kici-dev/engine';
|
|
7
|
+
import { type CancelRunResult } from './cancel-run.js';
|
|
8
|
+
export interface CancelRouteAnswer {
|
|
9
|
+
httpStatus: 200 | 409;
|
|
10
|
+
body: {
|
|
11
|
+
status: ExecutionRunStatus;
|
|
12
|
+
cancelledJobs: number;
|
|
13
|
+
} | {
|
|
14
|
+
error: string;
|
|
15
|
+
status: ExecutionRunStatus;
|
|
16
|
+
};
|
|
17
|
+
/** Note recorded on the access-log row, when the answer is not a plain success. */
|
|
18
|
+
accessNote?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function cancelRouteAnswer(result: CancelRunResult): CancelRouteAnswer;
|
|
21
|
+
//# sourceMappingURL=cancel-route-answer.d.ts.map
|
|
@@ -20,6 +20,8 @@ import type { Database } from '../db/types.js';
|
|
|
20
20
|
import type { JobQueue } from '../queue/job-queue.js';
|
|
21
21
|
import type { AgentRegistry } from '../agent/registry.js';
|
|
22
22
|
import type { ExecutionTracker } from '../reporting/execution-tracker.js';
|
|
23
|
+
import type { HeldRun } from '../db/types.js';
|
|
24
|
+
import { type HeldRunDecidedFirst, type RejectHeldWorkflowOptions } from './cancel-held-run.js';
|
|
23
25
|
export interface CancelRunDeps {
|
|
24
26
|
db: Kysely<Database>;
|
|
25
27
|
jobQueue: JobQueue;
|
|
@@ -38,6 +40,13 @@ export interface CancelRunDeps {
|
|
|
38
40
|
cancelJobOnPeer?: (peerId: string, runId: string, jobId: string, reason: string) => boolean;
|
|
39
41
|
/** How stale a `cluster_instances` heartbeat may be and still read as live. */
|
|
40
42
|
ownershipGraceMs?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Reject a held run's workflow-scoped hold: `rejectWorkflow` bound to the live
|
|
45
|
+
* processing deps. A cancel of a `held` run goes through it so the approval
|
|
46
|
+
* request is withdrawn with the run. Undefined where no provider wiring
|
|
47
|
+
* exists; the held run is then still cancelled and its holds rejected.
|
|
48
|
+
*/
|
|
49
|
+
rejectHeldWorkflow?: (hold: HeldRun, reason: string, opts?: RejectHeldWorkflowOptions) => Promise<boolean>;
|
|
41
50
|
}
|
|
42
51
|
export interface CancelRunOptions {
|
|
43
52
|
/** Force immediate SIGKILL on the agent (skip graceful hooks). */
|
|
@@ -64,6 +73,29 @@ export interface CancelRunResult {
|
|
|
64
73
|
* no-op: no agent was notified and no row was written.
|
|
65
74
|
*/
|
|
66
75
|
alreadyTerminal: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Set when the run was `held` and a decision reached its holds first — an
|
|
78
|
+
* approve, a reject or an expiry — so the cancel wrote nothing. Entry points
|
|
79
|
+
* refuse the cancel with {@link heldRunCancelRefusal}.
|
|
80
|
+
*/
|
|
81
|
+
decidedBeforeCancel?: HeldRunDecidedFirst;
|
|
82
|
+
}
|
|
83
|
+
/** Why a cancel of a held run whose hold an approve already released is refused. */
|
|
84
|
+
export declare const RUN_RESUMING_AFTER_APPROVAL_MESSAGE = "Run is resuming after approval; cancel it again once it is running";
|
|
85
|
+
/** Why a cancel of a held run whose hold a reject already decided is refused. */
|
|
86
|
+
export declare const RUN_REJECTED_BEFORE_CANCEL_MESSAGE = "Run was rejected before the cancel reached it; the rejection ends it";
|
|
87
|
+
/** Why a cancel of a held run whose hold already expired is refused. */
|
|
88
|
+
export declare const RUN_EXPIRED_BEFORE_CANCEL_MESSAGE = "Run approval request expired before the cancel reached it; the expiry ends it";
|
|
89
|
+
/** The message a refused cancel of a held run answers with, naming the decision that won. */
|
|
90
|
+
export declare function heldRunCancelRefusal(decision: HeldRunDecidedFirst): string;
|
|
91
|
+
/**
|
|
92
|
+
* Thrown by an entry point that refuses a cancel because a decision reached
|
|
93
|
+
* the held run first. An expected race, not a failure: callers answer it as a
|
|
94
|
+
* refusal rather than logging an error.
|
|
95
|
+
*/
|
|
96
|
+
export declare class HeldRunCancelRefusedError extends Error {
|
|
97
|
+
readonly decision: HeldRunDecidedFirst;
|
|
98
|
+
constructor(decision: HeldRunDecidedFirst);
|
|
67
99
|
}
|
|
68
100
|
/**
|
|
69
101
|
* Cancel a whole run, recording `reason` on its cancelled jobs and (if not
|
package/dist/cli/api-client.d.ts
CHANGED
|
@@ -158,6 +158,25 @@ export declare class AdminApiClient {
|
|
|
158
158
|
}>;
|
|
159
159
|
setSecret(orgId: string, scope: string, key: string, value: string): Promise<void>;
|
|
160
160
|
deleteSecret(orgId: string, scope: string, key: string): Promise<void>;
|
|
161
|
+
/**
|
|
162
|
+
* Create an empty secret scope. A `<backend>:` qualifier selects the
|
|
163
|
+
* backend; an unqualified scope targets the PG backend. Creating a scope
|
|
164
|
+
* that already exists succeeds and changes nothing.
|
|
165
|
+
*/
|
|
166
|
+
createScope(orgId: string, scope: string): Promise<{
|
|
167
|
+
created: boolean;
|
|
168
|
+
}>;
|
|
169
|
+
/**
|
|
170
|
+
* Rename a secret scope inside its backend. The route refuses a move between
|
|
171
|
+
* backends and a rename onto a scope that already exists.
|
|
172
|
+
*/
|
|
173
|
+
renameScope(orgId: string, oldScope: string, newScope: string): Promise<{
|
|
174
|
+
renamed: boolean;
|
|
175
|
+
}>;
|
|
176
|
+
/** Delete a secret scope and every secret in it. */
|
|
177
|
+
deleteScope(orgId: string, scope: string): Promise<{
|
|
178
|
+
deleted: boolean;
|
|
179
|
+
}>;
|
|
161
180
|
/**
|
|
162
181
|
* Create (or upsert) a deployment context. `allowLocalExecution` lets
|
|
163
182
|
* CLI-initiated / local runs resolve secrets through this context.
|
|
@@ -204,6 +223,9 @@ export declare class AdminApiClient {
|
|
|
204
223
|
skippedEphemeralKeys: number;
|
|
205
224
|
reEncryptedSecretOutputs: number;
|
|
206
225
|
skippedSecretOutputs: number;
|
|
226
|
+
/** Absent from an orchestrator that predates sealed job secrets. */
|
|
227
|
+
reEncryptedJobSecrets?: number;
|
|
228
|
+
skippedJobSecrets?: number;
|
|
207
229
|
}>;
|
|
208
230
|
createGenericSource(data: {
|
|
209
231
|
orgId: string;
|
|
@@ -270,7 +292,7 @@ export declare class AdminApiClient {
|
|
|
270
292
|
to?: string;
|
|
271
293
|
limit?: number;
|
|
272
294
|
offset?: number;
|
|
273
|
-
/**
|
|
295
|
+
/** Opt-in cold-store read-through. */
|
|
274
296
|
includeArchived?: boolean;
|
|
275
297
|
}): Promise<any[]>;
|
|
276
298
|
createToken(data: {
|