@kici-dev/orchestrator 0.1.15 → 0.1.17

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.
Files changed (94) hide show
  1. package/dist/agent/dispatcher.d.ts +18 -1
  2. package/dist/app.d.ts +25 -0
  3. package/dist/approvals/apply-decision.d.ts +70 -0
  4. package/dist/approvals/approval-resolver.d.ts +66 -0
  5. package/dist/approvals/step-approval-bridge.d.ts +72 -0
  6. package/dist/approvals/team-membership-lookup.d.ts +13 -0
  7. package/dist/cache/pending-inits.d.ts +5 -0
  8. package/dist/cache/user-cache.d.ts +1 -1
  9. package/dist/cli/api-client.d.ts +35 -0
  10. package/dist/cli/commands/firecracker/index.d.ts +11 -0
  11. package/dist/cli/commands/firecracker/provision.d.ts +13 -0
  12. package/dist/cli/commands/firecracker/teardown.d.ts +3 -0
  13. package/dist/cli/commands/firecracker/verify.d.ts +3 -0
  14. package/dist/cli/commands/local-hook.d.ts +15 -0
  15. package/dist/cli/commands/local-trigger.d.ts +24 -0
  16. package/dist/cli/commands/remote-source.d.ts +17 -0
  17. package/dist/cli/commands/scaler.d.ts +18 -0
  18. package/dist/cli/commands/shared/versioned-upgrade.d.ts +14 -0
  19. package/dist/cli/kici-admin.d.ts +23 -1
  20. package/dist/cli/service/image-digests.d.ts +21 -0
  21. package/dist/cli.js +4320 -490
  22. package/dist/cluster/peer-client.d.ts +23 -1
  23. package/dist/cluster/peer-handler.d.ts +9 -1
  24. package/dist/config.d.ts +0 -4
  25. package/dist/dashboard/handler.d.ts +26 -2
  26. package/dist/dashboard/needs-edges.d.ts +13 -0
  27. package/dist/db/migrations/033_org_settings_approval.d.ts +19 -0
  28. package/dist/db/migrations/034_held_runs_generalize.d.ts +24 -0
  29. package/dist/db/migrations/035_pending_workflow_contexts.d.ts +11 -0
  30. package/dist/db/migrations/036_attestations.d.ts +15 -0
  31. package/dist/db/migrations/037_generic_sources_provider_type_local.d.ts +19 -0
  32. package/dist/db/migrations/038_remote_sources.d.ts +14 -0
  33. package/dist/db/types.d.ts +135 -11
  34. package/dist/diagnostics/bundle-writer.d.ts +1 -17
  35. package/dist/diagnostics/checks/firecracker-network.d.ts +13 -0
  36. package/dist/diagnostics/checks/index.d.ts +2 -1
  37. package/dist/diagnostics/fleet-collector.d.ts +52 -0
  38. package/dist/diagnostics/fleet-constants.d.ts +8 -0
  39. package/dist/diagnostics/fleet-selection.d.ts +15 -0
  40. package/dist/diagnostics/fleet-topology.d.ts +47 -0
  41. package/dist/diagnostics/fleet-wiring.d.ts +60 -0
  42. package/dist/entry-helpers.d.ts +7 -29
  43. package/dist/environments/held-runs.d.ts +93 -1
  44. package/dist/firecracker/host-network.d.ts +83 -0
  45. package/dist/firecracker/persist.d.ts +14 -0
  46. package/dist/index.js +25 -6
  47. package/dist/metrics/prometheus.d.ts +4 -2
  48. package/dist/orchestrator-core.d.ts +57 -1
  49. package/dist/pipeline/dispatch-matched-workflow.d.ts +18 -1
  50. package/dist/pipeline/install-secrets-resolver.d.ts +32 -5
  51. package/dist/pipeline/needs-scheduler.d.ts +12 -10
  52. package/dist/pipeline/pending-workflow-context.d.ts +44 -0
  53. package/dist/pipeline/processor.d.ts +28 -4
  54. package/dist/pipeline/remote-source-store.d.ts +21 -0
  55. package/dist/pipeline/resume-workflow.d.ts +26 -0
  56. package/dist/providers/local/index.d.ts +33 -0
  57. package/dist/providers/local/local-source-config.d.ts +17 -0
  58. package/dist/providers/{internal → local}/lock-file-fetcher.d.ts +6 -6
  59. package/dist/providers/{internal → local}/normalizer.d.ts +28 -28
  60. package/dist/providers/{internal → local}/repo-url-builder.d.ts +6 -6
  61. package/dist/reporting/execution-tracker.d.ts +33 -0
  62. package/dist/routes/admin-events.d.ts +3 -4
  63. package/dist/routes/fleet.d.ts +20 -0
  64. package/dist/routes/uploads.d.ts +36 -26
  65. package/dist/scaler/config.d.ts +4 -2
  66. package/dist/scaler/disk-guard.d.ts +27 -0
  67. package/dist/scaler/firecracker-backend.d.ts +18 -0
  68. package/dist/scaler/manager.d.ts +6 -0
  69. package/dist/scaler/nftables.d.ts +4 -0
  70. package/dist/scaler/reap-orphans.d.ts +27 -0
  71. package/dist/scaler/types.d.ts +2 -0
  72. package/dist/server.js +26929 -23511
  73. package/dist/sources/build-platform-sources.d.ts +4 -2
  74. package/dist/stale-detector/stale-run-detector.d.ts +32 -1
  75. package/dist/standalone.js +16941 -15329
  76. package/dist/storage/filesystem.d.ts +2 -1
  77. package/dist/storage/s3.d.ts +2 -1
  78. package/dist/storage/types.d.ts +7 -0
  79. package/dist/webhook/generic-sources-listener.d.ts +4 -0
  80. package/dist/webhook/generic-sources.d.ts +37 -11
  81. package/dist/webhook/register-source-bundle.d.ts +14 -4
  82. package/dist/ws/agent-handler.d.ts +49 -0
  83. package/dist/ws/dashboard-dispatch-guard.d.ts +21 -0
  84. package/dist/ws/dashboard-env-handler.d.ts +47 -0
  85. package/dist/ws/fleet-agent-collector.d.ts +23 -0
  86. package/dist/ws/oidc-token-relay.d.ts +59 -0
  87. package/dist/ws/platform-client.d.ts +30 -1
  88. package/dist/ws/test-relay-handlers.d.ts +112 -0
  89. package/installer-image-digests.json +7 -0
  90. package/package.json +6 -5
  91. package/sbom.spdx.json +112 -57
  92. package/dist/providers/internal/index.d.ts +0 -32
  93. package/dist/routes/test-trigger.d.ts +0 -41
  94. package/dist/ws/observer-handler.d.ts +0 -42
@@ -10,7 +10,7 @@
10
10
  * Authentication uses ECDH key exchange followed by join token (first connect)
11
11
  * or HMAC credential proof (reconnection).
12
12
  */
13
- import { type PeerHeartbeat, type PeerToPeerMessage, type JobReroute, type JobProgress, type PeerJobCancel, type PeerLogChunk, type PeerCacheUploadRequest, type PeerCacheUploadResponse, type PeerConfigReload, type PeerConfigReloadResponse, type PeerLeaving, type PeerAgentTokenRevoke, type RaftVoteRequest, type RaftVoteResponse, type RaftAppendEntries } from '@kici-dev/engine';
13
+ import { type PeerHeartbeat, type PeerToPeerMessage, type JobReroute, type JobProgress, type PeerJobCancel, type PeerLogChunk, type PeerCacheUploadRequest, type PeerCacheUploadResponse, type PeerConfigReload, type PeerConfigReloadResponse, type PeerLogsCollectRequest, type PeerLeaving, type PeerAgentTokenRevoke, type RaftVoteRequest, type RaftVoteResponse, type RaftAppendEntries } from '@kici-dev/engine';
14
14
  import type { PeerRegistry } from './peer-registry.js';
15
15
  type PeerConnectionState = 'disconnected' | 'connecting' | 'handshaking' | 'authenticating' | 'connected';
16
16
  export interface PeerClientOptions {
@@ -78,7 +78,20 @@ export interface PeerClientOptions {
78
78
  * Platform-mediated discovery dedupes against the same client.
79
79
  */
80
80
  onAuthenticated?: (targetInstanceId: string) => void;
81
+ /**
82
+ * Callback when a peer.logs.collect.request is received from the peer. Builds
83
+ * this node's subtree bundle and streams it back via the supplied `send`
84
+ * (peer.logs.collect.chunk frames, or a peer.logs.collect.error on failure).
85
+ * If undefined, incoming collect requests are ignored.
86
+ */
87
+ onLogsCollectRequest?: PeerLogsCollectResponder;
81
88
  }
89
+ /**
90
+ * Builds a node's subtree bundle in response to a peer.logs.collect.request and
91
+ * streams it back through `send`. Shared by PeerClient (outgoing-dialed peers)
92
+ * and the peer handler (incoming-dialed peers).
93
+ */
94
+ export type PeerLogsCollectResponder = (msg: PeerLogsCollectRequest, send: (out: PeerToPeerMessage) => boolean) => Promise<void>;
82
95
  export declare class PeerClient {
83
96
  private ws;
84
97
  private _state;
@@ -91,6 +104,8 @@ export declare class PeerClient {
91
104
  private readonly ackWaiters;
92
105
  private readonly cacheWaiters;
93
106
  private readonly configReloadWaiters;
107
+ /** Correlates peer.logs.collect.request with the peer's chunked subtree response. */
108
+ private readonly logsCollectWaiters;
94
109
  private readonly url;
95
110
  private readonly joinToken?;
96
111
  private readonly credentialFile;
@@ -112,6 +127,7 @@ export declare class PeerClient {
112
127
  private readonly onAgentTokenRevoke?;
113
128
  private readonly onPeerConfigReload?;
114
129
  private readonly onAuthenticated?;
130
+ private readonly onLogsCollectRequest?;
115
131
  constructor(options: PeerClientOptions);
116
132
  /** Current connection state. */
117
133
  get state(): PeerConnectionState;
@@ -150,6 +166,12 @@ export declare class PeerClient {
150
166
  * if the peer doesn't reply within the timeout.
151
167
  */
152
168
  sendConfigReloadAndWait(msg: PeerConfigReload, timeoutMs?: number): Promise<PeerConfigReloadResponse | null>;
169
+ /**
170
+ * Send a peer.logs.collect.request to the connected peer and await its
171
+ * reassembled subtree-bundle ZIP. Rejects on timeout, an error frame, or
172
+ * peer disconnect.
173
+ */
174
+ sendLogsCollectAndWait(msg: PeerLogsCollectRequest, timeoutMs: number): Promise<Buffer>;
153
175
  /**
154
176
  * Send a cache upload request to the coordinator and wait for a response
155
177
  * with a pre-signed URL.
@@ -6,7 +6,7 @@
6
6
  * proof (reconnection), registers the peer in PeerRegistry, and routes
7
7
  * messages bidirectionally. Sends periodic heartbeats to the connecting peer.
8
8
  */
9
- import { type PeerHeartbeat, type PeerToPeerMessage, type JobReroute, type JobProgress, type PeerScalerEvent, type PeerJobCancel, type PeerLogChunk, type PeerCacheUploadRequest, type PeerCacheUploadResponse, type PeerConfigReload, type PeerConfigReloadResponse, type PeerLeaving, type PeerAgentTokenRevoke, type RaftVoteRequest, type RaftVoteResponse, type RaftAppendEntries } from '@kici-dev/engine';
9
+ import { type PeerHeartbeat, type PeerToPeerMessage, type JobReroute, type JobProgress, type PeerScalerEvent, type PeerJobCancel, type PeerLogChunk, type PeerCacheUploadRequest, type PeerCacheUploadResponse, type PeerConfigReload, type PeerConfigReloadResponse, type PeerLogsCollectRequest, type PeerLeaving, type PeerAgentTokenRevoke, type RaftVoteRequest, type RaftVoteResponse, type RaftAppendEntries } from '@kici-dev/engine';
10
10
  import type { PeerRegistry } from './peer-registry.js';
11
11
  import type { PeerCredentialStore } from './peer-credentials.js';
12
12
  import { type JoinTokenManager } from './join-token.js';
@@ -78,6 +78,13 @@ export interface PeerHandlerDeps {
78
78
  restartRequired?: string[];
79
79
  fieldsChanged?: string[];
80
80
  }>;
81
+ /**
82
+ * Callback when a peer.logs.collect.request arrives from an incoming-dialed
83
+ * peer. Builds this node's subtree bundle and streams it back through `send`
84
+ * (peer.logs.collect.chunk frames, or a peer.logs.collect.error on failure).
85
+ * If undefined, incoming collect requests are ignored.
86
+ */
87
+ onLogsCollectRequest?: (msg: PeerLogsCollectRequest, send: (out: PeerToPeerMessage) => boolean) => Promise<void>;
81
88
  }
82
89
  /**
83
90
  * Create a handler function for incoming peer WebSocket connections.
@@ -90,6 +97,7 @@ export declare function createPeerHandler(deps: PeerHandlerDeps): {
90
97
  sendToPeer: (targetInstanceId: string, msg: PeerToPeerMessage) => boolean;
91
98
  sendAndWaitAck: (targetInstanceId: string, msg: JobReroute, timeoutMs?: number) => Promise<boolean>;
92
99
  sendConfigReloadAndWait: (targetInstanceId: string, msg: PeerConfigReload, timeoutMs?: number) => Promise<PeerConfigReloadResponse | null>;
100
+ sendLogsCollectAndWait: (targetInstanceId: string, msg: PeerLogsCollectRequest, timeoutMs: number) => Promise<Buffer>;
93
101
  getConnectionCount: () => number;
94
102
  broadcastHeartbeat: (inventory: Omit<PeerHeartbeat, "type">) => void;
95
103
  broadcastAgentTokenRevoke: (msg: PeerAgentTokenRevoke) => void;
package/dist/config.d.ts CHANGED
@@ -105,8 +105,6 @@ declare const configSchema: z.ZodObject<{
105
105
  production: "production";
106
106
  test: "test";
107
107
  }>>;
108
- internalProviderRepoPath: z.ZodOptional<z.ZodString>;
109
- internalProviderCloneUrl: z.ZodOptional<z.ZodString>;
110
108
  autoMigrate: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<boolean, string>>;
111
109
  agentMaxReconnectDelayMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
112
110
  skipS3SentinelValidation: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<boolean, string>>;
@@ -262,8 +260,6 @@ export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
262
260
  secretKeyFileOld?: string | undefined;
263
261
  bootstrapAdminToken?: string | undefined;
264
262
  testEventFailFirstN?: string | undefined;
265
- internalProviderRepoPath?: string | undefined;
266
- internalProviderCloneUrl?: string | undefined;
267
263
  otelExporterOtlpEndpoint?: string | undefined;
268
264
  clusterName?: string | undefined;
269
265
  }>;
@@ -13,14 +13,24 @@
13
13
  */
14
14
  import { type Kysely } from 'kysely';
15
15
  import { type ColdStore } from '@kici-dev/shared';
16
- import type { DashboardRunDetailRequest, DashboardRunsListRequest, DashboardRunsListResponse, DashboardRunsFiltersRequest, DashboardRunsFiltersResponse, DashboardSourcesListRequest, DashboardSourcesListResponse, DashboardStepLogsRequest, DashboardPayloadRequest, DashboardOrchLogsRequest, DashboardEventLogListRequest, DashboardEventLogDetailRequest, DashboardEventLogPayloadStreamRequest, DashboardAccessLogListRequest, DashboardEventDlqListRequest, DashboardEventDlqCountRequest, DashboardEventDlqRetryRequest, DashboardEventDlqDiscardRequest, RunRerunRequest, RunCancelRequest, ManualScheduleRequest } from '@kici-dev/engine';
16
+ import type { DashboardRunDetailRequest, DashboardRunsListRequest, DashboardRunsListResponse, DashboardRunsFiltersRequest, DashboardRunsFiltersResponse, DashboardSourcesListRequest, DashboardSourcesListResponse, DashboardStepLogsRequest, DashboardAttestationsListRequest, DashboardPayloadRequest, DashboardOrchLogsRequest, DashboardEventLogListRequest, DashboardEventLogDetailRequest, DashboardEventLogPayloadStreamRequest, DashboardAccessLogListRequest, DashboardEventDlqListRequest, DashboardEventDlqCountRequest, DashboardEventDlqRetryRequest, DashboardEventDlqDiscardRequest, RunRerunRequest, RunCancelRequest, ManualScheduleRequest } from '@kici-dev/engine';
17
17
  import type { Database } from '../db/types.js';
18
18
  import type { LogStorage } from '../reporting/log-storage.js';
19
+ import type { CacheStorage } from '../storage/types.js';
19
20
  import type { AccessLogWriter } from '../audit/access-log.js';
20
21
  import type { EventStore } from '../events/event-store.js';
21
22
  interface DashboardHandlerDeps {
22
23
  db: Kysely<Database>;
23
24
  logStorage: LogStorage;
25
+ /**
26
+ * Object-storage backend for provenance bundles. The attestations handler
27
+ * reads each stored bundle by `storage_key` and inlines it into the response
28
+ * so the dashboard verifies it client-side without a second fetch. Optional —
29
+ * when absent (e.g. orchestrators without provenance configured) the handler
30
+ * replies with an `error` and an empty list. Reuses the cache storage backend
31
+ * (the same one P1.5 writes bundles to).
32
+ */
33
+ provenanceStorage?: CacheStorage | null;
24
34
  /** Send a response message back to Platform over the WS connection. */
25
35
  send: (msg: unknown) => void;
26
36
  /** This orchestrator's instance ID, included in job detail responses. */
@@ -78,6 +88,7 @@ interface DashboardHandlerDeps {
78
88
  export declare class DashboardHandler {
79
89
  private readonly db;
80
90
  private readonly logStorage;
91
+ private readonly provenanceStorage;
81
92
  private readonly send;
82
93
  private readonly orchestratorId;
83
94
  private readonly accessLog;
@@ -222,7 +233,7 @@ export declare class DashboardHandler {
222
233
  *
223
234
  * `triggerTypes` is populated from `execution_runs.provider` — the
224
235
  * orchestrator has no dedicated trigger-event column, so `provider`
225
- * (`github` / `generic` / `internal`) is the closest available
236
+ * (`github` / `generic` / `local`) is the closest available
226
237
  * discriminator the customer filter can offer.
227
238
  *
228
239
  * Attribution uses the handler-bound `orgId` / `routingKey` directly — the
@@ -251,6 +262,19 @@ export declare class DashboardHandler {
251
262
  * Looks up the step's log_path and reads content from LogStorage.
252
263
  */
253
264
  handleStepLogs(msg: DashboardStepLogsRequest): Promise<void>;
265
+ /**
266
+ * Read the attestation rows for a run, joined to `execution_jobs` for the
267
+ * job name. Ordered oldest-first so the dashboard table is stable.
268
+ */
269
+ private resolveAttestationsForRun;
270
+ /**
271
+ * Handle a dashboard.attestations.list request: list the run's provenance
272
+ * attestations, inlining each stored bundle from object storage so the
273
+ * dashboard verifies it client-side. Mirrors `handleStepLogs` (per-run org
274
+ * resolution + `recordAccess` + `send`). Rows whose bundle can't be read are
275
+ * skipped (best-effort) rather than failing the whole list.
276
+ */
277
+ handleAttestationsList(msg: DashboardAttestationsListRequest): Promise<void>;
254
278
  /**
255
279
  * Handle a dashboard.payload request.
256
280
  * Reads the webhook payload from log storage for the given runId.
@@ -0,0 +1,13 @@
1
+ import { IfFailedPolicy } from '@kici-dev/engine';
2
+ /** A single resolved upstream dependency edge for a job. */
3
+ export interface JobNeedEdge {
4
+ upstreamName: string;
5
+ ifFailed: IfFailedPolicy;
6
+ }
7
+ /** Group raw execution_job_needs rows by downstream job_name. */
8
+ export declare function groupNeedsByJobName(rows: ReadonlyArray<{
9
+ job_name: string;
10
+ upstream_name: string;
11
+ if_failed: string;
12
+ }>): Map<string, JobNeedEdge[]>;
13
+ //# sourceMappingURL=needs-edges.d.ts.map
@@ -0,0 +1,19 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add the two approval-policy columns to `org_settings`:
4
+ *
5
+ * - `approval_expiry_seconds INTEGER NOT NULL DEFAULT 86400` — how long a held
6
+ * approval element waits before it expires (and its run/job/step is
7
+ * rejected). One day by default. An SDK `requireApproval` `timeout` overrides
8
+ * this per element; otherwise this per-org value applies.
9
+ * - `allow_self_approval BOOLEAN NOT NULL DEFAULT true` — whether the user who
10
+ * triggered a run may also approve its held elements. Operators turn it off
11
+ * to enforce four-eyes review.
12
+ *
13
+ * Both are cluster-configurable per org via `kici-admin org-settings approval`
14
+ * and the orchestrator admin route. Idempotent: a re-run on a DB that already
15
+ * has the columns is a no-op (each column is guarded independently).
16
+ */
17
+ export declare function up(db: Kysely<unknown>): Promise<void>;
18
+ export declare function down(db: Kysely<unknown>): Promise<void>;
19
+ //# sourceMappingURL=033_org_settings_approval.d.ts.map
@@ -0,0 +1,24 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Generalize `held_runs` from an environment-only hold into the unified
4
+ * "held element" model that backs per-element approvals, and add the
5
+ * `held_run_approvals` table that records each approver's decision.
6
+ *
7
+ * New `held_runs` columns (all idempotent, column-exists guarded):
8
+ * - `hold_scope text NOT NULL DEFAULT 'job'` — 'workflow' | 'job' | 'step'
9
+ * (engine `HoldScope`). Existing rows held a single job, so they default to
10
+ * 'job'.
11
+ * - `step_index integer` — nullable; set only for step-scoped holds.
12
+ * - `trigger_source text NOT NULL DEFAULT 'environment'` — 'environment' |
13
+ * 'explicit' (engine `TriggerSource`). Existing holds came from environment
14
+ * protection, so they default to 'environment'.
15
+ * - `approval_requirement jsonb` — the normalized `ApprovalRequirement`
16
+ * (clauses + expiresAt + reason) the hold must satisfy. Nullable for legacy
17
+ * rows that predate the approval model.
18
+ *
19
+ * New `held_run_approvals` table: one row per approver decision, FK to
20
+ * `held_runs.id` (uuid) with ON DELETE CASCADE.
21
+ */
22
+ export declare function up(db: Kysely<unknown>): Promise<void>;
23
+ export declare function down(db: Kysely<unknown>): Promise<void>;
24
+ //# sourceMappingURL=034_held_runs_generalize.d.ts.map
@@ -0,0 +1,11 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Pending workflow dispatch context — backs resume of a workflow whose install
4
+ * gate held. One row per held run: the serializable dispatch inputs needed to
5
+ * rebuild the WorkflowDispatchContext when the hold releases (reviewer approve,
6
+ * wait-timer expiry, concurrency slot free). The row is deleted once the resume
7
+ * dispatch has been kicked off.
8
+ */
9
+ export declare function up(db: Kysely<unknown>): Promise<void>;
10
+ export declare function down(db: Kysely<unknown>): Promise<void>;
11
+ //# sourceMappingURL=035_pending_workflow_contexts.d.ts.map
@@ -0,0 +1,15 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add the `attestations` table for build-provenance bundles.
4
+ *
5
+ * When a workflow step calls `ctx.attestProvenance`, the agent uploads the
6
+ * signed KiCI bundle to object storage under
7
+ * `provenance/{run_id}/{job_id}/{subject_digest}.kici.json` and the
8
+ * orchestrator records one row here so the dashboard can list and fetch
9
+ * attestations per run/job.
10
+ *
11
+ * Idempotent: a re-run on a DB that already has the table is a no-op.
12
+ */
13
+ export declare function up(db: Kysely<unknown>): Promise<void>;
14
+ export declare function down(db: Kysely<unknown>): Promise<void>;
15
+ //# sourceMappingURL=036_attestations.d.ts.map
@@ -0,0 +1,19 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Replace the `generic_webhook_sources.provider_type` CHECK constraint so it
4
+ * permits `'local'` instead of `'internal'`, and migrate any carried-over
5
+ * `'internal'` rows to `'local'`.
6
+ *
7
+ * The local filesystem (`file://`) provider is `provider_type='local'`; the
8
+ * value used to be `'internal'`. The original CHECK constraint
9
+ * (`generic_webhook_sources_provider_type_check`) allowed only
10
+ * `{'generic','internal'}`, so writing a `'local'` row fails. Universal-git
11
+ * sources keep `provider_type='generic'` (discriminated by `git_config`), so
12
+ * the new allowed set is `{'generic','local'}`.
13
+ *
14
+ * Idempotent: the constraint is dropped IF EXISTS and recreated; the data
15
+ * backfill is a plain UPDATE that is a no-op once no `'internal'` rows remain.
16
+ */
17
+ export declare function up(db: Kysely<unknown>): Promise<void>;
18
+ export declare function down(db: Kysely<unknown>): Promise<void>;
19
+ //# sourceMappingURL=037_generic_sources_provider_type_local.d.ts.map
@@ -0,0 +1,14 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * `remote_sources` anchors a Platform-relayed `kici run remote` to its real
4
+ * org. One row per org served by this orchestrator: routing key
5
+ * `remote:<orgId>` maps to the canonical org id, so `resolveOrgId` resolves
6
+ * the real tenant through the same local-source path a webhook takes — no
7
+ * GitHub App, no webhook secret, no manual setup. The row is auto-provisioned
8
+ * on Platform auth from the canonical org id carried on `auth.success`.
9
+ *
10
+ * Idempotent: a re-run on a DB that already has the table is a no-op.
11
+ */
12
+ export declare function up(db: Kysely<unknown>): Promise<void>;
13
+ export declare function down(db: Kysely<unknown>): Promise<void>;
14
+ //# sourceMappingURL=038_remote_sources.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import type { ColumnType, Generated, Insertable, Selectable, Updateable } from 'kysely';
2
- import type { InitFailure } from '@kici-dev/engine';
2
+ import type { ApprovalRequirement, ApproverClause, InitFailure } from '@kici-dev/engine';
3
3
  /**
4
4
  * PostgreSQL-only database types.
5
5
  * Column names use snake_case matching the actual database column names.
@@ -19,6 +19,7 @@ export interface Database {
19
19
  environment_variables: EnvironmentVariablesTable;
20
20
  environment_source_overrides: EnvironmentSourceOverridesTable;
21
21
  held_runs: HeldRunsTable;
22
+ held_run_approvals: HeldRunApprovalsTable;
22
23
  admin_tokens: AdminTokenTable;
23
24
  agent_tokens: AgentTokenTable;
24
25
  config_versions: ConfigVersionTable;
@@ -38,6 +39,7 @@ export interface Database {
38
39
  org_settings: OrgSettingsTable;
39
40
  execution_job_needs: ExecutionJobNeedsTable;
40
41
  pending_job_contexts: PendingJobContextsTable;
42
+ pending_workflow_contexts: PendingWorkflowContextsTable;
41
43
  event_log: EventLogTable;
42
44
  access_log: AccessLogTable;
43
45
  cold_store_chunk_counts: ColdStoreChunkCountsTable;
@@ -46,6 +48,8 @@ export interface Database {
46
48
  scaler_spawning_agents: ScalerSpawningAgentsTable;
47
49
  scaler_agent_jobs: ScalerAgentJobsTable;
48
50
  scaler_reservations: ScalerReservationsTable;
51
+ attestations: AttestationsTable;
52
+ remote_sources: RemoteSourcesTable;
49
53
  }
50
54
  /**
51
55
  * Cluster metadata table
@@ -630,10 +634,49 @@ export interface HeldRunsTable {
630
634
  expires_at: Date;
631
635
  /** When this hold was resolved */
632
636
  resolved_at: Date | null;
637
+ /**
638
+ * Hold granularity: 'workflow' | 'job' | 'step' (engine `HoldScope`).
639
+ * Existing environment holds are job-scoped, hence the 'job' default.
640
+ */
641
+ hold_scope: Generated<string>;
642
+ /** Step index within the job for step-scoped holds; null otherwise. */
643
+ step_index: number | null;
644
+ /**
645
+ * What created the hold: 'environment' (mandatory env policy) | 'explicit'
646
+ * (SDK `requireApproval`). Engine `TriggerSource`.
647
+ */
648
+ trigger_source: Generated<string>;
649
+ /**
650
+ * Normalized `ApprovalRequirement` (clauses + expiresAt + reason) the hold
651
+ * must satisfy. Null for legacy rows that predate the approval model.
652
+ */
653
+ approval_requirement: ColumnType<ApprovalRequirement | null, ApprovalRequirement | string | null | undefined, ApprovalRequirement | string | null>;
633
654
  }
634
655
  export type HeldRun = Selectable<HeldRunsTable>;
635
656
  export type NewHeldRun = Insertable<HeldRunsTable>;
636
657
  export type HeldRunUpdate = Updateable<HeldRunsTable>;
658
+ /**
659
+ * One approver's recorded decision on a held element. Multiple rows accumulate
660
+ * until the hold's `ApprovalRequirement` clauses are all satisfied (approve) or
661
+ * any single reject lands.
662
+ */
663
+ export interface HeldRunApprovalsTable {
664
+ /** UUID primary key */
665
+ id: Generated<string>;
666
+ /** FK to held_runs.id (ON DELETE CASCADE) */
667
+ held_run_id: string;
668
+ /** The approver's user id (Keycloak sub) */
669
+ approver_user_id: string;
670
+ /** 'approve' | 'reject' (engine `ApprovalDecision`) */
671
+ decision: string;
672
+ /** Which requirement clauses this decision satisfied (for attribution). */
673
+ clauses_satisfied: ColumnType<ApproverClause[] | null, ApproverClause[] | string | null | undefined, ApproverClause[] | string | null>;
674
+ /** When the decision was recorded */
675
+ created_at: Generated<Date>;
676
+ }
677
+ export type HeldRunApproval = Selectable<HeldRunApprovalsTable>;
678
+ export type NewHeldRunApproval = Insertable<HeldRunApprovalsTable>;
679
+ export type HeldRunApprovalUpdate = Updateable<HeldRunApprovalsTable>;
637
680
  /**
638
681
  * Secret audit log table
639
682
  * Immutable log of secret access and denial events.
@@ -885,15 +928,17 @@ export interface GenericWebhookSourceTable {
885
928
  deleted_at: Date | null;
886
929
  /** Provider implementation to route this source through.
887
930
  * 'generic' (default) → GenericWebhookNormalizer (Stripe-shaped payloads).
888
- * 'internal' → InternalWebhookNormalizer (github-shaped push/PR payloads
889
- * for E2E tests and the staging smoke test). */
931
+ * 'local' → LocalWebhookNormalizer (github-shaped push/PR payloads for a
932
+ * git repository present on the agent filesystem, cloned via file://). */
890
933
  provider_type: Generated<string>;
891
- /** Universal-git config (JSONB) for sources that also know how to build
892
- * clone URLs, fetch lock files, and issue clone credentials against a
893
- * user-supplied git server (Forgejo / Gitea / Gogs / GitLab repo-webhook /
894
- * plain GitHub repo-webhook). null for legacy generic / internal sources
895
- * that don't drive git operations. Shape validated by
896
- * `UniversalGitConfigSchema` at the application layer. */
934
+ /** Git config (JSONB), dual-purpose discriminated by `provider_type`:
935
+ * - universal-git sources ('generic' with git_config) store a
936
+ * `UniversalGitConfig` (clone URLs, lock-file fetch, clone credentials
937
+ * against Forgejo / Gitea / Gogs / GitLab repo-webhook / GitHub repo).
938
+ * - local sources ('local') store a `LocalSourceConfig`
939
+ * (`{ repoBasePath, cloneUrlBase? }`).
940
+ * null for plain generic sources that don't drive git operations. Shape
941
+ * validated by the matching Zod schema at the application layer. */
897
942
  git_config: ColumnType<string | Record<string, unknown> | null, string | null, string | null>;
898
943
  }
899
944
  export type GenericWebhookSource = Selectable<GenericWebhookSourceTable>;
@@ -1192,6 +1237,17 @@ export interface OrgSettingsTable {
1192
1237
  * BIGINT — pg returns a string on select; accept a number on insert/update.
1193
1238
  */
1194
1239
  dispatch_ack_timeout_ms: ColumnType<string | null, number | null | undefined, number | null>;
1240
+ /**
1241
+ * Per-org expiry (seconds) for a held approval element before it is rejected
1242
+ * and its run/job/step fails. NOT NULL, default 86400 (one day). An SDK
1243
+ * `requireApproval` `timeout` overrides this per element.
1244
+ */
1245
+ approval_expiry_seconds: ColumnType<number, number | undefined, number>;
1246
+ /**
1247
+ * Whether the user who triggered a run may also approve its held elements.
1248
+ * NOT NULL, default true. Operators turn it off to enforce four-eyes review.
1249
+ */
1250
+ allow_self_approval: ColumnType<boolean, boolean | undefined, boolean>;
1195
1251
  /** When this setting was created */
1196
1252
  created_at: Generated<Date>;
1197
1253
  /** When this setting was last updated */
@@ -1220,6 +1276,24 @@ export interface PendingJobContextsTable {
1220
1276
  }
1221
1277
  export type PendingJobContextRow = Selectable<PendingJobContextsTable>;
1222
1278
  export type NewPendingJobContext = Insertable<PendingJobContextsTable>;
1279
+ /**
1280
+ * Pending workflow dispatch contexts table.
1281
+ * Persists the serializable WorkflowDispatchContext inputs needed to resume a
1282
+ * workflow whose install gate held. One row per held run (keyed by run_id).
1283
+ * Created at hold time, deleted once the resume dispatch is kicked off.
1284
+ */
1285
+ export interface PendingWorkflowContextsTable {
1286
+ /** Run identifier (one pending dispatch per run) */
1287
+ run_id: string;
1288
+ /** Organization id */
1289
+ org_id: string;
1290
+ /** Serializable WorkflowDispatchContext inputs as JSONB */
1291
+ context: ColumnType<Record<string, unknown>, string, string>;
1292
+ /** When this context was stored */
1293
+ created_at: Generated<Date>;
1294
+ }
1295
+ export type PendingWorkflowContextRow = Selectable<PendingWorkflowContextsTable>;
1296
+ export type NewPendingWorkflowContext = Insertable<PendingWorkflowContextsTable>;
1223
1297
  /**
1224
1298
  * Inbound webhook delivery event log table.
1225
1299
  * One row per inbound webhook delivery (relay or direct), regardless of
@@ -1238,7 +1312,7 @@ export interface EventLogTable {
1238
1312
  org_id: string;
1239
1313
  /** Provider delivery ID (unique within org) */
1240
1314
  delivery_id: string;
1241
- /** Routing key (e.g. "github:42", "generic:<org>:<src>", "internal:...") */
1315
+ /** Routing key (e.g. "github:42", "generic:<org>:<src>") */
1242
1316
  routing_key: string;
1243
1317
  /** Provider event name (X-GitHub-Event / X-Event-Type / 'default') */
1244
1318
  event: string;
@@ -1246,7 +1320,7 @@ export interface EventLogTable {
1246
1320
  action: string | null;
1247
1321
  /** Where the delivery arrived: 'relay' (Platform WS) or 'direct' (HTTP) */
1248
1322
  source: string;
1249
- /** Provider type ('github' / 'generic' / 'internal') */
1323
+ /** Provider type ('github' / 'generic' / 'local') */
1250
1324
  provider: string;
1251
1325
  /** owner/repo when extractable */
1252
1326
  repo_identifier: string | null;
@@ -1405,6 +1479,56 @@ export interface CheckRunTrackingTable {
1405
1479
  export type CheckRunTrackingRow = Selectable<CheckRunTrackingTable>;
1406
1480
  export type NewCheckRunTrackingRow = Insertable<CheckRunTrackingTable>;
1407
1481
  export type CheckRunTrackingUpdate = Updateable<CheckRunTrackingTable>;
1482
+ /**
1483
+ * Build-provenance attestation table.
1484
+ *
1485
+ * One row per `ctx.attestProvenance` bundle uploaded to object storage. The
1486
+ * dashboard lists/fetches attestations by `(run_id, job_id)`.
1487
+ */
1488
+ export interface AttestationsTable {
1489
+ /** Random id (primary key). */
1490
+ id: string;
1491
+ /** KiCI run this attestation belongs to. */
1492
+ run_id: string;
1493
+ /** KiCI job this attestation was produced by. */
1494
+ job_id: string;
1495
+ /** Caller-supplied artifact name (e.g. an npm package coordinate). */
1496
+ subject_name: string;
1497
+ /** Primary subject digest (lowercase hex) used in the storage key. */
1498
+ subject_digest: string;
1499
+ /** Object-storage key the bundle was written to. */
1500
+ storage_key: string;
1501
+ /** Signing mode ('kici' for Mode A). */
1502
+ mode: string;
1503
+ /** Bundle media type. */
1504
+ media_type: string;
1505
+ /** When this row was inserted. */
1506
+ created_at: Generated<Date>;
1507
+ }
1508
+ export type AttestationRow = Selectable<AttestationsTable>;
1509
+ export type NewAttestationRow = Insertable<AttestationsTable>;
1510
+ /**
1511
+ * Remote-source table (remote_sources).
1512
+ *
1513
+ * Anchors a Platform-relayed `kici run remote` to its real org: routing key
1514
+ * `remote:<orgId>` maps to the canonical org id so `resolveOrgId` resolves the
1515
+ * real tenant through the same local-source path a webhook takes. One row per
1516
+ * org served by this orchestrator, auto-provisioned on Platform auth.
1517
+ */
1518
+ export interface RemoteSourcesTable {
1519
+ /** Canonical org id (`org_<…>`) this anchor resolves to. */
1520
+ customer_id: string;
1521
+ /** Deterministic routing key `remote:<orgId>`. */
1522
+ routing_key: string;
1523
+ /** Cluster id this orchestrator deployment reports, or null. */
1524
+ cluster_id: string | null;
1525
+ /** When this row was first provisioned. */
1526
+ created_at: Generated<Date>;
1527
+ /** When this row was last upserted. */
1528
+ updated_at: Generated<Date>;
1529
+ }
1530
+ export type RemoteSourceRow = Selectable<RemoteSourcesTable>;
1531
+ export type NewRemoteSourceRow = Insertable<RemoteSourcesTable>;
1408
1532
  /**
1409
1533
  * Scaler spawning-agents table (scaler_spawning_agents).
1410
1534
  *
@@ -6,8 +6,8 @@
6
6
  * This is the primary support tool -- operators run debug-bundle and share
7
7
  * the ZIP for troubleshooting.
8
8
  */
9
- import archiver from 'archiver';
10
9
  import type { DiagnosticDeps } from './types.js';
10
+ export { redactConfig, addLogsToArchive } from '@kici-dev/shared';
11
11
  export interface BundleOptions {
12
12
  /** Where to write the ZIP. */
13
13
  outputPath: string;
@@ -26,11 +26,6 @@ export interface BundleOptions {
26
26
  /** URL for recent runs endpoint. */
27
27
  recentRunsUrl?: string;
28
28
  }
29
- /**
30
- * Redact config values using allowlist approach.
31
- * Only known-safe fields are preserved; everything else becomes "****".
32
- */
33
- export declare function redactConfig(obj: unknown, parentKey?: string): unknown;
34
29
  /**
35
30
  * Create a debug bundle ZIP file.
36
31
  *
@@ -43,15 +38,4 @@ export declare function redactConfig(obj: unknown, parentKey?: string): unknown;
43
38
  * - logs/summary.json: log statistics
44
39
  */
45
40
  export declare function createDebugBundle(options: BundleOptions): Promise<string>;
46
- /**
47
- * Add log files from logDir to the archive, respecting MAX_LOG_BYTES cap
48
- * and the logWindow time filter. Matches any `*.log` file in the directory,
49
- * so the per-instance filename pattern produced by
50
- * `buildLogFilename()` is picked up without additional configuration.
51
- *
52
- * Exported for reuse by the `kici-admin debug-bundle` CLI command, which
53
- * runs outside the orchestrator process but still needs to include the
54
- * same log files in its locally-assembled bundle.
55
- */
56
- export declare function addLogsToArchive(archive: archiver.Archiver, logDir: string, logWindowHours: number): Promise<void>;
57
41
  //# sourceMappingURL=bundle-writer.d.ts.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Firecracker host-bridge diagnostic. Emits one row per configured Firecracker
3
+ * scaler backend: the bridge interface + its gateway addr + its nft table must
4
+ * all be present, else the scaler cannot spawn microVMs.
5
+ */
6
+ import type { DiagnosticDeps, DiagnosticResult } from '../types.js';
7
+ import { type BridgeHealth, type FirecrackerBridgeConfig } from '../../firecracker/host-network.js';
8
+ interface CheckOpts {
9
+ verify?: (cfg: FirecrackerBridgeConfig) => Promise<BridgeHealth>;
10
+ }
11
+ export declare function checkFirecrackerNetwork(deps: DiagnosticDeps, opts?: CheckOpts): Promise<DiagnosticResult[]>;
12
+ export {};
13
+ //# sourceMappingURL=firecracker-network.d.ts.map
@@ -12,7 +12,8 @@ import { checkDiskSpace } from './disk.js';
12
12
  import { checkConfigValidity } from './config.js';
13
13
  import { checkCertificateExpiry } from './certs.js';
14
14
  import { checkScalerProvisioning } from './scaler.js';
15
+ import { checkFirecrackerNetwork } from './firecracker-network.js';
15
16
  /** All diagnostic checks in display order. */
16
17
  export declare const defaultChecks: DiagnosticCheck[];
17
- export { checkDbConnectivity, checkWsToPlatform, checkAgentConnectivity, checkDiskSpace, checkConfigValidity, checkCertificateExpiry, checkScalerProvisioning, };
18
+ export { checkDbConnectivity, checkWsToPlatform, checkAgentConnectivity, checkDiskSpace, checkConfigValidity, checkCertificateExpiry, checkScalerProvisioning, checkFirecrackerNetwork, };
18
19
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Recursive fleet subtree assembler.
3
+ *
4
+ * Every orchestrator runs this to produce a self-similar subtree ZIP:
5
+ * local/ + nested agents/<id>.zip + workers/<id>.zip + peers/<id>.zip, plus
6
+ * fleet-manifest.json recording per-node status. Dead branches are recorded,
7
+ * never fatal (Promise.allSettled at each level). The loop guard
8
+ * (includeCoordinatorMesh) is true only on the root call; every downstream peer
9
+ * request sets it false so the coordinator mesh never echoes.
10
+ */
11
+ import { z } from 'zod';
12
+ /** Per-node collection outcome recorded in the fleet manifest. */
13
+ export declare const FleetNodeStatus: z.ZodEnum<{
14
+ error: "error";
15
+ ok: "ok";
16
+ unreachable: "unreachable";
17
+ timeout: "timeout";
18
+ }>;
19
+ export type FleetNodeStatus = z.infer<typeof FleetNodeStatus>;
20
+ export interface FleetCollectorDeps {
21
+ /** This orchestrator's instanceId (the manifest owner). */
22
+ instanceId: string;
23
+ /** Build this node's own debug bundle as a Buffer (createDebugBundle output). */
24
+ buildLocalBundle: () => Promise<Buffer>;
25
+ /** List this node's directly-connected agents. */
26
+ listAgents: () => {
27
+ agentId: string;
28
+ }[];
29
+ /** Request a connected agent's mini-bundle over the agent WS channel. */
30
+ requestAgentBundle: (agentId: string) => Promise<Buffer>;
31
+ /** List this node's downstream peers (coordinator-mesh peers + its workers). */
32
+ listPeers: () => {
33
+ instanceId: string;
34
+ role: 'coordinator' | 'worker';
35
+ kind: 'peer' | 'worker';
36
+ }[];
37
+ /** Request a peer's subtree bundle over the peer WS channel (loop-guarded false). */
38
+ requestPeerSubtree: (instanceId: string, includeCoordinatorMesh: boolean) => Promise<Buffer>;
39
+ }
40
+ export interface FleetCollectOptions {
41
+ logWindowHours: number;
42
+ selection: {
43
+ all: boolean;
44
+ agentIds: string[];
45
+ workerInstanceIds: string[];
46
+ };
47
+ /** Loop guard. True only on the root call; downstream requests force false. */
48
+ includeCoordinatorMesh: boolean;
49
+ timeoutMs: number;
50
+ }
51
+ export declare function collectFleetSubtree(opts: FleetCollectOptions, deps: FleetCollectorDeps): Promise<Buffer>;
52
+ //# sourceMappingURL=fleet-collector.d.ts.map
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Shared constants for fleet log collection.
3
+ */
4
+ /** Default per-node deadline for a fleet bundle request (overridable via --fleet-timeout). */
5
+ export declare const FLEET_NODE_TIMEOUT_MS = 60000;
6
+ /** Per-node cap on raw log bytes an agent includes in its mini-bundle (50 MiB). */
7
+ export declare const FLEET_MAX_LOG_BYTES: number;
8
+ //# sourceMappingURL=fleet-constants.d.ts.map