@kici-dev/orchestrator 0.1.23 → 0.1.25

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 (86) hide show
  1. package/dist/agent/token-store.d.ts +4 -0
  2. package/dist/app.d.ts +27 -0
  3. package/dist/audit/access-log.d.ts +4 -0
  4. package/dist/cache/pending-inits.d.ts +3 -2
  5. package/dist/cancel/cancel-run.d.ts +2 -0
  6. package/dist/cli/api-client.d.ts +10 -0
  7. package/dist/cli/commands/attestations-list.d.ts +49 -0
  8. package/dist/cli/commands/attestations-retry.d.ts +28 -0
  9. package/dist/cli/commands/attestations-reverify.d.ts +18 -0
  10. package/dist/cli/commands/attestations.d.ts +4 -0
  11. package/dist/cli/commands/cluster.d.ts +3 -0
  12. package/dist/cli/commands/shared/versioned-upgrade.d.ts +52 -0
  13. package/dist/cli/local-github-ingress-url.d.ts +8 -0
  14. package/dist/cli.js +3308 -1011
  15. package/dist/cluster/cluster-identity.d.ts +11 -0
  16. package/dist/cluster/reconcile-identity.d.ts +50 -0
  17. package/dist/cold-store/load-access-log-range.d.ts +4 -0
  18. package/dist/config.d.ts +4 -0
  19. package/dist/dashboard/attestation-filters.d.ts +131 -0
  20. package/dist/dashboard/handler.d.ts +56 -4
  21. package/dist/db/migrations/054_local_working_tree.d.ts +15 -0
  22. package/dist/db/migrations/055_agent_token_mandatory_labels.d.ts +18 -0
  23. package/dist/db/migrations/056_execution_jobs_environments.d.ts +17 -0
  24. package/dist/db/migrations/057_step_concurrency.d.ts +4 -0
  25. package/dist/db/migrations/058_access_log_agent_label.d.ts +4 -0
  26. package/dist/db/migrations/059_attestation_verdict.d.ts +4 -0
  27. package/dist/db/migrations/060_run_trigger_actor.d.ts +4 -0
  28. package/dist/db/migrations/061_execution_runs_environment_id.d.ts +4 -0
  29. package/dist/db/migrations/062_execution_runs_agent_label.d.ts +4 -0
  30. package/dist/db/migrations/063_access_log_agent_label_index.d.ts +10 -0
  31. package/dist/db/migrations/064_execution_jobs_skipped_environments.d.ts +17 -0
  32. package/dist/db/migrations/065_pending_attestations.d.ts +22 -0
  33. package/dist/db/migrations/066_pending_attestations_rejected.d.ts +13 -0
  34. package/dist/db/types.d.ts +113 -0
  35. package/dist/environments/protection/aggregate.d.ts +43 -0
  36. package/dist/environments/protection/satisfiability.d.ts +69 -0
  37. package/dist/events/circuit-breaker.d.ts +8 -5
  38. package/dist/events/event-router.d.ts +12 -4
  39. package/dist/events/event-store.d.ts +21 -3
  40. package/dist/events/trust-store.d.ts +6 -1
  41. package/dist/events/types.d.ts +6 -1
  42. package/dist/helpers/rate-limiter.d.ts +17 -2
  43. package/dist/index.js +11 -1
  44. package/dist/metrics/prometheus.d.ts +6 -0
  45. package/dist/orchestrator-core.d.ts +8 -0
  46. package/dist/pipeline/dispatch-matched-workflow.d.ts +8 -0
  47. package/dist/pipeline/flatten-lock-steps.d.ts +11 -0
  48. package/dist/pipeline/inline-eval.d.ts +2 -1
  49. package/dist/pipeline/job-environments.d.ts +71 -0
  50. package/dist/pipeline/manual-schedule.d.ts +23 -1
  51. package/dist/pipeline/process-webhook.d.ts +14 -1
  52. package/dist/pipeline/rerun.d.ts +1 -1
  53. package/dist/pipeline/test-pipeline.d.ts +15 -0
  54. package/dist/provenance/attestation-retrier.d.ts +92 -0
  55. package/dist/provenance/backfill-run.d.ts +41 -0
  56. package/dist/provenance/pending-attestations-repo.d.ts +64 -0
  57. package/dist/provenance/trust-root.d.ts +24 -0
  58. package/dist/provenance/verify-at-ingest.d.ts +31 -0
  59. package/dist/reporting/agent-failure-category.d.ts +27 -0
  60. package/dist/reporting/agent-run-result-mapper.d.ts +13 -0
  61. package/dist/reporting/execution-tracker.d.ts +38 -6
  62. package/dist/reporting/run-aggregator.d.ts +165 -0
  63. package/dist/reporting/step-log-reader.d.ts +39 -0
  64. package/dist/routes/admin-access-log.d.ts +2 -1
  65. package/dist/routes/admin-registrations.d.ts +8 -0
  66. package/dist/routes/admin-runs.d.ts +7 -0
  67. package/dist/routes/admin.d.ts +14 -0
  68. package/dist/routes/github-webhook.d.ts +37 -0
  69. package/dist/routes/health.d.ts +9 -0
  70. package/dist/routes/webhooks.d.ts +2 -4
  71. package/dist/secrets/index.d.ts +1 -1
  72. package/dist/server.js +5326 -2100
  73. package/dist/sources/source-store.d.ts +6 -0
  74. package/dist/stale-detector/workflow-deadline-detector.d.ts +25 -0
  75. package/dist/standalone.js +19787 -17304
  76. package/dist/storage/loopback-guard.d.ts +49 -0
  77. package/dist/webhook/dedup.d.ts +14 -0
  78. package/dist/ws/agent-handler.d.ts +38 -1
  79. package/dist/ws/oidc-token-relay.d.ts +31 -21
  80. package/dist/ws/orch-rpc.d.ts +9 -0
  81. package/dist/ws/platform-client.d.ts +53 -1
  82. package/dist/ws/test-relay-handlers.d.ts +2 -0
  83. package/installer-image-digests.json +3 -3
  84. package/package.json +6 -8
  85. package/sbom.spdx.json +62 -57
  86. package/dist/secrets/crypto.d.ts +0 -49
@@ -29,6 +29,17 @@ export interface ClusterIdentityDeps {
29
29
  */
30
30
  skipSentinelValidation?: boolean;
31
31
  }
32
+ /**
33
+ * Default cache-storage S3 prefix (mirrors the orchestrator config
34
+ * `cacheStorageS3Prefix` default). Empty means the cache blobs and the
35
+ * cluster-identity sentinel live at the bucket root — the bucket already scopes
36
+ * the cluster. Every place that resolves a sentinel prefix (the orchestrator
37
+ * runtime, the `kici-admin cluster reconcile-identity` CLI, and the staging
38
+ * deploy's self-heal step) MUST fall back to THIS value when no explicit prefix
39
+ * is set, otherwise they compute divergent sentinel keys and crash-loop the
40
+ * orchestrator boot on a spurious "Cluster identity mismatch".
41
+ */
42
+ export declare const DEFAULT_CACHE_STORAGE_S3_PREFIX = "";
32
43
  /**
33
44
  * Build the S3 key for the cluster identity sentinel under an optional prefix.
34
45
  * Strips any trailing slash from the prefix so callers can pass either form.
@@ -0,0 +1,50 @@
1
+ import type { IdempotentStep } from '@kici-dev/shared/idempotency';
2
+ export type ReconcileDirection = 'db-from-sentinel' | 'sentinel-from-db';
3
+ export interface ReconcileS3Config {
4
+ bucket: string;
5
+ /**
6
+ * Optional storage prefix (mirrors `KICI_STORAGE_PREFIX`). The sentinel lives
7
+ * at `<prefix>/.kici-cluster-id`; must match the prefix the orchestrator boots
8
+ * with. When omitted, `clusterSentinelKey` resolves the bucket root — the same
9
+ * as the orchestrator's `DEFAULT_CACHE_STORAGE_S3_PREFIX` (empty) default.
10
+ */
11
+ prefix?: string;
12
+ region?: string;
13
+ endpoint?: string;
14
+ forcePathStyle?: boolean;
15
+ accessKeyId: string;
16
+ secretAccessKey: string;
17
+ }
18
+ export interface IdentityDrift {
19
+ dbClusterId: string | null;
20
+ sentinelClusterId: string | null;
21
+ direction: ReconcileDirection;
22
+ }
23
+ declare function readClusterIdFromDb(databaseUrl: string): Promise<string | null>;
24
+ declare function writeClusterIdToDb(databaseUrl: string, clusterId: string): Promise<void>;
25
+ declare function readSentinel(s3: ReconcileS3Config): Promise<string | null>;
26
+ declare function writeSentinel(s3: ReconcileS3Config, clusterId: string): Promise<void>;
27
+ /**
28
+ * Indirection object for the DB + S3 reads/writes, so the unit test can stub
29
+ * the I/O without an ESM partial-mock dance. `buildReconcileStep` calls every
30
+ * reader/writer through this object; the test overrides its members directly.
31
+ */
32
+ export declare const reconcileIo: {
33
+ readClusterIdFromDb: typeof readClusterIdFromDb;
34
+ writeClusterIdToDb: typeof writeClusterIdToDb;
35
+ readSentinel: typeof readSentinel;
36
+ writeSentinel: typeof writeSentinel;
37
+ };
38
+ /**
39
+ * Build the idempotent step that reconciles the cluster identity in the given
40
+ * direction. `check()` returns drift when the two sides disagree (or null when
41
+ * in sync); `apply()` performs the single write that brings them into
42
+ * agreement. Run it through `runIdempotentStep` (`@kici-dev/core/idempotency`).
43
+ */
44
+ export declare function buildReconcileStep(deps: {
45
+ databaseUrl: string;
46
+ s3: ReconcileS3Config;
47
+ direction: ReconcileDirection;
48
+ }): IdempotentStep<IdentityDrift>;
49
+ export {};
50
+ //# sourceMappingURL=reconcile-identity.d.ts.map
@@ -52,6 +52,10 @@ export interface LoadAccessLogRangeArgs {
52
52
  * `009_access_log_trigram.ts`. Min ~3 chars for the index to help.
53
53
  */
54
54
  q?: string;
55
+ /** Exact-match filter on the agent provenance label (`agent_label` column). */
56
+ agentLabel?: string;
57
+ /** When true, return only agent-attributed rows (`agent_label IS NOT NULL`). */
58
+ agentOnly?: boolean;
55
59
  };
56
60
  limit: number;
57
61
  cursor?: string;
package/dist/config.d.ts CHANGED
@@ -27,6 +27,7 @@ declare const configSchema: z.ZodObject<{
27
27
  platformUrl: z.ZodOptional<z.ZodString>;
28
28
  platformToken: z.ZodOptional<z.ZodString>;
29
29
  dashboardUrl: z.ZodOptional<z.ZodString>;
30
+ provenanceIssuer: z.ZodOptional<z.ZodString>;
30
31
  webhookPublicUrl: z.ZodOptional<z.ZodString>;
31
32
  databaseUrl: z.ZodDefault<z.ZodString>;
32
33
  lockfileCacheMax: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
@@ -99,6 +100,7 @@ declare const configSchema: z.ZodObject<{
99
100
  eventRouterRetryScanIntervalMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
100
101
  testMode: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<boolean, string>>;
101
102
  testEventFailFirstN: z.ZodOptional<z.ZodString>;
103
+ testMintDeferAudience: z.ZodOptional<z.ZodString>;
102
104
  eventLogMaxPayloadBytes: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
103
105
  logLevel: z.ZodDefault<z.ZodEnum<{
104
106
  error: "error";
@@ -248,6 +250,7 @@ export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
248
250
  platformUrl?: string | undefined;
249
251
  platformToken?: string | undefined;
250
252
  dashboardUrl?: string | undefined;
253
+ provenanceIssuer?: string | undefined;
251
254
  webhookPublicUrl?: string | undefined;
252
255
  cacheStorageType?: "s3" | "filesystem" | undefined;
253
256
  cacheStoragePath?: string | undefined;
@@ -272,6 +275,7 @@ export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
272
275
  bootstrapAdminToken?: string | undefined;
273
276
  orchestratorHostAgentId?: string | undefined;
274
277
  testEventFailFirstN?: string | undefined;
278
+ testMintDeferAudience?: string | undefined;
275
279
  otelExporterOtlpEndpoint?: string | undefined;
276
280
  clusterName?: string | undefined;
277
281
  }>;
@@ -0,0 +1,131 @@
1
+ import { type Kysely } from 'kysely';
2
+ import type { AttestationListFilters } from '@kici-dev/engine';
3
+ import type { Database } from '../db/types.js';
4
+ /**
5
+ * The org-wide attestations base query: joins `attestations` to `execution_jobs`
6
+ * (for the job name) and `execution_runs` (for repository / workflow context).
7
+ *
8
+ * `attestations.run_id` / `job_id` are TEXT (P1.5 schema) while the
9
+ * `execution_*` keys are `uuid`; Postgres won't compare `uuid = text` implicitly,
10
+ * so the join casts the uuid side to text — mirroring `resolveAttestationsForRun`.
11
+ * The `execution_runs` join is a LEFT join so a row with no matching run still
12
+ * lists (repository / workflow come back null).
13
+ */
14
+ export declare function baseAttestationsQuery(db: Kysely<Database>): import("kysely").SelectQueryBuilder<{
15
+ cluster_meta: import("../db/types.js").ClusterMetaTable;
16
+ environments: import("../db/types.js").EnvironmentsTable;
17
+ host_roster: import("../db/types.js").HostRosterTable;
18
+ dispatch_queue: import("../db/types.js").DispatchQueueTable;
19
+ dedup_cache: import("../db/types.js").DedupCacheTable;
20
+ ip_allocations: import("../db/types.js").IpAllocationTable;
21
+ execution_runs: import("kysely").Nullable<import("../db/types.js").ExecutionRunTable>;
22
+ execution_jobs: import("../db/types.js").ExecutionJobTable;
23
+ execution_steps: import("../db/types.js").ExecutionStepTable;
24
+ raft_state: import("../db/types.js").RaftStateTable;
25
+ secret_audit_log: import("../db/types.js").SecretAuditLogTable;
26
+ scoped_secrets: import("../db/types.js").ScopedSecretsTable;
27
+ environment_bindings: import("../db/types.js").EnvironmentBindingsTable;
28
+ environment_variables: import("../db/types.js").EnvironmentVariablesTable;
29
+ environment_source_overrides: import("../db/types.js").EnvironmentSourceOverridesTable;
30
+ held_runs: import("../db/types.js").HeldRunsTable;
31
+ held_run_approvals: import("../db/types.js").HeldRunApprovalsTable;
32
+ admin_tokens: import("../db/types.js").AdminTokenTable;
33
+ agent_tokens: import("../db/types.js").AgentTokenTable;
34
+ config_versions: import("../db/types.js").ConfigVersionTable;
35
+ kici_events: import("../db/types.js").KiciEventTable;
36
+ generic_webhook_sources: import("../db/types.js").GenericWebhookSourceTable;
37
+ cross_repo_trust: import("../db/types.js").CrossRepoTrustTable;
38
+ test_uploads: import("../db/types.js").TestUploadsTable;
39
+ workflow_registrations: import("../db/types.js").WorkflowRegistrationsTable;
40
+ registry_versions: import("../db/types.js").RegistryVersionsTable;
41
+ cron_last_fired: import("../db/types.js").CronLastFiredTable;
42
+ run_ephemeral_keys: import("../db/types.js").RunEphemeralKeysTable;
43
+ run_secret_outputs: import("../db/types.js").RunSecretOutputsTable;
44
+ concurrency_groups: import("../db/types.js").ConcurrencyGroupsTable;
45
+ sources: import("../db/types.js").SourcesTable;
46
+ join_tokens: import("../db/types.js").JoinTokenTable;
47
+ org_settings: import("../db/types.js").OrgSettingsTable;
48
+ execution_job_needs: import("../db/types.js").ExecutionJobNeedsTable;
49
+ pending_job_contexts: import("../db/types.js").PendingJobContextsTable;
50
+ pending_workflow_contexts: import("../db/types.js").PendingWorkflowContextsTable;
51
+ event_log: import("../db/types.js").EventLogTable;
52
+ access_log: import("../db/types.js").AccessLogTable;
53
+ cold_store_chunk_counts: import("../db/types.js").ColdStoreChunkCountsTable;
54
+ cold_store_chunks: import("../db/types.js").ColdStoreChunksTable;
55
+ check_run_tracking: import("../db/types.js").CheckRunTrackingTable;
56
+ scaler_spawning_agents: import("../db/types.js").ScalerSpawningAgentsTable;
57
+ scaler_agent_jobs: import("../db/types.js").ScalerAgentJobsTable;
58
+ scaler_reservations: import("../db/types.js").ScalerReservationsTable;
59
+ attestations: import("../db/types.js").AttestationsTable;
60
+ pending_attestations: import("../db/types.js").PendingAttestationsTable;
61
+ remote_sources: import("../db/types.js").RemoteSourcesTable;
62
+ }, "execution_runs" | "execution_jobs" | "attestations", {}>;
63
+ export type AttestationsBaseQuery = ReturnType<typeof baseAttestationsQuery>;
64
+ /**
65
+ * Base query for the deferred-attestation outbox (`pending_attestations`),
66
+ * joined to `execution_jobs` (job name) and `execution_runs` (repo / workflow
67
+ * context) for the org-wide list's pending summaries.
68
+ *
69
+ * Same uuid/text mismatch as `baseAttestationsQuery`: `pending_attestations`
70
+ * `run_id` / `job_id` are TEXT while the `execution_*` keys are `uuid`, and
71
+ * Postgres won't compare `uuid = text` implicitly — so the joins cast the uuid
72
+ * side to text. Both joins are LEFT joins so a pending row with no matching
73
+ * run / job still lists (repository / workflow / job name come back null).
74
+ */
75
+ export declare function basePendingAttestationsQuery(db: Kysely<Database>): import("kysely").SelectQueryBuilder<{
76
+ cluster_meta: import("../db/types.js").ClusterMetaTable;
77
+ environments: import("../db/types.js").EnvironmentsTable;
78
+ host_roster: import("../db/types.js").HostRosterTable;
79
+ dispatch_queue: import("../db/types.js").DispatchQueueTable;
80
+ dedup_cache: import("../db/types.js").DedupCacheTable;
81
+ ip_allocations: import("../db/types.js").IpAllocationTable;
82
+ execution_runs: import("kysely").Nullable<import("../db/types.js").ExecutionRunTable>;
83
+ execution_jobs: import("kysely").Nullable<import("../db/types.js").ExecutionJobTable>;
84
+ execution_steps: import("../db/types.js").ExecutionStepTable;
85
+ raft_state: import("../db/types.js").RaftStateTable;
86
+ secret_audit_log: import("../db/types.js").SecretAuditLogTable;
87
+ scoped_secrets: import("../db/types.js").ScopedSecretsTable;
88
+ environment_bindings: import("../db/types.js").EnvironmentBindingsTable;
89
+ environment_variables: import("../db/types.js").EnvironmentVariablesTable;
90
+ environment_source_overrides: import("../db/types.js").EnvironmentSourceOverridesTable;
91
+ held_runs: import("../db/types.js").HeldRunsTable;
92
+ held_run_approvals: import("../db/types.js").HeldRunApprovalsTable;
93
+ admin_tokens: import("../db/types.js").AdminTokenTable;
94
+ agent_tokens: import("../db/types.js").AgentTokenTable;
95
+ config_versions: import("../db/types.js").ConfigVersionTable;
96
+ kici_events: import("../db/types.js").KiciEventTable;
97
+ generic_webhook_sources: import("../db/types.js").GenericWebhookSourceTable;
98
+ cross_repo_trust: import("../db/types.js").CrossRepoTrustTable;
99
+ test_uploads: import("../db/types.js").TestUploadsTable;
100
+ workflow_registrations: import("../db/types.js").WorkflowRegistrationsTable;
101
+ registry_versions: import("../db/types.js").RegistryVersionsTable;
102
+ cron_last_fired: import("../db/types.js").CronLastFiredTable;
103
+ run_ephemeral_keys: import("../db/types.js").RunEphemeralKeysTable;
104
+ run_secret_outputs: import("../db/types.js").RunSecretOutputsTable;
105
+ concurrency_groups: import("../db/types.js").ConcurrencyGroupsTable;
106
+ sources: import("../db/types.js").SourcesTable;
107
+ join_tokens: import("../db/types.js").JoinTokenTable;
108
+ org_settings: import("../db/types.js").OrgSettingsTable;
109
+ execution_job_needs: import("../db/types.js").ExecutionJobNeedsTable;
110
+ pending_job_contexts: import("../db/types.js").PendingJobContextsTable;
111
+ pending_workflow_contexts: import("../db/types.js").PendingWorkflowContextsTable;
112
+ event_log: import("../db/types.js").EventLogTable;
113
+ access_log: import("../db/types.js").AccessLogTable;
114
+ cold_store_chunk_counts: import("../db/types.js").ColdStoreChunkCountsTable;
115
+ cold_store_chunks: import("../db/types.js").ColdStoreChunksTable;
116
+ check_run_tracking: import("../db/types.js").CheckRunTrackingTable;
117
+ scaler_spawning_agents: import("../db/types.js").ScalerSpawningAgentsTable;
118
+ scaler_agent_jobs: import("../db/types.js").ScalerAgentJobsTable;
119
+ scaler_reservations: import("../db/types.js").ScalerReservationsTable;
120
+ attestations: import("../db/types.js").AttestationsTable;
121
+ pending_attestations: import("../db/types.js").PendingAttestationsTable;
122
+ remote_sources: import("../db/types.js").RemoteSourcesTable;
123
+ }, "execution_runs" | "execution_jobs" | "pending_attestations", {}>;
124
+ /**
125
+ * Apply org-wide attestation filters to the base query. Digest is exact-match;
126
+ * name is an ILIKE substring; status / repository / workflow / job are equality;
127
+ * created_at gets `>=` / `<=` bounds for the date range. Absent filters are
128
+ * skipped.
129
+ */
130
+ export declare function applyAttestationFilters(qb: AttestationsBaseQuery, filters: AttestationListFilters): AttestationsBaseQuery;
131
+ //# sourceMappingURL=attestation-filters.d.ts.map
@@ -13,7 +13,7 @@
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, DashboardAttestationsListRequest, 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, DashboardAttestationsListAllRequest, DashboardAttestationGetRequest, DashboardAttestationRetryRequest, DashboardPayloadRequest, DashboardOrchLogsRequest, DashboardEventLogListRequest, DashboardEventLogDetailRequest, DashboardEventLogPayloadStreamRequest, DashboardAccessLogListRequest, DashboardEventDlqListRequest, DashboardEventDlqCountRequest, DashboardEventDlqRetryRequest, DashboardEventDlqDiscardRequest, RunRerunRequest, RunCancelRequest, ManualScheduleRequest, DashboardRunStructuredRequest } from '@kici-dev/engine';
17
17
  import type { Database } from '../db/types.js';
18
18
  import type { LogStorage } from '../reporting/log-storage.js';
19
19
  import type { CacheStorage } from '../storage/types.js';
@@ -31,6 +31,17 @@ interface DashboardHandlerDeps {
31
31
  * (the same one P1.5 writes bundles to).
32
32
  */
33
33
  provenanceStorage?: CacheStorage | null;
34
+ /**
35
+ * Drain the deferred-attestation outbox on demand (mints in this process,
36
+ * which owns the Platform WS). Backs `dashboard.attestation.retry`. Optional —
37
+ * absent on orchestrators without the retrier wired.
38
+ */
39
+ retryAttestations?: (opts: {
40
+ runId?: string;
41
+ }) => Promise<{
42
+ minted: number;
43
+ stillPending: number;
44
+ }>;
34
45
  /** Send a response message back to Platform over the WS connection. */
35
46
  send: (msg: unknown) => void;
36
47
  /** This orchestrator's instance ID, included in job detail responses. */
@@ -59,7 +70,7 @@ interface DashboardHandlerDeps {
59
70
  * compat with mixed deploys; absent means the orchestrator falls
60
71
  * back to the legacy "no PG row → throw" path.
61
72
  */
62
- onRerun: (runId: string, triggeredBy: string | null, routingKey?: string) => Promise<{
73
+ onRerun: (runId: string, triggeredBy: string | null, triggeredByAgentLabel: string | null, routingKey?: string) => Promise<{
63
74
  newRunId: string;
64
75
  }>;
65
76
  /**
@@ -67,14 +78,14 @@ interface DashboardHandlerDeps {
67
78
  * Returns { cancelledJobs } on success or throws on failure.
68
79
  * The force flag indicates whether to force-cancel (SIGKILL, skip hooks).
69
80
  */
70
- onCancel: (runId: string, cancelledBy: string | null, force?: boolean) => Promise<{
81
+ onCancel: (runId: string, cancelledBy: string | null, cancelledByAgentLabel: string | null, force?: boolean) => Promise<{
71
82
  cancelledJobs: number;
72
83
  }>;
73
84
  /**
74
85
  * Callback for handling manual schedule trigger requests.
75
86
  * Returns { newRunId } on success or throws on failure.
76
87
  */
77
- onManualSchedule: (registrationId: string, triggeredBy: string | null) => Promise<{
88
+ onManualSchedule: (registrationId: string, triggeredBy: string | null, triggeredByAgentLabel: string | null) => Promise<{
78
89
  newRunId: string;
79
90
  }>;
80
91
  /**
@@ -99,6 +110,7 @@ export declare class DashboardHandler {
99
110
  private readonly onManualSchedule;
100
111
  private readonly coldStore;
101
112
  private readonly eventStore;
113
+ private readonly retryAttestations;
102
114
  constructor(deps: DashboardHandlerDeps);
103
115
  /**
104
116
  * Update the bound orgId + routingKey. Called from server.ts after resolving
@@ -166,6 +178,14 @@ export declare class DashboardHandler {
166
178
  * builds a nested job/step tree, and sends the response.
167
179
  */
168
180
  handleRunDetail(msg: DashboardRunDetailRequest): Promise<void>;
181
+ /**
182
+ * Handle a dashboard.run.structured request — the user-plane equivalent of
183
+ * the orchestrator-admin `/runs/:id/structured` endpoint. Reuses the Phase-1
184
+ * aggregator + provenance mapper so the result is byte-identical to the admin
185
+ * surface; emits an `access_log` `run.structured.read` row (carrying the
186
+ * agent label when the actor came through an agent PAT).
187
+ */
188
+ handleRunStructured(msg: DashboardRunStructuredRequest): Promise<void>;
169
189
  /**
170
190
  * Resolve every routing key owned by an org by unioning both source
171
191
  * tables. The orchestrator is single-org but multi-routing-key: one org
@@ -275,6 +295,38 @@ export declare class DashboardHandler {
275
295
  * skipped (best-effort) rather than failing the whole list.
276
296
  */
277
297
  handleAttestationsList(msg: DashboardAttestationsListRequest): Promise<void>;
298
+ /**
299
+ * Fetch + parse one attestation bundle from object storage. Returns the full
300
+ * detail item, or null when the bundle is missing or not valid JSON (logged).
301
+ * Shared by `handleAttestationsList` (per-run) and `handleAttestationGet`.
302
+ */
303
+ private inlineBundle;
304
+ /**
305
+ * Org-wide attestations query: one page of metadata-only summaries (no bundle
306
+ * fetch) plus the total matching count. Filters/pagination/sort applied via
307
+ * the shared filter builder.
308
+ */
309
+ private resolveAttestationsListAll;
310
+ /** Map the deferred-attestation outbox into pending list summaries (page 1). */
311
+ private resolvePendingAttestationSummaries;
312
+ /**
313
+ * Handle a dashboard.attestations.list.all request: org-wide, paginated,
314
+ * filtered list of attestation summaries (metadata only). Access-logged
315
+ * against the `attestation` target.
316
+ */
317
+ handleAttestationsListAll(msg: DashboardAttestationsListAllRequest): Promise<void>;
318
+ /**
319
+ * Handle a dashboard.attestation.retry request: drain the deferred-attestation
320
+ * outbox (optionally scoped to one run) and reply with the mint counts. The
321
+ * mint happens in this orchestrator process, which owns the Platform WS.
322
+ */
323
+ handleAttestationRetry(msg: DashboardAttestationRetryRequest): Promise<void>;
324
+ /**
325
+ * Handle a dashboard.attestation.get request: a single attestation by id with
326
+ * its bundle inlined for the detail page. Resolves the run-owning org for the
327
+ * access-log row, then logs against the `attestation` target.
328
+ */
329
+ handleAttestationGet(msg: DashboardAttestationGetRequest): Promise<void>;
278
330
  /**
279
331
  * Handle a dashboard.payload request.
280
332
  * Reads the webhook payload from log storage for the given runId.
@@ -0,0 +1,15 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Mark runs that executed an uploaded local working tree (`kici run remote`):
4
+ *
5
+ * - `execution_runs.local_working_tree boolean NOT NULL DEFAULT false` — true
6
+ * for runs that ran a developer's local working tree from the CLI (inline
7
+ * lock file). The dashboard renders a "Local machine" badge for these runs
8
+ * and avoids building an external repository link from the repo identifier.
9
+ *
10
+ * Idempotent (`ADD COLUMN IF NOT EXISTS`); additive with a default, so staging
11
+ * data is preserved.
12
+ */
13
+ export declare function up(db: Kysely<unknown>): Promise<void>;
14
+ export declare function down(db: Kysely<unknown>): Promise<void>;
15
+ //# sourceMappingURL=054_local_working_tree.d.ts.map
@@ -0,0 +1,18 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add a token-bound mandatory-label taint to agent tokens:
4
+ *
5
+ * - `agent_tokens.mandatory_labels text NULL` — a JSON-encoded `string[]` of
6
+ * Kubernetes-taint-style gate labels the token authorizes. When a static
7
+ * agent registers with this token, the set becomes the agent's registry-entry
8
+ * `mandatoryLabels`: the agent only accepts a job when every label here
9
+ * appears in the job's required labels. NULL = no taint (the default; the
10
+ * agent accepts any job its advertised labels match), so every existing token
11
+ * stays unconfined until re-minted.
12
+ *
13
+ * Idempotent (`ADD COLUMN IF NOT EXISTS`); additive, so staging data is
14
+ * preserved.
15
+ */
16
+ export declare function up(db: Kysely<unknown>): Promise<void>;
17
+ export declare function down(db: Kysely<unknown>): Promise<void>;
18
+ //# sourceMappingURL=055_agent_token_mandatory_labels.d.ts.map
@@ -0,0 +1,17 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add a per-job bound deployment-environment list to `execution_jobs`:
4
+ *
5
+ * - `execution_jobs.environments text NULL` — a JSON-encoded `string[]` of the
6
+ * ordered environment names a job binds (`environments: [...]`), in merge
7
+ * order. Written at dispatch with the statically-resolved names (impure
8
+ * dynamic elements as a `(dynamic)` placeholder), then overwritten with the
9
+ * fully-resolved list when a deferred-init agent eval resolves dynamic
10
+ * elements. NULL = the job binds no environment.
11
+ *
12
+ * Idempotent (`ADD COLUMN IF NOT EXISTS`); additive, so staging data is
13
+ * preserved.
14
+ */
15
+ export declare function up(db: Kysely<unknown>): Promise<void>;
16
+ export declare function down(db: Kysely<unknown>): Promise<void>;
17
+ //# sourceMappingURL=056_execution_jobs_environments.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { type Kysely } from 'kysely';
2
+ export declare function up(db: Kysely<unknown>): Promise<void>;
3
+ export declare function down(db: Kysely<unknown>): Promise<void>;
4
+ //# sourceMappingURL=057_step_concurrency.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { type Kysely } from 'kysely';
2
+ export declare function up(db: Kysely<unknown>): Promise<void>;
3
+ export declare function down(db: Kysely<unknown>): Promise<void>;
4
+ //# sourceMappingURL=058_access_log_agent_label.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { type Kysely } from 'kysely';
2
+ export declare function up(db: Kysely<unknown>): Promise<void>;
3
+ export declare function down(db: Kysely<unknown>): Promise<void>;
4
+ //# sourceMappingURL=059_attestation_verdict.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { type Kysely } from 'kysely';
2
+ export declare function up(db: Kysely<unknown>): Promise<void>;
3
+ export declare function down(db: Kysely<unknown>): Promise<void>;
4
+ //# sourceMappingURL=060_run_trigger_actor.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { type Kysely } from 'kysely';
2
+ export declare function up(db: Kysely<unknown>): Promise<void>;
3
+ export declare function down(db: Kysely<unknown>): Promise<void>;
4
+ //# sourceMappingURL=061_execution_runs_environment_id.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { type Kysely } from 'kysely';
2
+ export declare function up(db: Kysely<unknown>): Promise<void>;
3
+ export declare function down(db: Kysely<unknown>): Promise<void>;
4
+ //# sourceMappingURL=062_execution_runs_agent_label.d.ts.map
@@ -0,0 +1,10 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Index `access_log.agent_label` (column added by migration 058) so the
4
+ * operator-facing agent filter (`kici-admin access-log list --agent-label`,
5
+ * the dashboard "agent name" filter) does an indexed exact-match lookup
6
+ * instead of a scan. Idempotent.
7
+ */
8
+ export declare function up(db: Kysely<unknown>): Promise<void>;
9
+ export declare function down(db: Kysely<unknown>): Promise<void>;
10
+ //# sourceMappingURL=063_access_log_agent_label_index.d.ts.map
@@ -0,0 +1,17 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add the test-run skipped-environment columns to `execution_jobs`:
4
+ *
5
+ * - `execution_jobs.skipped_environments text NULL` — a JSON-encoded `string[]`
6
+ * of the bound environment names dropped on a test/local run because they
7
+ * disallow local execution (`allowLocalExecution=false`) or are unconfigured.
8
+ * NULL = nothing skipped.
9
+ * - `execution_jobs.env_warning text NULL` — the user-visible warning naming the
10
+ * skipped environments, surfaced on the dashboard run view. NULL = no warning.
11
+ *
12
+ * Idempotent (`ADD COLUMN IF NOT EXISTS`); additive, so staging data is
13
+ * preserved.
14
+ */
15
+ export declare function up(db: Kysely<unknown>): Promise<void>;
16
+ export declare function down(db: Kysely<unknown>): Promise<void>;
17
+ //# sourceMappingURL=064_execution_jobs_skipped_environments.d.ts.map
@@ -0,0 +1,22 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add the `pending_attestations` deferred-attestation outbox and an idempotency
4
+ * unique index on `attestations`.
5
+ *
6
+ * When a build's provenance mint fails transiently, the agent freezes and
7
+ * DSSE-signs the statement at build time; the orchestrator records the frozen
8
+ * envelope here instead of failing the job. A Raft-leader-only retrier later
9
+ * mints the deferred token, attaches it, uploads the bundle, and records one
10
+ * `attestations` row — deleting the pending row. The unique index on
11
+ * `attestations (run_id, job_id, subject_digest)` makes that fulfilment
12
+ * idempotent across a cluster (ON CONFLICT DO NOTHING).
13
+ *
14
+ * `origin_kind` holds the non-`live` `AttestationOrigin` values
15
+ * (`deferred` / `offline-backfill`); the `created_at` default anchors the true
16
+ * build time so temporal honesty survives a later mint.
17
+ *
18
+ * Idempotent: guarded on table existence.
19
+ */
20
+ export declare function up(db: Kysely<unknown>): Promise<void>;
21
+ export declare function down(db: Kysely<unknown>): Promise<void>;
22
+ //# sourceMappingURL=065_pending_attestations.d.ts.map
@@ -0,0 +1,13 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add `rejected_at` to `pending_attestations`: the terminal-rejection marker for
4
+ * a deferred attestation the Platform definitively cannot mint (run/job absent).
5
+ * NULL while the row is still pending a later mint; set once, the row is skipped
6
+ * by the retrier and drops out of the pending-attestations gauge. Re-armed via
7
+ * `kici-admin attestations retry --include-rejected`.
8
+ *
9
+ * Idempotent: guarded on column existence.
10
+ */
11
+ export declare function up(db: Kysely<unknown>): Promise<void>;
12
+ export declare function down(db: Kysely<unknown>): Promise<void>;
13
+ //# sourceMappingURL=066_pending_attestations_rejected.d.ts.map