@kici-dev/orchestrator 0.6.1 → 0.7.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/agent/dispatcher.d.ts +10 -1
- package/dist/agent/host-roster.d.ts +8 -3
- package/dist/agent/registry.d.ts +60 -5
- package/dist/app.d.ts +10 -5
- package/dist/cache/dep-cache.d.ts +14 -6
- package/dist/cache/global-eval-round-cache.d.ts +1 -1
- package/dist/cache/index.d.ts +1 -1
- package/dist/cache/source-cache.d.ts +92 -15
- package/dist/cancel/cancel-run.d.ts +20 -2
- package/dist/cancel/sweep-stuck-cancelling.d.ts +30 -0
- package/dist/cli/api-client.d.ts +10 -0
- package/dist/cli/commands/agent-service/logs.d.ts +1 -1
- package/dist/cli/commands/agent-service/restart.d.ts +1 -1
- package/dist/cli/commands/agent-service/start.d.ts +1 -1
- package/dist/cli/commands/agent-service/status.d.ts +1 -1
- package/dist/cli/commands/agent-service/stop.d.ts +1 -1
- package/dist/cli/commands/agent-service/uninstall.d.ts +1 -1
- package/dist/cli/commands/agent.d.ts +25 -0
- package/dist/cli/commands/config.d.ts +16 -0
- package/dist/cli/commands/db-backup.d.ts +46 -0
- package/dist/cli/commands/held-run.d.ts +9 -0
- package/dist/cli/commands/orchestrator-service/drain.d.ts +2 -19
- package/dist/cli/commands/orchestrator-service/index.d.ts +9 -1
- package/dist/cli/commands/orchestrator-service/install-env.d.ts +43 -2
- package/dist/cli/commands/orchestrator-service/logs.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/restart.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/start.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/status.d.ts +17 -1
- package/dist/cli/commands/orchestrator-service/stop.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/uninstall.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/upgrade.d.ts +2 -1
- package/dist/cli/commands/rotate.d.ts +1 -1
- package/dist/cli/commands/shared/env-file-mode.d.ts +16 -0
- package/dist/cli/commands/shared/upgrade-hooks.d.ts +32 -0
- package/dist/cli/commands/shared/upgrade-safety.d.ts +81 -0
- package/dist/cli/commands/shared/versioned-upgrade.d.ts +67 -12
- package/dist/cli/commands/source.d.ts +1 -0
- package/dist/cli/commands/token.d.ts +4 -0
- package/dist/cli/commands/trust-policy.d.ts +57 -1
- package/dist/cli/join.d.ts +1 -1
- package/dist/cli/service/backup-timer.d.ts +108 -0
- package/dist/cli/service/compose-path.d.ts +11 -0
- package/dist/cli/service/compose.d.ts +22 -0
- package/dist/cli/service/deploy-env.d.ts +10 -11
- package/dist/cli/service/env-assignment.d.ts +24 -0
- package/dist/cli/service/index.d.ts +2 -2
- package/dist/cli/service/instance/resolve.d.ts +71 -7
- package/dist/cli/service/instance/types.d.ts +15 -0
- package/dist/cli/service/launchd.d.ts +7 -0
- package/dist/cli/service/systemd.d.ts +1 -0
- package/dist/cli/service/types.d.ts +36 -0
- package/dist/cli/service/windows.d.ts +16 -0
- package/dist/cli/wizard/orchestrator-wizard.d.ts +12 -3
- package/dist/cli/wizard/prompts.d.ts +7 -0
- package/dist/cli.js +12525 -9298
- package/dist/cluster/cluster-settings-reader.d.ts +2 -2
- package/dist/cluster/coordinator.d.ts +11 -0
- package/dist/cluster/instance-heartbeat.d.ts +96 -0
- package/dist/cluster/join-client.d.ts +55 -5
- package/dist/cluster/join-handler.d.ts +1 -0
- package/dist/cluster/orphan-recovery.d.ts +16 -0
- package/dist/cluster/peer-registry.d.ts +10 -0
- package/dist/concurrency/dispatch-next-queued.d.ts +1 -13
- package/dist/concurrency/index.d.ts +1 -2
- package/dist/concurrency/queue-manager.d.ts +63 -18
- package/dist/config/env-overlay.d.ts +3 -2
- package/dist/config.d.ts +24 -0
- package/dist/contexts/release-queued-holds.d.ts +23 -1
- package/dist/dashboard/attestation-filters.d.ts +2 -0
- package/dist/dashboard/handler.d.ts +22 -2
- package/dist/db/deferred-indexes.d.ts +72 -0
- package/dist/db/migration-test-harness.d.ts +22 -0
- package/dist/db/migrations/131_execution_jobs_git_credentials.d.ts +30 -0
- package/dist/db/migrations/132_execution_runs_trigger_event.d.ts +23 -0
- package/dist/db/migrations/133_dispatch_queue_source_tar_digest.d.ts +23 -0
- package/dist/db/migrations/134_dispatch_queue_ownership.d.ts +4 -0
- package/dist/db/migrations/135_cluster_settings_retention_days.d.ts +4 -0
- package/dist/db/migrations/136_master_key_wrapped_tables_key_version.d.ts +4 -0
- package/dist/db/migrations/137_execution_runs_pr_head_context.d.ts +4 -0
- package/dist/db/migrations/138_execution_runs_subject_trigger_event.d.ts +4 -0
- package/dist/db/migrations/139_admin_token_subject.d.ts +4 -0
- package/dist/db/migrations/140_dispatch_queue_canonical_labels.d.ts +54 -0
- package/dist/db/migrations/141_event_log_shed.d.ts +15 -0
- package/dist/db/migrator.d.ts +47 -0
- package/dist/db/notify-listener.d.ts +60 -0
- package/dist/db/synthetic-job-ids.d.ts +24 -0
- package/dist/db/types.d.ts +169 -4
- package/dist/deployment/deployment-identity.d.ts +31 -1
- package/dist/diagnostics/checks/index.d.ts +2 -1
- package/dist/diagnostics/checks/retention.d.ts +24 -0
- package/dist/diagnostics/types.d.ts +7 -0
- package/dist/events/event-router.d.ts +1 -1
- package/dist/fault-injection-types.d.ts +53 -0
- package/dist/firecracker/host-network.d.ts +63 -8
- package/dist/git/credential-broker.d.ts +35 -2
- package/dist/git/inherited-secret.d.ts +7 -2
- package/dist/git/job-context.d.ts +7 -4
- package/dist/helpers/secure-write.d.ts +35 -0
- package/dist/index.js +196 -67
- package/dist/metrics/prometheus.d.ts +116 -1
- package/dist/oidc/db-signer.d.ts +27 -5
- package/dist/oidc/id-token-claims.d.ts +33 -2
- package/dist/oidc/oidc-mint-registration.d.ts +6 -0
- package/dist/oidc/orchestrator-mint.d.ts +8 -0
- package/dist/oidc/reconcile-signing-key.d.ts +37 -0
- package/dist/orchestrator-core.d.ts +9 -3
- package/dist/pipeline/decorating-secret-resolver.d.ts +1 -1
- package/dist/pipeline/dispatch-matched-workflow.d.ts +65 -14
- package/dist/pipeline/manual-schedule.d.ts +1 -0
- package/dist/pipeline/process-webhook.d.ts +20 -2
- package/dist/pipeline/route-or-dispatch-jobs.d.ts +7 -0
- package/dist/pipeline/run-event-context.d.ts +39 -0
- package/dist/policy/dashboard-write-policy-listener.d.ts +1 -1
- package/dist/policy/dashboard-write-policy.d.ts +47 -1
- package/dist/provenance/dispatch-context.d.ts +46 -0
- package/dist/provenance/verify-deferred-capture.d.ts +39 -0
- package/dist/providers/github/auth.d.ts +9 -0
- package/dist/providers/github/deliveries.d.ts +118 -0
- package/dist/providers/universal-git/config.d.ts +1 -1
- package/dist/queue/cleanup.d.ts +13 -0
- package/dist/queue/job-queue.d.ts +162 -14
- package/dist/queue/retention.d.ts +105 -0
- package/dist/reporting/execution-tracker.d.ts +87 -36
- package/dist/routes/admin-db.d.ts +5 -0
- package/dist/routes/admin-events.d.ts +13 -0
- package/dist/routes/admin-held-runs.d.ts +11 -1
- package/dist/routes/admin-org-settings.d.ts +9 -0
- package/dist/routes/admin-runs.d.ts +7 -4
- package/dist/routes/admin-sources.d.ts +15 -0
- package/dist/routes/admin-trust-policy.d.ts +11 -0
- package/dist/routes/admin.d.ts +25 -0
- package/dist/scaler/backend-factory.d.ts +16 -0
- package/dist/scaler/bare-metal-backend.d.ts +22 -4
- package/dist/scaler/config.d.ts +6 -3
- package/dist/scaler/container-backend.d.ts +102 -3
- package/dist/scaler/container-hostconfig.d.ts +60 -0
- package/dist/scaler/file-tail.d.ts +25 -2
- package/dist/scaler/firecracker-api.d.ts +9 -1
- package/dist/scaler/firecracker-backend.d.ts +135 -2
- package/dist/scaler/host-access.d.ts +59 -0
- package/dist/scaler/index.d.ts +1 -0
- package/dist/scaler/manager.d.ts +33 -0
- package/dist/scaler/scaler-state-store.d.ts +6 -0
- package/dist/scaler/types.d.ts +5 -7
- package/dist/secrets/config.d.ts +48 -0
- package/dist/secrets/dashboard-encryption-key.d.ts +19 -0
- package/dist/secrets/ephemeral-keys.d.ts +9 -3
- package/dist/secrets/index.d.ts +3 -1
- package/dist/secrets/job-secret-gate.d.ts +76 -0
- package/dist/secrets/master-key-rotation.d.ts +65 -0
- package/dist/secrets/secret-output-crypto.d.ts +17 -0
- package/dist/secrets/secret-resolver.d.ts +23 -6
- package/dist/secrets/source-credentials.d.ts +1 -1
- package/dist/secrets/token-manager.d.ts +4 -1
- package/dist/security/reduced-privilege-note.d.ts +5 -0
- package/dist/security/trust-policy-gate.d.ts +70 -6
- package/dist/security/trust-tier.d.ts +31 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +10661 -5282
- package/dist/sources/source-manager.d.ts +1 -1
- package/dist/stale-detector/stale-dispatch-candidates.d.ts +43 -0
- package/dist/standalone.js +9258 -4122
- package/dist/storage/loopback-guard.d.ts +53 -6
- package/dist/webhook/event-log.d.ts +14 -1
- package/dist/webhook/generic-sources-listener.d.ts +1 -1
- package/dist/webhook/ingest-admission.d.ts +24 -0
- package/dist/webhook/ingest-overflow-replayer.d.ts +78 -14
- package/dist/webhook/ingest-overflow-types.d.ts +13 -1
- package/dist/webhook/register-source-bundle.d.ts +23 -0
- package/dist/webhook/relay-reinject.d.ts +11 -12
- package/dist/webhook/shed-breadcrumb.d.ts +15 -0
- package/dist/ws/git-credential-relay.d.ts +41 -12
- package/dist/ws/platform-client.d.ts +28 -5
- package/installer-image-digests.json +3 -3
- package/package.json +4 -4
- package/sbom.spdx.json +53 -53
- package/dist/concurrency/group-tracker.d.ts +0 -51
- package/dist/scaler/nftables.d.ts +0 -111
|
@@ -27,7 +27,7 @@ export declare enum AgentDrainDecline {
|
|
|
27
27
|
* Default per-pass cap on how many pending jobs a capacity-freed re-drive
|
|
28
28
|
* re-offers to the scaler. Bounds the burst so a single free event cannot storm
|
|
29
29
|
* the scaler; the per-backend spawn semaphore bounds actual provisioning, and a
|
|
30
|
-
* job that gets `at-capacity` again
|
|
30
|
+
* job that gets `at-capacity` again stays pending for the next tick.
|
|
31
31
|
*/
|
|
32
32
|
export declare const DEFAULT_REDRIVE_BATCH = 10;
|
|
33
33
|
/**
|
|
@@ -403,6 +403,15 @@ export declare class Dispatcher {
|
|
|
403
403
|
* triage can surface failed job IDs to the caller.
|
|
404
404
|
*/
|
|
405
405
|
private requeueOrFail;
|
|
406
|
+
/**
|
|
407
|
+
* The half of {@link requeueOrFail} that runs once the row has been flipped:
|
|
408
|
+
* fail the job when its attempt budget is exhausted, otherwise re-dispatch.
|
|
409
|
+
*
|
|
410
|
+
* Split out so the ack-expiry paths can drive it from the attempt count their
|
|
411
|
+
* own guarded requeue (`requeueIfAwaitingAck`) returned, instead of flipping
|
|
412
|
+
* the row a second time.
|
|
413
|
+
*/
|
|
414
|
+
private finishRequeue;
|
|
406
415
|
/**
|
|
407
416
|
* Try to deliver a requeued pending job: prefer an idle matching agent
|
|
408
417
|
* (atomic claim via dispatchBoundJob), otherwise consult the scaler so a
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Kysely } from 'kysely';
|
|
2
|
-
import { type HostInventoryEntry, type InventorySelector, type LabelMatcher } from '@kici-dev/engine';
|
|
2
|
+
import { type CanonicalLabel, type HostInventoryEntry, type InventorySelector, type LabelMatcher } from '@kici-dev/engine';
|
|
3
3
|
import type { Database, HostRosterRow } from '../db/types.js';
|
|
4
4
|
/** Typed host-vars bag carried by roster rows (`string | number | boolean`). */
|
|
5
5
|
export type HostProperties = Record<string, string | number | boolean>;
|
|
@@ -61,9 +61,14 @@ export type LifecycleClass = 'static' | 'ephemeral';
|
|
|
61
61
|
*/
|
|
62
62
|
export interface MatchedHost {
|
|
63
63
|
agentId: string;
|
|
64
|
-
/**
|
|
64
|
+
/** Canonical hostname; falls back to the raw agentId when the row has none. */
|
|
65
65
|
host: string;
|
|
66
|
-
|
|
66
|
+
/**
|
|
67
|
+
* The row's labels, folded on read. A row written before labels were
|
|
68
|
+
* canonicalized still carries the case the operator typed, and this is the
|
|
69
|
+
* only place that case would otherwise reach a matcher.
|
|
70
|
+
*/
|
|
71
|
+
labels: CanonicalLabel[];
|
|
67
72
|
lifecycleClass: LifecycleClass;
|
|
68
73
|
/** Which orchestrator holds the live WS (null = disconnected). For the cross-cluster pin. */
|
|
69
74
|
connectedInstanceId: string | null;
|
package/dist/agent/registry.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* No persistence needed -- agents re-register on reconnect.
|
|
10
10
|
*/
|
|
11
|
-
import { type LabelMatcher } from '@kici-dev/engine';
|
|
11
|
+
import { type CanonicalLabel, type LabelMatcher } from '@kici-dev/engine';
|
|
12
12
|
import type { WsLike } from '@kici-dev/engine';
|
|
13
13
|
export type { WsLike } from '@kici-dev/engine';
|
|
14
14
|
/**
|
|
@@ -19,8 +19,12 @@ export interface AgentEntry {
|
|
|
19
19
|
agentId: string;
|
|
20
20
|
/** The underlying WebSocket (or mock). */
|
|
21
21
|
ws: WsLike;
|
|
22
|
-
/**
|
|
23
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Set of labels this agent provides (e.g., "linux", "gpu", "docker"), folded
|
|
24
|
+
* to canonical form by `register()`. The label reverse index is keyed the
|
|
25
|
+
* same way, so a lookup must fold its query before it reaches either.
|
|
26
|
+
*/
|
|
27
|
+
labels: Set<CanonicalLabel>;
|
|
24
28
|
/**
|
|
25
29
|
* Kubernetes-taint-style mandatory labels inherited from the scaler that
|
|
26
30
|
* spawned this agent. A job is only dispatched to this agent when every
|
|
@@ -35,8 +39,11 @@ export interface AgentEntry {
|
|
|
35
39
|
* (`onAgentAvailable` → `dequeueForLabels`) sees only the agent's labels
|
|
36
40
|
* and would otherwise pull a queued job whose `runsOn` is a subset of the
|
|
37
41
|
* agent's labels but does not satisfy the gate).
|
|
42
|
+
*
|
|
43
|
+
* Folded to canonical form by `register()`, so a scaler that declared `GPU`
|
|
44
|
+
* gates the same jobs a scaler that declared `gpu` does.
|
|
38
45
|
*/
|
|
39
|
-
mandatoryLabels: Set<
|
|
46
|
+
mandatoryLabels: Set<CanonicalLabel>;
|
|
40
47
|
/**
|
|
41
48
|
* True when this agent was spawned by a scaler backend. Scaler-managed
|
|
42
49
|
* agents are single-use: the scaler destroys them on disconnect, so they
|
|
@@ -45,6 +52,22 @@ export interface AgentEntry {
|
|
|
45
52
|
* recovery window that cannot succeed.
|
|
46
53
|
*/
|
|
47
54
|
scalerManaged: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* True while this agent is being torn down and must receive no new work.
|
|
57
|
+
*
|
|
58
|
+
* The warm pool decides an agent is idle, marks it, then awaits a destroy
|
|
59
|
+
* that takes seconds — a container `stop({ t: 5 })`, or a Firecracker
|
|
60
|
+
* `SendCtrlAltDel` plus its grace. The registry entry survives until the
|
|
61
|
+
* agent's WebSocket actually closes, so without this flag `findAvailable`
|
|
62
|
+
* kept returning the agent throughout: a job arriving in that window was
|
|
63
|
+
* dispatched onto a container that was already exiting, and failed as a
|
|
64
|
+
* spurious infrastructure error on a healthy system.
|
|
65
|
+
*
|
|
66
|
+
* In memory rather than DB-backed, unlike reboot-pending: a warm-pool
|
|
67
|
+
* destroy is issued by this process, lasts seconds, and ends with the
|
|
68
|
+
* WebSocket close that removes the entry — there is nothing to outlive.
|
|
69
|
+
*/
|
|
70
|
+
draining: boolean;
|
|
48
71
|
/** Number of jobs currently executing on this agent. */
|
|
49
72
|
activeJobs: number;
|
|
50
73
|
/** Maximum concurrent jobs this agent can handle (default 1). */
|
|
@@ -211,8 +234,16 @@ export declare class AgentRegistry {
|
|
|
211
234
|
/**
|
|
212
235
|
* Register an agent. If the agentId already exists, updates the existing
|
|
213
236
|
* entry (agent reconnection scenario).
|
|
237
|
+
*
|
|
238
|
+
* @returns the socket the previous entry was bound to, when this register
|
|
239
|
+
* replaced one bound to a *different* socket. The caller owns that socket's
|
|
240
|
+
* per-connection state and must retire it: a half-open connection can
|
|
241
|
+
* outlive the reconnect, and its later close carries the same agent id, so
|
|
242
|
+
* a caller that keeps treating it as live tears down the registration that
|
|
243
|
+
* replaced it. `undefined` for a first register or a re-register on the
|
|
244
|
+
* same socket.
|
|
214
245
|
*/
|
|
215
|
-
register(agentId: string, ws: WsLike, labels: string[], platform?: string, arch?: string, version?: string, maxConcurrency?: number, metadata?: AgentMetadata):
|
|
246
|
+
register(agentId: string, ws: WsLike, labels: string[], platform?: string, arch?: string, version?: string, maxConcurrency?: number, metadata?: AgentMetadata): WsLike | undefined;
|
|
216
247
|
/**
|
|
217
248
|
* Unregister an agent by ID. Removes from all indexes.
|
|
218
249
|
* @returns The removed AgentEntry, or undefined if not found.
|
|
@@ -300,6 +331,9 @@ export declare class AgentRegistry {
|
|
|
300
331
|
* matches zero agents (so callers can short-circuit). Returns an empty
|
|
301
332
|
* Set on `requiredLabels.length === 0` since the caller decides the
|
|
302
333
|
* walk strategy in that case.
|
|
334
|
+
*
|
|
335
|
+
* Takes canonical labels: the index it reads is keyed on the canonical form,
|
|
336
|
+
* so a caller folds before it gets here.
|
|
303
337
|
*/
|
|
304
338
|
private intersectLabelCandidates;
|
|
305
339
|
/**
|
|
@@ -334,6 +368,27 @@ export declare class AgentRegistry {
|
|
|
334
368
|
/**
|
|
335
369
|
* Get a single agent entry by ID.
|
|
336
370
|
*/
|
|
371
|
+
/**
|
|
372
|
+
* Whether one agent id is currently registered.
|
|
373
|
+
*
|
|
374
|
+
* Distinct from `findAvailable`, which answers "which agents could take this
|
|
375
|
+
* job" — the container orphan sweep needs to know only whether a running
|
|
376
|
+
* container's agent is present at all, including one that is busy or gated.
|
|
377
|
+
*/
|
|
378
|
+
isRegistered(agentId: string): boolean;
|
|
379
|
+
/**
|
|
380
|
+
* Condemn an agent: it stays registered and keeps finishing its current work,
|
|
381
|
+
* but takes no new dispatches.
|
|
382
|
+
*
|
|
383
|
+
* Called before a warm-pool destroy is issued. Returns the agent's current
|
|
384
|
+
* `activeJobs` so the caller can see a job that was claimed between its idle
|
|
385
|
+
* check and this mark, and back out.
|
|
386
|
+
*
|
|
387
|
+
* @returns the agent's active-job count, or `undefined` when it is not registered
|
|
388
|
+
*/
|
|
389
|
+
markDraining(agentId: string): number | undefined;
|
|
390
|
+
/** Undo {@link markDraining} — a destroy that was rejected leaves the agent alive. */
|
|
391
|
+
clearDraining(agentId: string): void;
|
|
337
392
|
get(agentId: string): AgentEntry | undefined;
|
|
338
393
|
/**
|
|
339
394
|
* Get an agent entry by its WebSocket reference.
|
package/dist/app.d.ts
CHANGED
|
@@ -57,6 +57,7 @@ import type { OwnershipTracker } from './agent/ownership-tracker.js';
|
|
|
57
57
|
import type { ObserverRegistry } from './ws/observer-registry.js';
|
|
58
58
|
import type { FleetAgentCollector } from './ws/fleet-agent-collector.js';
|
|
59
59
|
import type { FleetTopology } from './diagnostics/fleet-topology.js';
|
|
60
|
+
import type { ResolvedMasterKeys } from './secrets/config.js';
|
|
60
61
|
import type { TokenManager } from './secrets/token-manager.js';
|
|
61
62
|
import type { SecretResolver } from './secrets/secret-resolver.js';
|
|
62
63
|
import type { VerifyInboundDeps } from './webhook/verify-inbound.js';
|
|
@@ -75,7 +76,6 @@ import { type OverflowDelivery } from './webhook/ingest-overflow-types.js';
|
|
|
75
76
|
import type { IngestAdmissionController } from './webhook/ingest-admission.js';
|
|
76
77
|
import type { OrgIngestCapReader } from './webhook/org-ingest-cap-reader.js';
|
|
77
78
|
import type { SandboxAllowListReader } from './pipeline/sandbox-allowlist-reader.js';
|
|
78
|
-
import type { ConcurrencyGroupTracker } from './concurrency/group-tracker.js';
|
|
79
79
|
import type { ConcurrencyQueueManager } from './concurrency/queue-manager.js';
|
|
80
80
|
import type { EventRouter } from './events/event-router.js';
|
|
81
81
|
import type { EventStore } from './events/event-store.js';
|
|
@@ -85,7 +85,7 @@ import type { EventLogWriter } from './webhook/event-log.js';
|
|
|
85
85
|
import type { AccessLogWriter } from './audit/access-log.js';
|
|
86
86
|
import type { GenericSourceManager } from './webhook/generic-sources.js';
|
|
87
87
|
import type { TrustStore } from './events/trust-store.js';
|
|
88
|
-
import
|
|
88
|
+
import { ContextStore } from './contexts/context-store.js';
|
|
89
89
|
import type { VariableStore } from './contexts/variable-store.js';
|
|
90
90
|
import type { HeldRunStore, ReleaseSignal } from './contexts/held-runs.js';
|
|
91
91
|
import type { StepApprovalBridge } from './approvals/step-approval-bridge.js';
|
|
@@ -97,6 +97,13 @@ export interface AppDependencies {
|
|
|
97
97
|
config: AppConfig;
|
|
98
98
|
db: Kysely<Database>;
|
|
99
99
|
pool: pg.Pool;
|
|
100
|
+
/**
|
|
101
|
+
* The orchestrator master key in both forms, plus the previous generation
|
|
102
|
+
* during a rotation grace window. Null when no master key is configured.
|
|
103
|
+
* Resolved once at boot so every master-key-wrapped store agrees, and so
|
|
104
|
+
* `KICI_SECRET_KEY_FILE` reaches all of them.
|
|
105
|
+
*/
|
|
106
|
+
masterKeys?: ResolvedMasterKeys | null;
|
|
100
107
|
/** Fleet-wide settings reader; threads the live lock-file cap into warm-added universal-git sources. */
|
|
101
108
|
clusterSettings?: ClusterSettingsReader;
|
|
102
109
|
registry: AgentRegistry;
|
|
@@ -187,7 +194,7 @@ export interface AppDependencies {
|
|
|
187
194
|
* the composition root / server hooks. Type-only reference — the runtime
|
|
188
195
|
* module never enters the shipped bundle.
|
|
189
196
|
*/
|
|
190
|
-
faultInjection?: import('./
|
|
197
|
+
faultInjection?: import('./fault-injection-types.js').OrchestratorFaultInjection;
|
|
191
198
|
/**
|
|
192
199
|
* Orchestrator-owned provenance signing (Phase 1 root of trust). Present when
|
|
193
200
|
* `KICI_ORCHESTRATOR_PROVENANCE_ISSUER` is configured: the orchestrator mints +
|
|
@@ -336,8 +343,6 @@ export interface AppDependencies {
|
|
|
336
343
|
coldStore?: ColdStore | null;
|
|
337
344
|
/** Read + mutation attribution log writer. Optional -- if not set, access_log rows are not written. */
|
|
338
345
|
accessLogWriter?: AccessLogWriter;
|
|
339
|
-
/** In-memory concurrency group tracker. Optional -- if not set, concurrency is disabled. */
|
|
340
|
-
concurrencyTracker?: ConcurrencyGroupTracker;
|
|
341
346
|
/** DB-backed concurrency queue manager. Optional -- if not set, concurrency is disabled. */
|
|
342
347
|
concurrencyQueueManager?: ConcurrencyQueueManager;
|
|
343
348
|
/** Optional callback when agent sends encrypted secret outputs on job success. */
|
|
@@ -27,14 +27,22 @@ import type { ClusterSettingsReader } from '../cluster/cluster-settings-reader.j
|
|
|
27
27
|
export declare function depTarballKey(depsHash: string, platform: string, arch: string): string;
|
|
28
28
|
/**
|
|
29
29
|
* Cache key for the pointer that resolves a lockfile to the content hash of the
|
|
30
|
-
* tarball built from it: `deps/{platform}-{arch}/{lockfileHash}.hash
|
|
30
|
+
* tarball built from it: `deps/{platform}-{arch}/{lockfileHash}.hash`, or
|
|
31
|
+
* `…/{lockfileHash}-{siblingsDigest}.hash` when the lock carries one.
|
|
32
|
+
*
|
|
33
|
+
* `siblingsDigest` is part of the key because the deps tarball carries in-repo
|
|
34
|
+
* `workspace:` sibling directories WITH their built output, and editing a
|
|
35
|
+
* sibling's source moves no package-manager lock file — so a `lockfileHash`-only
|
|
36
|
+
* key restored the sibling's stale build over the fresh clone on every run. A
|
|
37
|
+
* lock with no in-repo sibling carries no digest and keys exactly as before, so
|
|
38
|
+
* existing pointers stay live.
|
|
31
39
|
*
|
|
32
40
|
* This is the one mutable object in the scheme. A concurrent write replaces a
|
|
33
41
|
* pointer wholesale — there is no window in which it is half-written — so the
|
|
34
42
|
* worst a racing pair of builders can do is leave whichever pointer landed last,
|
|
35
43
|
* and both tarballs remain valid and fetchable.
|
|
36
44
|
*/
|
|
37
|
-
export declare function depPointerKey(lockfileHash: string, platform: string, arch: string): string;
|
|
45
|
+
export declare function depPointerKey(lockfileHash: string, platform: string, arch: string, siblingsDigest?: string): string;
|
|
38
46
|
export declare class DepCache {
|
|
39
47
|
private readonly storage;
|
|
40
48
|
private readonly maxTarballBytes;
|
|
@@ -67,19 +75,19 @@ export declare class DepCache {
|
|
|
67
75
|
* Both halves must be present: a pointer whose tarball has aged out is a miss,
|
|
68
76
|
* not a hit, or the caller skips a rebuild and dispatches a URL that 404s.
|
|
69
77
|
*/
|
|
70
|
-
has(lockfileHash: string, platform: string, arch: string): Promise<boolean>;
|
|
78
|
+
has(lockfileHash: string, platform: string, arch: string, siblingsDigest?: string): Promise<boolean>;
|
|
71
79
|
/**
|
|
72
80
|
* Get a pre-signed download URL for the dep tarball (for agent delivery).
|
|
73
81
|
* Refreshes TTL on hit.
|
|
74
82
|
*/
|
|
75
|
-
getUrl(lockfileHash: string, platform: string, arch: string): Promise<string | null>;
|
|
83
|
+
getUrl(lockfileHash: string, platform: string, arch: string, siblingsDigest?: string): Promise<string | null>;
|
|
76
84
|
/**
|
|
77
85
|
* Get a pre-signed download URL and the tarball content hash.
|
|
78
86
|
*
|
|
79
87
|
* Returns null on cache miss — including an entry with no pointer, which is
|
|
80
88
|
* unverifiable and so is deliberately not served.
|
|
81
89
|
*/
|
|
82
|
-
getUrlAndHash(lockfileHash: string, platform: string, arch: string): Promise<{
|
|
90
|
+
getUrlAndHash(lockfileHash: string, platform: string, arch: string, siblingsDigest?: string): Promise<{
|
|
83
91
|
url: string;
|
|
84
92
|
hash?: string;
|
|
85
93
|
} | null>;
|
|
@@ -93,7 +101,7 @@ export declare class DepCache {
|
|
|
93
101
|
* Called only after the agent confirms its upload completed. Publishing before
|
|
94
102
|
* the bytes land would let a reader follow the pointer to a missing object.
|
|
95
103
|
*/
|
|
96
|
-
publishPointer(lockfileHash: string, platform: string, arch: string, depsHash: string): Promise<void>;
|
|
104
|
+
publishPointer(lockfileHash: string, platform: string, arch: string, depsHash: string, siblingsDigest?: string): Promise<void>;
|
|
97
105
|
/**
|
|
98
106
|
* Store a dep tarball in cache.
|
|
99
107
|
* Throws if tarball exceeds max size (per user decision).
|
|
@@ -42,7 +42,7 @@ import type { GlobalEvalRoundResult } from '@kici-dev/engine';
|
|
|
42
42
|
* than a wrong verdict.
|
|
43
43
|
*
|
|
44
44
|
* Returns `null` when the inputs cannot be serialized. A round that cannot be
|
|
45
|
-
* keyed is
|
|
45
|
+
* keyed is not cached — never keyed on a partial input, which is how a
|
|
46
46
|
* cache starts answering questions it was not asked.
|
|
47
47
|
*/
|
|
48
48
|
export declare function globalEvalRoundCacheKey(args: {
|
package/dist/cache/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Cache module for customer-workflow source tarballs and dependency tarballs.
|
|
3
3
|
*
|
|
4
4
|
* SourceCache: content-hash-keyed storage for `.kici/` source tarballs
|
|
5
|
-
* (`source/{
|
|
5
|
+
* (`source/v2/{orgId}/{sourceTarDigest}.tar.gz`).
|
|
6
6
|
* BuildCoordinator: deduplicates concurrent build requests.
|
|
7
7
|
* DepCache: lockfileHash-keyed storage for dependency tarballs.
|
|
8
8
|
*/
|
|
@@ -1,30 +1,107 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Source-tarball cache layer wrapping CacheStorage.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Stores customer-workflow source tarballs — the `.kici/` directory minus
|
|
5
|
+
* `node_modules/`, packed by the agent's build job via `source-packer.ts` —
|
|
6
|
+
* under the tarball's OWN content hash, with a small pointer resolving an org's
|
|
7
|
+
* workflow `contentHash` to that hash. Tarballs are platform-independent: raw
|
|
8
|
+
* TypeScript source is identical across architectures. Refreshes TTL on reads
|
|
8
9
|
* (touch-on-read) so actively used sources stay in cache longer.
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
+
* Keys: `source/v2/{orgId}/{sourceTarDigest}.tar.gz` (immutable) and
|
|
12
|
+
* `source/v2/{orgId}/{contentHash}.hash` (the pointer) — the shape `dep-cache.ts`
|
|
13
|
+
* already uses, for the same reasons — content addressing and org scoping.
|
|
11
14
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
15
|
+
* **Content addressing** makes a mismatched pair unrepresentable. At
|
|
16
|
+
* `source/{contentHash}.tar.gz` the object's key was derived from something
|
|
17
|
+
* other than its bytes, so nothing a reader fetched could be verified against
|
|
18
|
+
* anything, and the agent restored whatever the signed URL returned.
|
|
19
|
+
*
|
|
20
|
+
* **Org scoping** makes the key a tenant's key. `contentHash` alone is a
|
|
21
|
+
* property of a `.kici/` tree, so two repositories scaffolded from the same
|
|
22
|
+
* `kici init` template — or a fork and its upstream — produced one object, and
|
|
23
|
+
* whichever built first won for the life of that object. On an orchestrator
|
|
24
|
+
* serving more than one org that is a cross-tenant read of `.kici/` contents.
|
|
25
|
+
* The org is the tenant boundary and the segment the user cache already scopes
|
|
26
|
+
* by; inside one org, sharing a key now means the two trees are byte-identical,
|
|
27
|
+
* so a monorepo or a same-org fork keeps its warm cache and pays nothing.
|
|
28
|
+
*
|
|
29
|
+
* Legacy `source/{contentHash}.tar.gz` objects are **not read**. Only a
|
|
30
|
+
* `compileSchemaVersion: 5` lock can name one, and that `contentHash` covers
|
|
31
|
+
* the workflow entry file alone rather than the tree the tarball holds — the
|
|
32
|
+
* defect this layout closes — so serving it would serve the bug. For a v6 lock
|
|
33
|
+
* the fallback is unreachable anyway, since the schema bump moves every hash.
|
|
34
|
+
* Old objects are orphaned and aged out by the normal cache TTL.
|
|
16
35
|
*/
|
|
17
36
|
import type { CacheStorage } from '../storage/types.js';
|
|
37
|
+
/**
|
|
38
|
+
* Cache key for a source tarball, addressed by the tarball's OWN content hash:
|
|
39
|
+
* `source/v2/{orgId}/{sourceTarDigest}.tar.gz`.
|
|
40
|
+
*
|
|
41
|
+
* Naming the object by its own hash means every pair a reader can observe is
|
|
42
|
+
* self-consistent, and the bytes at a given key can never change after a URL is
|
|
43
|
+
* signed for it.
|
|
44
|
+
*/
|
|
45
|
+
export declare function sourceTarballKey(orgId: string, sourceTarDigest: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Cache key for the pointer that resolves a workflow `contentHash` to the
|
|
48
|
+
* content hash of the tarball built from it: `source/v2/{orgId}/{contentHash}.hash`.
|
|
49
|
+
*
|
|
50
|
+
* This is the one mutable object in the scheme. A concurrent write replaces a
|
|
51
|
+
* pointer wholesale — there is no half-written window — so the worst a racing
|
|
52
|
+
* pair of builders can do is leave whichever pointer landed last, and both
|
|
53
|
+
* tarballs stay valid and fetchable.
|
|
54
|
+
*/
|
|
55
|
+
export declare function sourcePointerKey(orgId: string, contentHash: string): string;
|
|
18
56
|
export declare class SourceCache {
|
|
19
57
|
private readonly storage;
|
|
20
58
|
constructor(options: {
|
|
21
59
|
storage: CacheStorage;
|
|
22
60
|
});
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
61
|
+
/** The single place the pointer indirection is read. */
|
|
62
|
+
private resolvePointer;
|
|
63
|
+
/**
|
|
64
|
+
* Whether a source tarball for this org's `contentHash` exists.
|
|
65
|
+
*
|
|
66
|
+
* Both halves must be present: a pointer whose tarball has aged out is a
|
|
67
|
+
* miss, not a hit, or the caller skips a rebuild and dispatches a URL that
|
|
68
|
+
* 404s on the agent.
|
|
69
|
+
*/
|
|
70
|
+
has(orgId: string, contentHash: string): Promise<boolean>;
|
|
71
|
+
get(orgId: string, contentHash: string): Promise<Buffer | null>;
|
|
72
|
+
/**
|
|
73
|
+
* A pre-signed download URL and the tarball's own digest.
|
|
74
|
+
*
|
|
75
|
+
* The pointer is resolved FIRST: it names the content hash, which is also the
|
|
76
|
+
* tarball's key, so the url and the digest returned here are read from a
|
|
77
|
+
* single source of truth and cannot disagree. Returns null on a miss —
|
|
78
|
+
* including a pointer with no tarball behind it, which is unverifiable and so
|
|
79
|
+
* is deliberately not served.
|
|
80
|
+
*/
|
|
81
|
+
getUrlAndDigest(orgId: string, contentHash: string): Promise<{
|
|
82
|
+
url: string;
|
|
83
|
+
digest: string;
|
|
84
|
+
} | null>;
|
|
85
|
+
getUrl(orgId: string, contentHash: string): Promise<string | null>;
|
|
86
|
+
/**
|
|
87
|
+
* A pre-signed upload URL for direct agent-to-storage upload.
|
|
88
|
+
*
|
|
89
|
+
* Takes the tarball's OWN digest, not the workflow `contentHash`: the agent
|
|
90
|
+
* computes it before asking for a URL, and the object is named by it.
|
|
91
|
+
*/
|
|
92
|
+
getUploadUrl(orgId: string, sourceTarDigest: string): Promise<string>;
|
|
93
|
+
/**
|
|
94
|
+
* Publish the pointer that makes an uploaded tarball discoverable by
|
|
95
|
+
* `contentHash`. Called only after the agent confirms its upload completed —
|
|
96
|
+
* publishing before the bytes land would let a reader follow the pointer to a
|
|
97
|
+
* missing object.
|
|
98
|
+
*/
|
|
99
|
+
publishPointer(orgId: string, contentHash: string, sourceTarDigest: string): Promise<void>;
|
|
100
|
+
/** Store a tarball and the pointer that names it. */
|
|
101
|
+
store(orgId: string, contentHash: string, tarball: Buffer | string): Promise<void>;
|
|
102
|
+
/** SHA-256 of a tarball's bytes. The agent computes the same value. */
|
|
103
|
+
static computeDigest(data: Buffer): string;
|
|
104
|
+
/** Remove a source tarball and its pointer. */
|
|
105
|
+
remove(orgId: string, contentHash: string): Promise<boolean>;
|
|
29
106
|
}
|
|
30
107
|
//# sourceMappingURL=source-cache.d.ts.map
|
|
@@ -18,15 +18,26 @@
|
|
|
18
18
|
import type { Kysely } from 'kysely';
|
|
19
19
|
import type { Database } from '../db/types.js';
|
|
20
20
|
import type { JobQueue } from '../queue/job-queue.js';
|
|
21
|
-
import type { Dispatcher } from '../agent/dispatcher.js';
|
|
22
21
|
import type { AgentRegistry } from '../agent/registry.js';
|
|
23
22
|
import type { ExecutionTracker } from '../reporting/execution-tracker.js';
|
|
24
23
|
export interface CancelRunDeps {
|
|
25
24
|
db: Kysely<Database>;
|
|
26
25
|
jobQueue: JobQueue;
|
|
27
|
-
dispatcher: Dispatcher;
|
|
28
26
|
registry: AgentRegistry;
|
|
29
27
|
executionTracker: ExecutionTracker;
|
|
28
|
+
/**
|
|
29
|
+
* This coordinator's instance id. Undefined ⇒ no cluster identity, so every
|
|
30
|
+
* job resolves to "mine" and the behaviour is the single-coordinator one.
|
|
31
|
+
*/
|
|
32
|
+
instanceId?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Forward `job.cancel` to the coordinator holding the agent's socket.
|
|
35
|
+
* Returns whether the send left this process. Undefined ⇒ no peer transport,
|
|
36
|
+
* so a job owned by a sibling is unreachable rather than orphaned.
|
|
37
|
+
*/
|
|
38
|
+
cancelJobOnPeer?: (peerId: string, runId: string, jobId: string, reason: string) => boolean;
|
|
39
|
+
/** How stale a `cluster_instances` heartbeat may be and still read as live. */
|
|
40
|
+
ownershipGraceMs?: number;
|
|
30
41
|
}
|
|
31
42
|
export interface CancelRunOptions {
|
|
32
43
|
/** Force immediate SIGKILL on the agent (skip graceful hooks). */
|
|
@@ -39,6 +50,13 @@ export interface CancelRunOptions {
|
|
|
39
50
|
export interface CancelRunResult {
|
|
40
51
|
/** Number of `job.cancel` messages dispatched to agents (running jobs). */
|
|
41
52
|
agentsNotified: number;
|
|
53
|
+
/**
|
|
54
|
+
* Jobs whose owning coordinator is alive but could not be reached — the peer
|
|
55
|
+
* send failed, or there is no peer transport. They are NOT notified and they
|
|
56
|
+
* are NOT orphaned: the job may well still be running, so the run stays
|
|
57
|
+
* `cancelling` and the re-drive sweep tries again.
|
|
58
|
+
*/
|
|
59
|
+
unreachable: number;
|
|
42
60
|
/** Number of pending/queued execution_jobs rows marked cancelled. */
|
|
43
61
|
pendingCancelled: number;
|
|
44
62
|
/**
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Kysely } from 'kysely';
|
|
2
|
+
import type { Database } from '../db/types.js';
|
|
3
|
+
export interface SweepStuckCancellingDeps {
|
|
4
|
+
db: Kysely<Database>;
|
|
5
|
+
/** The canonical cancel path, bound to this orchestrator's deps. */
|
|
6
|
+
cancelRun: (runId: string, reason: string) => Promise<unknown>;
|
|
7
|
+
/**
|
|
8
|
+
* How long a run may sit in `cancelling` before it is re-driven. Twice the
|
|
9
|
+
* recovery grace period: long enough that a graceful agent teardown finishes
|
|
10
|
+
* on its own, short enough that a dropped cancel does not sit for an hour.
|
|
11
|
+
*/
|
|
12
|
+
stuckAfterMs: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Re-drive the cancel for runs left in `cancelling`.
|
|
16
|
+
*
|
|
17
|
+
* A cancel reaches its target over the peer channel, and a peer blip drops it.
|
|
18
|
+
* The run then sits in `cancelling` with its jobs still executing, and nothing
|
|
19
|
+
* retries: the workflow-deadline detector re-scans `cancelling` runs, but only
|
|
20
|
+
* ones that HAVE a workflow timeout, so a run without one waits forever. This
|
|
21
|
+
* extends the same coverage to every run.
|
|
22
|
+
*
|
|
23
|
+
* Leader-gated by its caller, and idempotent by construction — re-driving a
|
|
24
|
+
* cancel that already landed re-sends `job.cancel` to an agent that is already
|
|
25
|
+
* unwinding, and re-driving one whose jobs are all terminal completes the run.
|
|
26
|
+
*
|
|
27
|
+
* @returns how many runs were re-driven.
|
|
28
|
+
*/
|
|
29
|
+
export declare function sweepStuckCancelling(deps: SweepStuckCancellingDeps): Promise<number>;
|
|
30
|
+
//# sourceMappingURL=sweep-stuck-cancelling.d.ts.map
|
package/dist/cli/api-client.d.ts
CHANGED
|
@@ -199,6 +199,14 @@ export declare class AdminApiClient {
|
|
|
199
199
|
skippedConfigs: number;
|
|
200
200
|
reEncryptedBackends: number;
|
|
201
201
|
skippedBackends: number;
|
|
202
|
+
reEncryptedSigningKeys: number;
|
|
203
|
+
skippedSigningKeys: number;
|
|
204
|
+
reEncryptedDashboardKeys: number;
|
|
205
|
+
skippedDashboardKeys: number;
|
|
206
|
+
reEncryptedEphemeralKeys: number;
|
|
207
|
+
skippedEphemeralKeys: number;
|
|
208
|
+
reEncryptedSecretOutputs: number;
|
|
209
|
+
skippedSecretOutputs: number;
|
|
202
210
|
}>;
|
|
203
211
|
createGenericSource(data: {
|
|
204
212
|
orgId: string;
|
|
@@ -274,6 +282,8 @@ export declare class AdminApiClient {
|
|
|
274
282
|
routingKey?: string;
|
|
275
283
|
/** Optional absolute expiry as an ISO datetime string. */
|
|
276
284
|
expiresAt?: string;
|
|
285
|
+
/** Optional intended holder (an OIDC `sub` or an email). Advisory only. */
|
|
286
|
+
subject?: string;
|
|
277
287
|
}): Promise<{
|
|
278
288
|
token: string;
|
|
279
289
|
id: string;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* and output format. Delegates to the platform-specific service
|
|
6
6
|
* manager's logs() method.
|
|
7
7
|
*
|
|
8
|
-
* Target resolution goes through
|
|
8
|
+
* Target resolution goes through resolveInstanceTarget — the same priority chain
|
|
9
9
|
* every lifecycle command uses (--instance-dir > --name > CWD manifest >
|
|
10
10
|
* refusal with candidate list).
|
|
11
11
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `kici-admin agent restart` command.
|
|
3
3
|
*
|
|
4
4
|
* Restarts the agent service. Target resolution goes through
|
|
5
|
-
*
|
|
5
|
+
* resolveInstanceTarget — the same priority chain every lifecycle command uses
|
|
6
6
|
* (--instance-dir > --name > CWD manifest > refusal with candidate list).
|
|
7
7
|
* `--name` has no default; every invocation must resolve via one of the
|
|
8
8
|
* above paths.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `kici-admin agent start` command.
|
|
3
3
|
*
|
|
4
4
|
* Starts the agent service. Target resolution goes through
|
|
5
|
-
*
|
|
5
|
+
* resolveInstanceTarget — the same priority chain every lifecycle command uses
|
|
6
6
|
* (--instance-dir > --name > CWD manifest > refusal with candidate list).
|
|
7
7
|
* `--name` has no default; every invocation must resolve via one of the
|
|
8
8
|
* above paths.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* the running agent's health API for agent-specific info (labels,
|
|
6
6
|
* orchestrator connection, current job).
|
|
7
7
|
*
|
|
8
|
-
* Target resolution goes through
|
|
8
|
+
* Target resolution goes through resolveInstanceTarget — the same priority chain
|
|
9
9
|
* every lifecycle command uses (--instance-dir > --name > CWD manifest >
|
|
10
10
|
* refusal with candidate list).
|
|
11
11
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `kici-admin agent stop` command.
|
|
3
3
|
*
|
|
4
4
|
* Stops the agent service. Target resolution goes through
|
|
5
|
-
*
|
|
5
|
+
* resolveInstanceTarget — the same priority chain every lifecycle command uses
|
|
6
6
|
* (--instance-dir > --name > CWD manifest > refusal with candidate list).
|
|
7
7
|
* `--name` has no default; every invocation must resolve via one of the
|
|
8
8
|
* above paths.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `kici-admin agent uninstall` command.
|
|
3
3
|
*
|
|
4
4
|
* Removes the agent service registration. Target resolution goes
|
|
5
|
-
* through
|
|
5
|
+
* through resolveInstanceTarget — the same priority chain every lifecycle command
|
|
6
6
|
* uses (--instance-dir > --name > CWD manifest > refusal with candidate list).
|
|
7
7
|
* The manifest stays on disk so subsequent commands can still reference the
|
|
8
8
|
* deploy folder; the host-wide index entry is dropped unconditionally so a
|
|
@@ -6,5 +6,30 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { Command } from 'commander';
|
|
8
8
|
import type { AdminApiClient } from '../api-client.js';
|
|
9
|
+
/**
|
|
10
|
+
* The authorized label scope a static agent token is minted with.
|
|
11
|
+
*
|
|
12
|
+
* Beyond the operator's own `--labels` set, the authorized scope carries:
|
|
13
|
+
*
|
|
14
|
+
* - A mandatory (taint) label must also be advertisable (the selector side),
|
|
15
|
+
* so union it into the authorized labels — a taint the agent can't even
|
|
16
|
+
* advertise would be incoherent.
|
|
17
|
+
* - Every real agent derives its `kici:role:*` labels from its own host and
|
|
18
|
+
* advertises them at registration, so a scope omitting them can never admit
|
|
19
|
+
* the agent that presents it: the orchestrator's register-time scope gate
|
|
20
|
+
* closes the connection with `Agent labels exceed token-bound scope`. A role
|
|
21
|
+
* the agent can't even advertise is incoherent for the same reason a taint
|
|
22
|
+
* is. The mint site cannot know which roles the target host will derive — the
|
|
23
|
+
* agent discovers them from its own capabilities — so the whole role
|
|
24
|
+
* namespace is authorized and the agent advertises the subset it has.
|
|
25
|
+
*
|
|
26
|
+
* The operator's own labels still bound everything else: a token minted with
|
|
27
|
+
* `--labels linux,x64` still refuses an agent advertising `gpu`. An agent that
|
|
28
|
+
* must carry no roles at all sets `KICI_ROLES=` on its own side.
|
|
29
|
+
*
|
|
30
|
+
* Returns undefined when the operator supplied no labels and no taint — an
|
|
31
|
+
* unscoped token, which the register-time gate skips entirely.
|
|
32
|
+
*/
|
|
33
|
+
export declare function authorizedAgentTokenLabels(baseLabels: readonly string[], mandatoryLabels: readonly string[] | undefined): string[] | undefined;
|
|
9
34
|
export declare function registerAgentCommands(program: Command, getClient: () => AdminApiClient): void;
|
|
10
35
|
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -12,5 +12,21 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import type { Command } from 'commander';
|
|
14
14
|
import type { AdminApiClient } from '../api-client.js';
|
|
15
|
+
/**
|
|
16
|
+
* Whether a shared-config path is one a joining orchestrator receives.
|
|
17
|
+
*
|
|
18
|
+
* True for the consumed paths themselves and for anything below them, so
|
|
19
|
+
* `storage.bucket` counts and `storageQuota` does not.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isConsumedSharedConfigPath(path: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Warning text for a `config set` on a path nothing reads back, or null when
|
|
24
|
+
* the path is consumed.
|
|
25
|
+
*
|
|
26
|
+
* The write itself succeeds and is versioned — the operator is told which
|
|
27
|
+
* mechanism actually changes a running orchestrator, so a stored-but-inert
|
|
28
|
+
* value is not mistaken for an applied one.
|
|
29
|
+
*/
|
|
30
|
+
export declare function sharedConfigSetWarning(path: string): string | null;
|
|
15
31
|
export declare function registerConfigCommands(program: Command, getClient: () => AdminApiClient): void;
|
|
16
32
|
//# sourceMappingURL=config.d.ts.map
|