@kici-dev/orchestrator 0.1.23 → 0.1.24

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 (48) hide show
  1. package/dist/agent/token-store.d.ts +4 -0
  2. package/dist/app.d.ts +3 -0
  3. package/dist/cache/pending-inits.d.ts +3 -2
  4. package/dist/cli/api-client.d.ts +8 -0
  5. package/dist/cli/commands/attestations-reverify.d.ts +18 -0
  6. package/dist/cli/commands/attestations.d.ts +3 -0
  7. package/dist/cli/commands/shared/versioned-upgrade.d.ts +52 -0
  8. package/dist/cli.js +2023 -343
  9. package/dist/config.d.ts +2 -0
  10. package/dist/dashboard/attestation-filters.d.ts +70 -0
  11. package/dist/dashboard/handler.d.ts +33 -1
  12. package/dist/db/migrations/054_local_working_tree.d.ts +15 -0
  13. package/dist/db/migrations/055_agent_token_mandatory_labels.d.ts +18 -0
  14. package/dist/db/migrations/056_execution_jobs_environments.d.ts +17 -0
  15. package/dist/db/migrations/057_step_concurrency.d.ts +4 -0
  16. package/dist/db/migrations/058_access_log_agent_label.d.ts +4 -0
  17. package/dist/db/migrations/059_attestation_verdict.d.ts +4 -0
  18. package/dist/db/migrations/060_run_trigger_actor.d.ts +4 -0
  19. package/dist/db/types.d.ts +55 -0
  20. package/dist/environments/protection/aggregate.d.ts +43 -0
  21. package/dist/environments/protection/satisfiability.d.ts +64 -0
  22. package/dist/index.js +9 -0
  23. package/dist/orchestrator-core.d.ts +8 -0
  24. package/dist/pipeline/dispatch-matched-workflow.d.ts +2 -0
  25. package/dist/pipeline/flatten-lock-steps.d.ts +11 -0
  26. package/dist/pipeline/inline-eval.d.ts +2 -1
  27. package/dist/pipeline/job-environments.d.ts +71 -0
  28. package/dist/pipeline/manual-schedule.d.ts +22 -0
  29. package/dist/pipeline/test-pipeline.d.ts +9 -0
  30. package/dist/provenance/trust-root.d.ts +24 -0
  31. package/dist/provenance/verify-at-ingest.d.ts +24 -0
  32. package/dist/reporting/agent-failure-category.d.ts +27 -0
  33. package/dist/reporting/agent-run-result-mapper.d.ts +13 -0
  34. package/dist/reporting/execution-tracker.d.ts +22 -2
  35. package/dist/reporting/run-aggregator.d.ts +161 -0
  36. package/dist/reporting/step-log-reader.d.ts +39 -0
  37. package/dist/routes/admin-registrations.d.ts +8 -0
  38. package/dist/routes/admin-runs.d.ts +7 -0
  39. package/dist/secrets/index.d.ts +1 -1
  40. package/dist/server.js +2798 -1148
  41. package/dist/standalone.js +2627 -1221
  42. package/dist/storage/loopback-guard.d.ts +49 -0
  43. package/dist/ws/agent-handler.d.ts +15 -1
  44. package/dist/ws/platform-client.d.ts +36 -1
  45. package/installer-image-digests.json +3 -3
  46. package/package.json +6 -8
  47. package/sbom.spdx.json +57 -57
  48. package/dist/secrets/crypto.d.ts +0 -49
@@ -0,0 +1,24 @@
1
+ import type { JSONWebKeySet } from 'jose';
2
+ /**
3
+ * Derive the JWKS URI for a provenance OIDC issuer. Identical to the Platform's
4
+ * own derivation (`packages/platform/src/dashboard/routes/runs.ts`) so a bundle
5
+ * verified client-side and at ingest resolve the same key set.
6
+ */
7
+ export declare function deriveJwksUri(issuer: string): string;
8
+ /**
9
+ * The orchestrator's view of the provenance trust root. The issuer arrives over
10
+ * the `auth.success` connect message for the live process, or from config/env
11
+ * (`KICI_PROVENANCE_ISSUER`) for the CLI backfill which has no live handshake.
12
+ * The JWKS is fetched lazily and cached with a single refetch-on-`kid`-miss.
13
+ */
14
+ export interface ProvenanceTrustRoot {
15
+ getIssuer(): string | null;
16
+ getJwks(kid?: string): Promise<JSONWebKeySet | null>;
17
+ setIssuer(issuer: string | null): void;
18
+ }
19
+ export declare function createProvenanceTrustRoot(opts?: {
20
+ issuer?: string | null;
21
+ fetchImpl?: typeof fetch;
22
+ ttlMs?: number;
23
+ }): ProvenanceTrustRoot;
24
+ //# sourceMappingURL=trust-root.d.ts.map
@@ -0,0 +1,24 @@
1
+ import { type AttestationVerifyStatus } from '@kici-dev/engine';
2
+ import type { CacheStorage } from '../storage/types.js';
3
+ import type { ProvenanceTrustRoot } from './trust-root.js';
4
+ export interface AttestationVerdict {
5
+ verifyStatus: AttestationVerifyStatus;
6
+ verifyReason: string | null;
7
+ verifiedAt: Date | null;
8
+ }
9
+ /**
10
+ * Compute the verification verdict for a stored provenance bundle at ingest.
11
+ *
12
+ * Fail-closed: a missing trust root, unfetchable JWKS, missing storage, or an
13
+ * unreadable bundle all yield `unverifiable` (never silently `verified`). A
14
+ * bundle that verifies false yields `failed` with the first failure code. Any
15
+ * thrown error is caught and recorded as `unverifiable` — verification never
16
+ * fails the upload.
17
+ */
18
+ export declare function computeAttestationVerdict(opts: {
19
+ trustRoot: ProvenanceTrustRoot | undefined;
20
+ storage: CacheStorage | undefined;
21
+ storageKey: string;
22
+ logWarn?: (reason: string) => void;
23
+ }): Promise<AttestationVerdict>;
24
+ //# sourceMappingURL=verify-at-ingest.d.ts.map
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Derive a coarse, trusted run-failure classification from existing signals.
3
+ *
4
+ * Pure derivation — no heuristics, no flaky/regression detection (that's a
5
+ * deferred phase). KiCI computes this from data it already records, so the
6
+ * resulting category is a trusted field on the agent run-result.
7
+ */
8
+ import { AgentFailureCategory } from '@kici-dev/engine';
9
+ export interface FailureSignals {
10
+ /** `execution_runs.status`. */
11
+ runStatus: string;
12
+ /** A run- or job-scoped init failure was recorded. */
13
+ hasInitFailure: boolean;
14
+ /** The init-failure category (`InitFailureCategory`), if any. */
15
+ initFailureCategory: string | null;
16
+ /** Any job ended in `timed_out_stale` (or a workflow/job timeout fired). */
17
+ timedOut: boolean;
18
+ /** Any step recorded a non-zero exit code. */
19
+ anyStepNonZeroExit: boolean;
20
+ }
21
+ /**
22
+ * Returns the failure category, or null for a non-failed run (success, or still
23
+ * in flight). Precedence: init failure → timeout → cancelled → step exit →
24
+ * unknown.
25
+ */
26
+ export declare function deriveFailureCategory(s: FailureSignals): AgentFailureCategory | null;
27
+ //# sourceMappingURL=agent-failure-category.d.ts.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Map the canonical run detail into the provenance-tagged `AgentRunResult`.
3
+ *
4
+ * Trusted (plain): ids, enum statuses, exit codes, durations, timestamps,
5
+ * hashes, the derived failure category. Untrusted (enveloped): every name, ref,
6
+ * error string, contributor, job output value — anything sourced from the user's
7
+ * repo / contributor / process output. Secret output *values* are never emitted;
8
+ * only their key names appear.
9
+ */
10
+ import { type AgentRunResult } from '@kici-dev/engine';
11
+ import type { CanonicalRunDetail } from './run-aggregator.js';
12
+ export declare function mapToAgentRunResult(d: CanonicalRunDetail): AgentRunResult;
13
+ //# sourceMappingURL=agent-run-result-mapper.d.ts.map
@@ -23,6 +23,8 @@ export interface ExecutionContext {
23
23
  provider: string;
24
24
  repoIdentifier: string;
25
25
  sha: string;
26
+ /** True when the run executed an uploaded local working tree (`kici run remote`). */
27
+ localWorkingTree?: boolean;
26
28
  installationId?: number;
27
29
  requestId?: string;
28
30
  routingKey?: string;
@@ -38,6 +40,14 @@ export interface ExecutionContext {
38
40
  originalRunId?: string | null;
39
41
  /** User identity that triggered this re-run (null/undefined for webhook-triggered). */
40
42
  triggeredBy?: string | null;
43
+ /**
44
+ * Provider login of the person who triggered the run (pusher / PR author).
45
+ * Captured for all event types; forwarded to the Platform run projection and
46
+ * used to resolve actor-scope notifications.
47
+ */
48
+ triggerActorUsername?: string | null;
49
+ /** Immutable provider user id of the triggering actor (preferred for resolution). */
50
+ triggerActorUserId?: string | null;
41
51
  /** Workflow-level concurrency config from the lock file. */
42
52
  concurrency?: {
43
53
  cancelInProgress?: boolean;
@@ -112,7 +122,9 @@ export interface ExecutionTrackerDeps {
112
122
  * Structured init-failure signal. Set for synthetic rejected-* / init-failed-*
113
123
  * jobs that never started. Persisted in execution_jobs.init_failure.
114
124
  */
115
- initFailure?: InitFailure) => void;
125
+ initFailure?: InitFailure,
126
+ /** Ordered bound deployment-environment names for this job (multi-env jobs). */
127
+ environments?: string[]) => void;
116
128
  /**
117
129
  * Optional callback to emit run.event messages to Platform.
118
130
  * Fires at orchestrator lifecycle points (dispatch, agent assignment, job start/complete).
@@ -208,6 +220,7 @@ export declare class ExecutionTracker {
208
220
  waveGated?: boolean;
209
221
  waveMaxParallel?: number;
210
222
  waveFailFast?: boolean;
223
+ environments?: string[];
211
224
  }>, routingKey?: string,
212
225
  /** Secret context names dispatched with jobs (for context-disable job lookup). */
213
226
  dispatchedContexts?: string[],
@@ -229,7 +242,13 @@ export declare class ExecutionTracker {
229
242
  /** Workflow-level wall-clock timeout in ms from the lock file. Sets the run deadline. */
230
243
  workflowTimeoutMs?: number,
231
244
  /** Run mode for idempotent steps; non-apply labels the run a check-mode preview. */
232
- checkMode?: string): Promise<void>;
245
+ checkMode?: string,
246
+ /** True when the run executes an uploaded local working tree (`kici run remote`). */
247
+ localWorkingTree?: boolean,
248
+ /** Provider login of the triggering actor (pusher / PR author). */
249
+ triggerActorUsername?: string | null,
250
+ /** Immutable provider user id of the triggering actor. */
251
+ triggerActorUserId?: string | null): Promise<void>;
233
252
  /**
234
253
  * Add additional jobs to an already-started execution run.
235
254
  * Used when build jobs are tracked early and regular jobs are dispatched later.
@@ -283,6 +302,7 @@ export declare class ExecutionTracker {
283
302
  baseJobName?: string;
284
303
  variantKind?: string;
285
304
  variantLabel?: string;
305
+ environments?: string[];
286
306
  }>, dispatchedContexts?: string[],
287
307
  /** Synthetic job ID to replace (e.g. needs-pending-deploy-{uuid}). */
288
308
  replaceSyntheticId?: string): Promise<void>;
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Shared run-detail aggregator.
3
+ *
4
+ * One source of truth for "DB rows → canonical nested run detail (jobs with
5
+ * nested steps + needs + outputs)". The dashboard handler and the agent-facing
6
+ * structured run-result route both build on the same `buildRunDetailJobs` /
7
+ * `mapRunDetailStep` mapping, so the row→jobs shape never diverges between the
8
+ * two read surfaces.
9
+ *
10
+ * `aggregateRunDetail` is the warm-path convenience used by the agent route: it
11
+ * runs the run-header + per-run batch queries and returns the canonical detail.
12
+ * (Cold-store fallback stays a dashboard-handler concern — the agent read path
13
+ * is warm-only in v1.)
14
+ */
15
+ import type { Kysely } from 'kysely';
16
+ import type { ExecutionJobStatus, InitFailure } from '@kici-dev/engine';
17
+ import type { Database } from '../db/types.js';
18
+ /** A run-detail step row as queried from execution_steps (warm + cold paths). */
19
+ export interface RunDetailStepRow {
20
+ step_index: number;
21
+ step_name: string;
22
+ status: string;
23
+ started_at: Date | null;
24
+ completed_at: Date | null;
25
+ duration_ms: number | null;
26
+ exit_code: number | null;
27
+ error_message: string | null;
28
+ step_type: string;
29
+ secrets_accessed: string | null;
30
+ check_outcome: string | null;
31
+ drift_summary: string | null;
32
+ concurrency_kind: string | null;
33
+ group_id: string | null;
34
+ }
35
+ /** Map a step row to the dashboard run-detail step shape (epoch-ms timestamps). */
36
+ export declare function mapRunDetailStep(step: RunDetailStepRow): {
37
+ groupId?: string | undefined;
38
+ concurrencyKind?: string | undefined;
39
+ driftSummary?: string | undefined;
40
+ checkOutcome?: string | undefined;
41
+ secretsAccessed: string | null;
42
+ stepType?: string | undefined;
43
+ stepIndex: number;
44
+ stepName: string;
45
+ status: string;
46
+ startedAt: number | null;
47
+ completedAt: number | null;
48
+ durationMs: number | null;
49
+ exitCode: number | null;
50
+ errorMessage: string | null;
51
+ };
52
+ /** A run-detail job row as queried from execution_jobs (warm + cold paths). */
53
+ export interface RunDetailJobRow {
54
+ job_id: string;
55
+ job_name: string;
56
+ status: string;
57
+ matrix_values: unknown;
58
+ base_job_name: string | null;
59
+ variant_kind: string | null;
60
+ variant_label: string | null;
61
+ started_at: Date | null;
62
+ completed_at: Date | null;
63
+ duration_ms: number | null;
64
+ agent_id: string | null;
65
+ error_message: string | null;
66
+ runs_on_labels: unknown;
67
+ environments: unknown;
68
+ outputs: unknown;
69
+ init_failure: unknown;
70
+ }
71
+ /** Lookups threaded into {@link buildRunDetailJobs} from the per-run batch queries. */
72
+ export interface RunDetailJobLookups {
73
+ stepsByJob: Map<string, RunDetailStepRow[]>;
74
+ secretKeysByJob: Map<string, string[]>;
75
+ needsByJob: Map<string, Array<{
76
+ upstreamName: string;
77
+ runOn: ExecutionJobStatus[];
78
+ }>>;
79
+ }
80
+ /** Map queried job + step rows into the dashboard run-detail job DTO shape. */
81
+ export declare function buildRunDetailJobs(jobs: RunDetailJobRow[], lookups: RunDetailJobLookups): {
82
+ needs: {
83
+ upstreamName: string;
84
+ runOn: ExecutionJobStatus[];
85
+ }[] | null;
86
+ steps: {
87
+ groupId?: string | undefined;
88
+ concurrencyKind?: string | undefined;
89
+ driftSummary?: string | undefined;
90
+ checkOutcome?: string | undefined;
91
+ secretsAccessed: string | null;
92
+ stepType?: string | undefined;
93
+ stepIndex: number;
94
+ stepName: string;
95
+ status: string;
96
+ startedAt: number | null;
97
+ completedAt: number | null;
98
+ durationMs: number | null;
99
+ exitCode: number | null;
100
+ errorMessage: string | null;
101
+ }[];
102
+ initFailure?: {
103
+ scope: "run" | "job";
104
+ category: "secret_resolution" | "install_secrets" | "lock_resolution" | "build_coordination" | "environment_rules" | "dynamic_eval" | "no_agent" | "matrix_expansion";
105
+ message: string;
106
+ jobName?: string | undefined;
107
+ } | undefined;
108
+ jobId: string;
109
+ jobName: string;
110
+ status: string;
111
+ matrixValues: Record<string, unknown> | null;
112
+ baseJobName: string | null;
113
+ variantKind: string | null;
114
+ variantLabel: string | null;
115
+ startedAt: number | null;
116
+ completedAt: number | null;
117
+ durationMs: number | null;
118
+ agentId: string | null;
119
+ orchestratorId: null;
120
+ errorMessage: string | null;
121
+ runsOnLabels: string[] | null;
122
+ environments: string[] | null;
123
+ outputs: any;
124
+ secretOutputKeys: string[] | null;
125
+ }[];
126
+ /** A dashboard-shaped run-detail job (epoch-ms timestamps). */
127
+ export type CanonicalRunDetailJob = ReturnType<typeof buildRunDetailJobs>[number];
128
+ /**
129
+ * Canonical run detail: the run header (raw `Date` timestamps) plus the
130
+ * dashboard-shaped nested jobs. The agent mapper formats timestamps to ISO and
131
+ * wraps untrusted fields; the dashboard handler consumes `buildRunDetailJobs`
132
+ * directly.
133
+ */
134
+ export interface CanonicalRunDetail {
135
+ runId: string;
136
+ workflowName: string;
137
+ status: string;
138
+ provider: string;
139
+ repoIdentifier: string;
140
+ ref: string;
141
+ sha: string;
142
+ /** Best-effort base commit from provider context; null when unavailable. */
143
+ baseSha: string | null;
144
+ startedAt: Date | null;
145
+ completedAt: Date | null;
146
+ durationMs: number | null;
147
+ trustTier: string | null;
148
+ contributorUsername: string | null;
149
+ triggeredBy: string | null;
150
+ failureReason: string | null;
151
+ /** Run-scoped init failure (the run never executed a step). */
152
+ initFailure: InitFailure | null;
153
+ routingKey: string | null;
154
+ jobs: CanonicalRunDetailJob[];
155
+ }
156
+ /**
157
+ * Aggregate a run into the canonical nested detail (warm path). Returns null
158
+ * when the run row is absent in PostgreSQL.
159
+ */
160
+ export declare function aggregateRunDetail(db: Kysely<Database>, runId: string): Promise<CanonicalRunDetail | null>;
161
+ //# sourceMappingURL=run-aggregator.d.ts.map
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Shared step-log reader for the agent-facing step-logs endpoint.
3
+ *
4
+ * Resolves a step's stored log file via the same `execution_steps.log_path` +
5
+ * `LogStorage` access the dashboard step.logs path uses, then returns the lines
6
+ * with line-based cursor pagination. `toAgentStepLogs` wraps every line in an
7
+ * untrusted envelope (log content is process/user output — never trusted).
8
+ */
9
+ import type { Kysely } from 'kysely';
10
+ import { type AgentStepLogs } from '@kici-dev/engine';
11
+ import type { Database } from '../db/types.js';
12
+ import type { LogStorage } from './log-storage.js';
13
+ export interface StepLogReaderDeps {
14
+ db: Kysely<Database>;
15
+ logStorage: LogStorage;
16
+ }
17
+ export interface RawStepLogs {
18
+ lines: string[];
19
+ totalLines: number;
20
+ nextCursor: string | null;
21
+ }
22
+ export interface ReadStepLogArgs {
23
+ runId: string;
24
+ jobId: string;
25
+ stepIndex: number;
26
+ /** Stringified line offset to start from (0-based). Default 0. */
27
+ cursor?: string;
28
+ /** Max number of lines to return. Default 500, hard cap applied by caller. */
29
+ limit?: number;
30
+ }
31
+ /**
32
+ * Read a page of a step's log lines. Returns an empty page (not an error) when
33
+ * the step row or its log file is absent, so a never-emitted-logs step reads as
34
+ * `{ lines: [], totalLines: 0, nextCursor: null }`.
35
+ */
36
+ export declare function readStepLogLines(deps: StepLogReaderDeps, args: ReadStepLogArgs): Promise<RawStepLogs>;
37
+ /** Wrap raw step logs into the untrusted-tagged `AgentStepLogs` shape. */
38
+ export declare function toAgentStepLogs(runId: string, jobId: string, stepIndex: number, raw: RawStepLogs): AgentStepLogs;
39
+ //# sourceMappingURL=step-log-reader.d.ts.map
@@ -10,6 +10,7 @@ import type { RegistrationStore } from '../registration/registration-store.js';
10
10
  import type { RegistrationIndex } from '../registration/registration-index.js';
11
11
  import type { TokenManager } from '../secrets/token-manager.js';
12
12
  import type { RbacEnforcer, Role } from '../secrets/rbac.js';
13
+ import type { EnvironmentStore } from '../environments/environment-store.js';
13
14
  /**
14
15
  * Dependencies for admin registration routes.
15
16
  */
@@ -18,6 +19,13 @@ export interface AdminRegistrationRoutesDeps {
18
19
  registrationIndex: RegistrationIndex;
19
20
  tokenManager: TokenManager;
20
21
  rbac: RbacEnforcer;
22
+ /**
23
+ * Resolves a bound environment by name for registration-time satisfiability.
24
+ * When present, a manual registration is rejected up front if a job binds a
25
+ * provably-unsatisfiable environment list (missing/disabled env, or
26
+ * mutually-exclusive fixed branch/trigger/repo restrictions).
27
+ */
28
+ environmentStore?: Pick<EnvironmentStore, 'matchEnvironment'>;
21
29
  }
22
30
  /** Hono env type for admin registration routes with context variables. */
23
31
  type AdminRegEnv = {
@@ -24,6 +24,7 @@ import type { Database } from '../db/types.js';
24
24
  import type { TokenManager } from '../secrets/token-manager.js';
25
25
  import type { RbacEnforcer, Role } from '../secrets/rbac.js';
26
26
  import type { AuditLogger } from '../secrets/audit-logger.js';
27
+ import type { LogStorage } from '../reporting/log-storage.js';
27
28
  /**
28
29
  * Dependencies for admin run routes.
29
30
  */
@@ -38,6 +39,12 @@ export interface AdminRunRoutesDeps {
38
39
  * secret-output plaintext. Derived once per request via deriveKey().
39
40
  */
40
41
  masterSecretKey?: string;
42
+ /**
43
+ * Log storage backend. Required only by the agent step-logs endpoint
44
+ * (`/runs/:runId/jobs/:jobId/steps/:stepIndex/logs`); when absent, that
45
+ * path 503s cleanly.
46
+ */
47
+ logStorage?: LogStorage;
41
48
  }
42
49
  /** Hono env type for admin run routes with context variables. */
43
50
  type AdminRunEnv = {
@@ -7,7 +7,7 @@
7
7
  export { PgSecretStore } from './pg-secret-store.js';
8
8
  export { AuditLogger } from './audit-logger.js';
9
9
  export { loadMasterKey, loadOldMasterKey, loadSecretStoreConfig, type SecretStoreConfig, } from './config.js';
10
- export { encrypt, decrypt, deriveKey, generateMasterKey, type EncryptedValue } from './crypto.js';
10
+ export { encrypt, decrypt, deriveKey, generateMasterKey, type EncryptedValue, } from '@kici-dev/shared';
11
11
  export { VaultSecretStore, type VaultConfig } from './vault-secret-store.js';
12
12
  export { SecretResolver, type SecretResolverDeps, type ResolvedSecretMeta, type EnvironmentStoreLike, type BindingStoreLike, type SecretStoreLike, } from './secret-resolver.js';
13
13
  export { BackendSyncManager } from './backend-sync.js';