@kici-dev/orchestrator 0.1.27 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/dist/__test-helpers__/mock-db.d.ts +2 -0
  2. package/dist/agent/dispatcher.d.ts +52 -2
  3. package/dist/agent/host-roster-reaper.d.ts +1 -2
  4. package/dist/agent/host-roster.d.ts +34 -0
  5. package/dist/agent/ownership-refusal.d.ts +12 -0
  6. package/dist/agent/ownership-tracker.d.ts +64 -16
  7. package/dist/agent/token-store.d.ts +13 -0
  8. package/dist/agent-packaging/availability.d.ts +27 -0
  9. package/dist/agent-packaging/build-package.d.ts +16 -0
  10. package/dist/agent-packaging/download.d.ts +30 -0
  11. package/dist/agent-packaging/index.d.ts +9 -0
  12. package/dist/agent-packaging/install-closure.d.ts +30 -0
  13. package/dist/agent-packaging/node-binary.d.ts +26 -0
  14. package/dist/agent-packaging/refresh.d.ts +50 -0
  15. package/dist/agent-packaging/store.d.ts +15 -0
  16. package/dist/agent-packaging/upload.d.ts +24 -0
  17. package/dist/app-on-error.d.ts +29 -0
  18. package/dist/app.d.ts +56 -4
  19. package/dist/artifacts/artifact-store.d.ts +233 -0
  20. package/dist/artifacts/failure-messages.d.ts +46 -0
  21. package/dist/audit/access-log.d.ts +18 -1
  22. package/dist/cache/dep-cache.d.ts +15 -0
  23. package/dist/cache/user-cache.d.ts +37 -0
  24. package/dist/cancel/cancel-run.d.ts +10 -3
  25. package/dist/cancel/dashboard-cancel-handler.d.ts +19 -0
  26. package/dist/cli/api-client.d.ts +44 -1
  27. package/dist/cli/commands/agent-package.d.ts +34 -0
  28. package/dist/cli/commands/check-run.d.ts +26 -0
  29. package/dist/cli/commands/cluster-settings.d.ts +55 -0
  30. package/dist/cli/commands/dashboard-encryption-key.d.ts +3 -0
  31. package/dist/cli/commands/db-backup.d.ts +71 -0
  32. package/dist/cli/commands/orchestrator-service/drain.d.ts +31 -0
  33. package/dist/cli/commands/orchestrator-service/index.d.ts +7 -4
  34. package/dist/cli/commands/orchestrator-service/install-env.d.ts +58 -0
  35. package/dist/cli/commands/secret.d.ts +45 -1
  36. package/dist/cli/commands/shared/admin-cli-access-log.d.ts +46 -0
  37. package/dist/cli/commands/shared/versioned-upgrade.d.ts +65 -2
  38. package/dist/cli/commands/signing-key.d.ts +3 -0
  39. package/dist/cli/commands/source.d.ts +12 -0
  40. package/dist/cli/commands/token.d.ts +9 -0
  41. package/dist/cli/commands/trust-policy.d.ts +48 -0
  42. package/dist/cli/join.d.ts +1 -1
  43. package/dist/cli/service/index.d.ts +2 -2
  44. package/dist/cli/service/instance/manifest.d.ts +17 -0
  45. package/dist/cli/service/instance/resolve.d.ts +11 -0
  46. package/dist/cli/wizard/orchestrator-wizard.d.ts +39 -11
  47. package/dist/cli.js +9921 -3409
  48. package/dist/cluster/cluster-settings-reader.d.ts +78 -0
  49. package/dist/cluster/coordinator.d.ts +81 -9
  50. package/dist/cluster/join-client.d.ts +1 -1
  51. package/dist/cluster/leader-gated-scheduler.d.ts +50 -0
  52. package/dist/cluster/orphan-recovery.d.ts +14 -0
  53. package/dist/cluster/peer-client.d.ts +12 -2
  54. package/dist/cluster/peer-handler.d.ts +15 -4
  55. package/dist/cluster/peer-registry.d.ts +12 -0
  56. package/dist/cluster/verified-issuer-poller.d.ts +11 -0
  57. package/dist/cluster/verified-issuer.d.ts +63 -0
  58. package/dist/cold-store/tables/access-log.d.ts +1 -1
  59. package/dist/cold-store/tables/event-log.d.ts +1 -1
  60. package/dist/cold-store/tables/execution-jobs.d.ts +1 -1
  61. package/dist/cold-store/tables/execution-runs.d.ts +1 -1
  62. package/dist/cold-store/tables/execution-steps.d.ts +1 -1
  63. package/dist/cold-store/tables/secret-audit-log.d.ts +1 -1
  64. package/dist/config/loader.d.ts +1 -1
  65. package/dist/config/resolver.d.ts +2 -1
  66. package/dist/config/schema.d.ts +9 -6
  67. package/dist/config/types.d.ts +5 -2
  68. package/dist/config.d.ts +366 -53
  69. package/dist/contexts/context-store.d.ts +21 -8
  70. package/dist/contexts/glob-specificity.d.ts +30 -0
  71. package/dist/contexts/held-runs.d.ts +51 -19
  72. package/dist/contexts/protection/aggregate.d.ts +2 -2
  73. package/dist/contexts/protection/concurrency-gate.d.ts +0 -3
  74. package/dist/contexts/protection/reviewer-gate.d.ts +0 -3
  75. package/dist/contexts/protection/satisfiability.d.ts +1 -1
  76. package/dist/contexts/protection/trust-gate.d.ts +0 -3
  77. package/dist/contexts/protection/wait-timer-gate.d.ts +0 -3
  78. package/dist/cron/cron-scheduler.d.ts +24 -4
  79. package/dist/cron/cron-store.d.ts +21 -7
  80. package/dist/dashboard/attestation-filters.d.ts +92 -74
  81. package/dist/dashboard/handler.d.ts +35 -1
  82. package/dist/db/migration-test-harness.d.ts +41 -0
  83. package/dist/db/migrations/069_reroute_tunables.d.ts +21 -0
  84. package/dist/db/migrations/070_execution_runs_failure_class.d.ts +4 -0
  85. package/dist/db/migrations/071_batch_accumulation.d.ts +26 -0
  86. package/dist/db/migrations/072_dispatch_queue_run_id_index.d.ts +15 -0
  87. package/dist/db/migrations/073_org_settings_ingest_concurrency.d.ts +13 -0
  88. package/dist/db/migrations/074_normalize_zero_concurrency_limit.d.ts +13 -0
  89. package/dist/db/migrations/075_ingest_overflow_buffer.d.ts +16 -0
  90. package/dist/db/migrations/076_artifacts.d.ts +19 -0
  91. package/dist/db/migrations/077_backup_runs.d.ts +13 -0
  92. package/dist/db/migrations/078_org_settings_backup_staleness.d.ts +12 -0
  93. package/dist/db/migrations/079_org_settings_scaler_spawn_timeout.d.ts +14 -0
  94. package/dist/db/migrations/080_cluster_settings.d.ts +17 -0
  95. package/dist/db/migrations/081_org_settings_queue_timeout.d.ts +19 -0
  96. package/dist/db/migrations/082_host_s3_reachable.d.ts +16 -0
  97. package/dist/db/migrations/083_org_settings_artifact_caps.d.ts +18 -0
  98. package/dist/db/migrations/084_orchestrator_signing_keys.d.ts +20 -0
  99. package/dist/db/migrations/085_cluster_settings_reroute_flap_grace_ms.d.ts +12 -0
  100. package/dist/db/migrations/086_cluster_settings_max_fanout_hosts.d.ts +12 -0
  101. package/dist/db/migrations/087_cluster_settings_event_router_rate_limit.d.ts +12 -0
  102. package/dist/db/migrations/088_cluster_settings_cache_max_tarball_bytes.d.ts +12 -0
  103. package/dist/db/migrations/089_cluster_settings_cache_ttl_days.d.ts +12 -0
  104. package/dist/db/migrations/090_cluster_settings_concurrency_wait_timeout_ms.d.ts +12 -0
  105. package/dist/db/migrations/091_cluster_settings_agent_token_ttl_ms.d.ts +12 -0
  106. package/dist/db/migrations/092_cluster_settings_version.d.ts +16 -0
  107. package/dist/db/migrations/093_org_settings_sandbox_allowlist.d.ts +4 -0
  108. package/dist/db/migrations/094_dashboard_encryption_keys.d.ts +21 -0
  109. package/dist/db/migrations/095_dashboard_write_policy_tristate.d.ts +20 -0
  110. package/dist/db/migrations/096_multi_schedule_cron_last_fired.d.ts +4 -0
  111. package/dist/db/migrations/097_execution_runs_pr_number.d.ts +4 -0
  112. package/dist/db/migrations/098_execution_runs_customer_id.d.ts +4 -0
  113. package/dist/db/migrations/099_cluster_settings_dashboard_verified_issuer.d.ts +21 -0
  114. package/dist/db/migrations/100_held_runs_hold_type_vocabulary.d.ts +31 -0
  115. package/dist/db/migrations/101_contexts_hold_expiry_drop_default.d.ts +31 -0
  116. package/dist/db/migrations/102_dispatch_queue_agent_id.d.ts +20 -0
  117. package/dist/db/migrations/103_cluster_settings_ownership_db_check_timeout_ms.d.ts +20 -0
  118. package/dist/db/migrations/104_check_run_terminal_sent.d.ts +22 -0
  119. package/dist/db/migrations/105_org_trust_policy.d.ts +19 -0
  120. package/dist/db/migrations/106_cluster_settings_check_run_tracking_ttl_days.d.ts +18 -0
  121. package/dist/db/migrations/107_check_run_tracking_updated_at_index.d.ts +23 -0
  122. package/dist/db/migrations/108_unroutable_fast_fail.d.ts +4 -0
  123. package/dist/db/repos/dashboard-encryption-keys-repo.d.ts +48 -0
  124. package/dist/db/repos/signing-keys-repo.d.ts +34 -0
  125. package/dist/db/types.d.ts +441 -7
  126. package/dist/deployment/deployment-identity.d.ts +87 -2
  127. package/dist/diagnostics/checks/backup.d.ts +18 -0
  128. package/dist/diagnostics/checks/index.d.ts +2 -1
  129. package/dist/diagnostics/fleet-collector.d.ts +1 -1
  130. package/dist/drain/drain-controller.d.ts +52 -0
  131. package/dist/events/batch-accumulator.d.ts +63 -0
  132. package/dist/events/circuit-breaker.d.ts +9 -3
  133. package/dist/events/event-emitter.d.ts +31 -0
  134. package/dist/events/event-retry-scanner.d.ts +12 -2
  135. package/dist/events/event-router.d.ts +29 -0
  136. package/dist/firecracker/host-network.d.ts +2 -0
  137. package/dist/firecracker/net-interfaces.d.ts +14 -0
  138. package/dist/github-app-name-refresher/github-app-name-refresher.d.ts +18 -8
  139. package/dist/index.d.ts +2 -0
  140. package/dist/index.js +654 -29
  141. package/dist/lockfile-cache.d.ts +4 -0
  142. package/dist/lockfile-validate.d.ts +16 -9
  143. package/dist/metrics/prometheus.d.ts +113 -15
  144. package/dist/oidc/aws-kms-signer.d.ts +37 -0
  145. package/dist/oidc/command-signer.d.ts +23 -0
  146. package/dist/oidc/db-signer.d.ts +48 -0
  147. package/dist/oidc/id-token-claims.d.ts +22 -9
  148. package/dist/oidc/jwt.d.ts +5 -2
  149. package/dist/oidc/local-dev-signer.d.ts +1 -1
  150. package/dist/oidc/oidc-mint-registration.d.ts +27 -11
  151. package/dist/oidc/orchestrator-mint.d.ts +97 -0
  152. package/dist/oidc/orchestrator-signer-factory.d.ts +33 -0
  153. package/dist/oidc/reconcile-signing-key.d.ts +21 -0
  154. package/dist/oidc/signer.d.ts +25 -0
  155. package/dist/oidc/signing-key-status.d.ts +23 -0
  156. package/dist/orchestrator-core.d.ts +42 -2
  157. package/dist/pipeline/decorating-secret-resolver.d.ts +3 -2
  158. package/dist/pipeline/dispatch-matched-workflow.d.ts +41 -0
  159. package/dist/pipeline/install-secrets-resolver.d.ts +12 -1
  160. package/dist/pipeline/manual-schedule.d.ts +20 -13
  161. package/dist/pipeline/pending-workflow-context.d.ts +1 -1
  162. package/dist/pipeline/process-webhook.d.ts +57 -2
  163. package/dist/pipeline/processor.d.ts +44 -8
  164. package/dist/pipeline/rerun.d.ts +12 -13
  165. package/dist/pipeline/resolve-sandbox-grant.d.ts +28 -0
  166. package/dist/pipeline/route-or-dispatch-jobs.d.ts +71 -0
  167. package/dist/pipeline/sandbox-allowlist-reader.d.ts +33 -0
  168. package/dist/policy/dashboard-write-policy.d.ts +9 -4
  169. package/dist/provenance/backfill-run.d.ts +1 -0
  170. package/dist/provenance/trust-root.d.ts +13 -0
  171. package/dist/providers/generic/normalizer.d.ts +1 -1
  172. package/dist/providers/github/auth.d.ts +1 -1
  173. package/dist/providers/github/changed-files.d.ts +14 -6
  174. package/dist/providers/github/check-status-poster.d.ts +19 -3
  175. package/dist/providers/github/contributor-resolver.d.ts +1 -1
  176. package/dist/providers/github/lock-file.d.ts +1 -1
  177. package/dist/providers/github/normalizer.d.ts +1 -1
  178. package/dist/providers/github/repo-url.d.ts +1 -1
  179. package/dist/providers/local/lock-file-fetcher.d.ts +1 -1
  180. package/dist/providers/local/normalizer.d.ts +1 -1
  181. package/dist/providers/local/repo-url-builder.d.ts +1 -1
  182. package/dist/providers/universal-git/changed-files.d.ts +8 -7
  183. package/dist/providers/universal-git/clone-token.d.ts +1 -1
  184. package/dist/providers/universal-git/config.d.ts +4 -4
  185. package/dist/providers/universal-git/index.d.ts +5 -1
  186. package/dist/providers/universal-git/lock-file.d.ts +6 -1
  187. package/dist/providers/universal-git/normalizer.d.ts +1 -1
  188. package/dist/providers/universal-git/repo-url.d.ts +1 -1
  189. package/dist/queue/bootstrap.d.ts +5 -0
  190. package/dist/queue/cleanup.d.ts +72 -9
  191. package/dist/queue/job-queue.d.ts +141 -14
  192. package/dist/queue/scheduled-job.d.ts +3 -2
  193. package/dist/queue/terminalize-unroutable.d.ts +53 -0
  194. package/dist/queue/unroutable-probe.d.ts +52 -0
  195. package/dist/registration/registration-index.d.ts +1 -1
  196. package/dist/reporting/agent-failure-category.d.ts +4 -1
  197. package/dist/reporting/check-run-reporter.d.ts +34 -14
  198. package/dist/reporting/check-run-tracking-store.d.ts +70 -8
  199. package/dist/reporting/execution-tracker.d.ts +156 -10
  200. package/dist/reporting/fs-log-storage.d.ts +31 -2
  201. package/dist/reporting/job-check-run-completion.d.ts +50 -0
  202. package/dist/reporting/log-chunk-sink.d.ts +47 -0
  203. package/dist/reporting/log-retention.d.ts +16 -0
  204. package/dist/reporting/log-storage.d.ts +64 -4
  205. package/dist/reporting/log-writer.d.ts +22 -7
  206. package/dist/reporting/peer-log-normalize.d.ts +14 -0
  207. package/dist/reporting/run-aggregator.d.ts +50 -33
  208. package/dist/reporting/s3-log-storage.d.ts +102 -8
  209. package/dist/routes/admin-auth.d.ts +90 -0
  210. package/dist/routes/admin-cluster-settings.d.ts +31 -0
  211. package/dist/routes/admin-events.d.ts +3 -0
  212. package/dist/routes/admin-orchestrator-drain.d.ts +35 -0
  213. package/dist/routes/admin-runs.d.ts +9 -0
  214. package/dist/routes/admin-sources.d.ts +7 -0
  215. package/dist/routes/admin-trust-policy.d.ts +49 -0
  216. package/dist/routes/admin.d.ts +15 -1
  217. package/dist/routes/github-webhook.d.ts +9 -3
  218. package/dist/routes/provenance-oidc.d.ts +38 -0
  219. package/dist/routes/verify-attestation.d.ts +21 -0
  220. package/dist/scaler/bare-metal-backend.d.ts +9 -2
  221. package/dist/scaler/config.d.ts +25 -4
  222. package/dist/scaler/container-backend.d.ts +9 -1
  223. package/dist/scaler/firecracker-backend.d.ts +29 -2
  224. package/dist/scaler/index.d.ts +1 -1
  225. package/dist/scaler/manager.d.ts +166 -8
  226. package/dist/scaler/pending-scale-sweeper.d.ts +35 -0
  227. package/dist/scaler/types.d.ts +75 -6
  228. package/dist/secrets/backend-registry.d.ts +32 -1
  229. package/dist/secrets/dashboard-encryption-key.d.ts +48 -0
  230. package/dist/secrets/ephemeral-keys.d.ts +16 -0
  231. package/dist/secrets/pg-secret-store.d.ts +10 -0
  232. package/dist/secrets/rbac.d.ts +5 -1
  233. package/dist/secrets/routing-key-scope.d.ts +6 -0
  234. package/dist/secrets/scope-routing.d.ts +126 -0
  235. package/dist/secrets/secret-resolver.d.ts +1 -14
  236. package/dist/secrets/token-manager.d.ts +5 -1
  237. package/dist/security/contributor-cache.d.ts +9 -1
  238. package/dist/security/trust-policy-gate.d.ts +117 -0
  239. package/dist/security/trust-policy-store.d.ts +78 -0
  240. package/dist/server.js +36074 -25052
  241. package/dist/sources/source-manager.d.ts +24 -0
  242. package/dist/stale-detector/stale-run-detector.d.ts +7 -0
  243. package/dist/standalone.js +35203 -25387
  244. package/dist/storage/filesystem.d.ts +17 -0
  245. package/dist/storage/key-discriminator.d.ts +20 -0
  246. package/dist/storage/s3.d.ts +2 -0
  247. package/dist/storage/types.d.ts +16 -0
  248. package/dist/webhook/dedup.d.ts +9 -1
  249. package/dist/webhook/event-log.d.ts +13 -2
  250. package/dist/webhook/generic-sources-listener.d.ts +4 -0
  251. package/dist/webhook/ingest-admission.d.ts +140 -0
  252. package/dist/webhook/ingest-overflow-buffer.d.ts +27 -0
  253. package/dist/webhook/ingest-overflow-replayer.d.ts +49 -0
  254. package/dist/webhook/ingest-overflow-types.d.ts +73 -0
  255. package/dist/webhook/loop-lag-source.d.ts +40 -0
  256. package/dist/webhook/observed-relay-guard.d.ts +40 -0
  257. package/dist/webhook/org-ingest-cap-reader.d.ts +24 -0
  258. package/dist/webhook/register-source-bundle.d.ts +3 -0
  259. package/dist/webhook/relay-reinject.d.ts +43 -0
  260. package/dist/worker/in-memory-job-queue.d.ts +8 -3
  261. package/dist/worker-core.d.ts +10 -0
  262. package/dist/ws/agent-api-registry.d.ts +20 -0
  263. package/dist/ws/agent-handler.d.ts +63 -7
  264. package/dist/ws/bringup-api.d.ts +99 -0
  265. package/dist/ws/dashboard-context-handler.d.ts +28 -10
  266. package/dist/ws/dashboard-run-state-handler.d.ts +31 -0
  267. package/dist/ws/failure-messages.d.ts +29 -0
  268. package/dist/ws/oidc-token-relay.d.ts +9 -0
  269. package/dist/ws/ownership-gate.d.ts +22 -0
  270. package/dist/ws/platform-client.d.ts +96 -1
  271. package/dist/ws/replay-chunker.d.ts +37 -0
  272. package/installer-image-digests.json +3 -3
  273. package/package.json +22 -21
  274. package/sbom.spdx.json +1240 -1788
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { z } from 'zod';
8
8
  import { ScalerEventType } from '@kici-dev/engine';
9
- import type { ResourceRequest, ResourceSpec, ScalerBackendType } from '@kici-dev/engine';
9
+ import type { ResourceRequest, ResourceSpec, ScalerBackendType, ScalerPlatform } from '@kici-dev/engine';
10
10
  export type { ResourceRequest, ResourceSpec } from '@kici-dev/engine';
11
11
  export { ScalerEventType } from '@kici-dev/engine';
12
12
  /**
@@ -73,6 +73,22 @@ export interface NetworkPolicy {
73
73
  /** Block all outbound traffic except allowlisted ranges */
74
74
  denyAll?: boolean;
75
75
  }
76
+ /**
77
+ * Image pull policy for container-backend agent images.
78
+ *
79
+ * - `IfNotPresent` (default): pull only when the image is not already local.
80
+ * KiCI agent images are pinned + immutable, so re-pulling on every spawn only
81
+ * storms the registry/socket.
82
+ * - `Always`: re-pull on every spawn. Set this on a label set that tracks a
83
+ * moving tag (e.g. `:latest`) or otherwise needs a fresh image each spawn.
84
+ * - `Never`: never pull; fail if the image is absent.
85
+ */
86
+ export declare const ImagePullPolicy: z.ZodEnum<{
87
+ Always: "Always";
88
+ IfNotPresent: "IfNotPresent";
89
+ Never: "Never";
90
+ }>;
91
+ export type ImagePullPolicy = z.infer<typeof ImagePullPolicy>;
76
92
  /**
77
93
  * Configuration for a single label-set mapping within a scaler backend.
78
94
  * Maps an exact set of labels to the agent provisioning details.
@@ -82,8 +98,8 @@ export interface LabelSetConfig {
82
98
  labels: string[];
83
99
  /** Container image (Docker backend) */
84
100
  image?: string;
85
- /** Image pull policy: Always (default), IfNotPresent, or Never */
86
- imagePullPolicy?: 'Always' | 'IfNotPresent' | 'Never';
101
+ /** Image pull policy: IfNotPresent (default), Always, or Never */
102
+ imagePullPolicy?: ImagePullPolicy;
87
103
  /** Path to agent binary (bare-metal backend) */
88
104
  binaryPath?: string;
89
105
  /**
@@ -154,7 +170,23 @@ export type ScaleResult = {
154
170
  } | {
155
171
  action: 'failed';
156
172
  error: string;
173
+ }
174
+ /** Scale-up declined without attempting a spawn (e.g. coordinator draining). */
175
+ | {
176
+ action: 'skipped';
177
+ reason: string;
157
178
  };
179
+ /**
180
+ * What triggered a pending-scale re-drive (`Dispatcher.retryPendingScaleRequests`):
181
+ * the near-zero-latency capacity-freed `hook` fired from `ScalerManager`, or the
182
+ * leader-gated periodic `sweep` backstop. Used as the `trigger` label on the
183
+ * `kici_orch_scaler_redispatch_total` counter.
184
+ */
185
+ export declare const ScalerRedispatchTrigger: z.ZodEnum<{
186
+ hook: "hook";
187
+ sweep: "sweep";
188
+ }>;
189
+ export type ScalerRedispatchTrigger = z.infer<typeof ScalerRedispatchTrigger>;
158
190
  /**
159
191
  * Result of a configuration validation or reload operation.
160
192
  */
@@ -184,7 +216,8 @@ export interface ScalerBackend {
184
216
  * True for bare-metal and Firecracker (local processes / local VMs) and for
185
217
  * container backends using a local runtime socket; false when the backend
186
218
  * provisions elsewhere (remote container runtime, future cloud backends).
187
- * Drives the static spawning-host display on the diagnostics page.
219
+ * Drives the static spawning-host display on the dashboard Infrastructure
220
+ * page.
188
221
  */
189
222
  readonly spawnsOnLocalHost: boolean;
190
223
  /** Current count of agents managed by this backend (including spawning) */
@@ -205,7 +238,14 @@ export interface ScalerBackend {
205
238
  * @returns The managed agent tracking object
206
239
  * @throws If the label set is not supported by this backend
207
240
  */
208
- spawn(labelSet: string[], agentId: string, orchestratorUrl: string, onEvent?: ScalerEventCallback, effectiveLimits?: EffectiveLimits, spawnContext?: SpawnContext): Promise<ManagedAgent>;
241
+ spawn(labelSet: string[], agentId: string, orchestratorUrl: string, onEvent?: ScalerEventCallback, effectiveLimits?: EffectiveLimits, spawnContext?: SpawnContext,
242
+ /**
243
+ * Optional abort signal from the ScalerManager spawn-timeout wrapper. When
244
+ * aborted, backends thread it into any long-running provisioning I/O
245
+ * (container-runtime requests, HTTP calls) so a hung provision cancels
246
+ * instead of pinning the per-backend spawn-semaphore slot.
247
+ */
248
+ signal?: AbortSignal): Promise<ManagedAgent>;
209
249
  /**
210
250
  * Destroy a specific managed agent.
211
251
  * Docker: docker rm -f; Bare-metal: SIGTERM -> SIGKILL
@@ -224,6 +264,14 @@ export interface ScalerBackend {
224
264
  * Used by the orchestrator to enrich job.context before forwarding to Platform.
225
265
  */
226
266
  getScalerContext?(agentId: string): Record<string, unknown> | undefined;
267
+ /**
268
+ * Provision or heal this backend's host prerequisites before it spawns.
269
+ * Called once by ScalerManager during startup. Optional — only backends with
270
+ * host-side setup (Firecracker's bridge) implement it; container/bare-metal
271
+ * omit it. May throw; the manager catches per-backend and degrades that
272
+ * scaler rather than aborting orchestrator startup.
273
+ */
274
+ ensureHostReady?(): Promise<void>;
227
275
  /**
228
276
  * Reload configuration (called on SIGHUP).
229
277
  * Returns validation errors if new config is invalid.
@@ -250,6 +298,12 @@ export interface FirecrackerNetworkConfig {
250
298
  netmask?: string;
251
299
  /** nft table name for this coordinator's host bridge @default 'kici' */
252
300
  table?: string;
301
+ /**
302
+ * When true (default), the orchestrator verifies and provisions this host
303
+ * bridge on startup (self-heal), so a fresh Firecracker host needs no manual
304
+ * `kici-admin firecracker provision`. @default true
305
+ */
306
+ autoProvisionHost?: boolean;
253
307
  }
254
308
  /**
255
309
  * Parsed and validated scaler configuration from YAML.
@@ -293,8 +347,15 @@ export interface ScalerEntry {
293
347
  name: string;
294
348
  /** Backend type */
295
349
  type: Exclude<ScalerBackendType, 'kubernetes'>;
296
- /** Maximum concurrent agents for this scaler */
350
+ /** Maximum concurrent agents for this scaler (population cap) */
297
351
  maxAgents: number;
352
+ /**
353
+ * Maximum concurrent `backend.spawn` operations for this scaler
354
+ * (provisioning-rate throttle). Orthogonal to `maxAgents`: excess in-cap
355
+ * spawns queue and drain at this rate rather than storming the socket.
356
+ * Defaults to `DEFAULT_MAX_CONCURRENT_SPAWNS` at config-load.
357
+ */
358
+ maxConcurrentSpawns: number;
298
359
  /** Label-set to image/binary mappings */
299
360
  labelSets: LabelSetConfig[];
300
361
  /** Container runtime host (e.g. 'tcp://192.168.1.10:2376'). Works for both Docker and Podman remote. */
@@ -319,6 +380,14 @@ export interface ScalerEntry {
319
380
  * `labelSets`. Default: `[]` (no gating).
320
381
  */
321
382
  mandatoryLabels?: string[];
383
+ /**
384
+ * Structured platform of this pool's agents. When set, the auto-injected
385
+ * `kici:os:*` / `kici:arch:*` labels AND the mandatory platform taint both
386
+ * derive from this single field. Optional: when omitted, bare-metal pools
387
+ * derive the platform from the host OS/arch, and container / firecracker
388
+ * pools default to linux.
389
+ */
390
+ readonly platform?: ScalerPlatform;
322
391
  /**
323
392
  * Agent roles this scaler handles. scaler-entry level, not per-label-set.
324
393
  * - undefined (not set): handles all job types including build and init (backward compat,)
@@ -18,7 +18,26 @@ export declare class BackendRegistry {
18
18
  private readonly db;
19
19
  private readonly masterKey;
20
20
  private readonly logger?;
21
- constructor(db: Kysely<any>, masterKey: Buffer, logger?: Logger | undefined);
21
+ private readonly oldMasterKey?;
22
+ constructor(db: Kysely<any>, masterKey: Buffer, logger?: Logger | undefined, oldMasterKey?: Buffer | undefined);
23
+ /**
24
+ * Decrypt a backend config with the current master key, falling back to the
25
+ * old key during a rotation grace window. Same dual-key pattern as
26
+ * PgSecretStore.decryptWithFallback / ephemeral-keys.decryptPrivateKey. The
27
+ * AAD stays `row.name` — ciphertext remains bound to its logical backend.
28
+ * Never called for sentinel rows (config_encrypted = '').
29
+ */
30
+ private decryptConfigWithFallback;
31
+ /** Loud, recovery-pointing error for a backend stranded by key rotation. */
32
+ private strandedError;
33
+ /**
34
+ * Re-seal a backend config that decrypted only under the old key back under
35
+ * the current master key. Runs at load time while KICI_SECRET_KEY_OLD is
36
+ * still configured, healing deployments that rotated before backend configs
37
+ * were part of the rotation sweep. The concurrent-rotation guard
38
+ * (`config_key_version` match) keeps a racing rotation from being clobbered.
39
+ */
40
+ private selfHealStrandedRow;
22
41
  /**
23
42
  * Register a new backend. Encrypts config and stores in DB.
24
43
  */
@@ -64,5 +83,17 @@ export declare class BackendRegistry {
64
83
  * Update sync status for a backend.
65
84
  */
66
85
  updateSyncStatus(name: string, scopeCount: number, error?: string): Promise<void>;
86
+ /**
87
+ * Re-encrypt every non-sentinel backend config under the current master key
88
+ * at max(config_key_version)+1. Same transactional skip-and-count shape as
89
+ * SharedConfigStore.rotateKey — an undecryptable row is counted and left in
90
+ * place (never aborts the sweep); recovery guidance lives in strandedError.
91
+ * Sentinel rows (config_encrypted = '') are excluded from the candidate set
92
+ * and never counted.
93
+ */
94
+ rotateKey(): Promise<{
95
+ reEncrypted: number;
96
+ skipped: number;
97
+ }>;
67
98
  }
68
99
  //# sourceMappingURL=backend-registry.d.ts.map
@@ -0,0 +1,48 @@
1
+ import { type JWK } from 'jose';
2
+ import type { DashboardEncryptionKeyRepo } from '../db/repos/dashboard-encryption-keys-repo.js';
3
+ export interface GeneratedDashboardEncryptionKey {
4
+ kid: string;
5
+ publicJwk: JWK;
6
+ /** AES-256-GCM-wrapped DER private key (master-key wrapped). */
7
+ encryptedPrivateKey: string;
8
+ /** DER-SPKI public key Buffer (for callers that need the raw bytes). */
9
+ publicKeyDer: Buffer;
10
+ }
11
+ /**
12
+ * Generate a fresh X25519 dashboard-encryption key: the OKP public JWK
13
+ * (`use:'enc'`, `kid` = RFC 7638 thumbprint) plus the master-key-wrapped
14
+ * private half.
15
+ */
16
+ export declare function generateDashboardEncryptionKey(secretKey: string): Promise<GeneratedDashboardEncryptionKey>;
17
+ export interface ReconcileDashboardEncryptionKeyDeps {
18
+ repo: Pick<DashboardEncryptionKeyRepo, 'getActiveRow' | 'upsertActive' | 'getByKid'>;
19
+ isLeader: () => boolean;
20
+ /** The orchestrator master key (`KICI_SECRET_KEY`), for db-custody wrapping. */
21
+ secretKey: string | undefined;
22
+ /** Called once when a NEW kid is first activated (audit log, system actor). */
23
+ audit: (info: {
24
+ kid: string;
25
+ }) => Promise<void> | void;
26
+ }
27
+ /** The resolved active dashboard-encryption key + a per-request decrypt closure. */
28
+ export interface ResolvedDashboardEncryptionKey {
29
+ activeKid: string;
30
+ publicJwk: JWK;
31
+ /**
32
+ * Unwrap the DER private key for a given `kid` — the active key OR a
33
+ * rotated-out one whose row is still on record. The lookup is
34
+ * status-agnostic, so a revoked key that has left the published JWKS still
35
+ * decrypts; null means the kid is unknown (never minted, or its row was
36
+ * deleted). Reads the wrapped private half from the DB each call, so
37
+ * rotation is picked up without a restart.
38
+ */
39
+ decryptPrivateKeyDer: (kid: string) => Promise<Buffer | null>;
40
+ }
41
+ /**
42
+ * Ensure exactly one `active` dashboard-encryption key exists and return the
43
+ * resolved key + decrypt closure, or null when not yet ready (non-leader before
44
+ * the leader has generated it). Requires `KICI_SECRET_KEY` (throws otherwise —
45
+ * the private key is master-key wrapped, same posture as db-custody signing).
46
+ */
47
+ export declare function reconcileDashboardEncryptionKey(deps: ReconcileDashboardEncryptionKeyDeps): Promise<ResolvedDashboardEncryptionKey | null>;
48
+ //# sourceMappingURL=dashboard-encryption-key.d.ts.map
@@ -46,4 +46,20 @@ export declare function decryptSecretOutput(envelope: {
46
46
  agentPublicKey: string;
47
47
  encrypted: string;
48
48
  }, runPrivateKeyDer: Buffer): string;
49
+ /**
50
+ * Decrypt a browser-sealed dashboard write.
51
+ *
52
+ * Under the `encrypted` dashboard-write posture the browser seals the value to
53
+ * the orchestrator's published X25519 encryption key using the SAME
54
+ * ECDH → HKDF → AES-256-GCM envelope the agent uses for run secret outputs,
55
+ * but with the `kici-dashboard-sealed-write` HKDF info string.
56
+ *
57
+ * @param envelope - `{ ephemeralPublicKey: base64 DER-SPKI, encrypted: base64 IV||tag||ct }`
58
+ * @param encryptionPrivateKeyDer - DER-encoded orchestrator X25519 private key
59
+ * @returns Decrypted plaintext string
60
+ */
61
+ export declare function decryptDashboardSealedWrite(envelope: {
62
+ ephemeralPublicKey: string;
63
+ encrypted: string;
64
+ }, encryptionPrivateKeyDer: Buffer): string;
49
65
  //# sourceMappingURL=ephemeral-keys.d.ts.map
@@ -19,6 +19,16 @@ export declare class SecretScopeNotFoundError extends Error {
19
19
  readonly scope: string;
20
20
  constructor(scope: string);
21
21
  }
22
+ /**
23
+ * Thrown by `renameScope` when the destination scope already holds secret rows
24
+ * or context bindings. Renaming onto it would merge two scopes rather than move
25
+ * one. The admin HTTP route maps it to a 409; the dashboard rename handler
26
+ * relays its message as the operation's error text.
27
+ */
28
+ export declare class SecretScopeExistsError extends Error {
29
+ readonly scope: string;
30
+ constructor(scope: string);
31
+ }
22
32
  /**
23
33
  * PostgreSQL secret store with AES-256-GCM encryption.
24
34
  * Uses scoped_secrets table keyed by (org_id, scope, key).
@@ -13,7 +13,11 @@ export type Role = 'owner' | 'admin' | 'auditor';
13
13
  /**
14
14
  * Permissions for the secrets management admin API.
15
15
  */
16
- export type Permission = 'context.create' | 'context.read' | 'context.update' | 'context.delete' | 'secret.read' | 'secret.write' | 'secret.delete' | 'secret.reveal' | 'audit.read' | 'token.manage' | 'key.rotate' | 'run.read' | 'run.cancel' | 'event_log.read' | 'event_log.read_payload' | 'access_log.read' | 'scheduled_job.trigger' | 'attestation.retry' | 'event_dlq.read' | 'event_dlq.manage';
16
+ export type Permission = 'context.create' | 'context.read' | 'context.update' | 'context.delete' | 'secret.read' | 'secret.write' | 'secret.delete' | 'secret.reveal' | 'audit.read' | 'token.manage' | 'key.rotate' | 'run.read' | 'run.cancel' | 'event_log.read' | 'event_log.read_payload' | 'access_log.read' | 'scheduled_job.trigger' | 'attestation.retry' | 'event_dlq.read' | 'event_dlq.manage' | 'orchestrator.drain'
17
+ /** Read the org-wide CI trust policy that gates fork / unknown / workflow-change PRs. */
18
+ | 'ci_trust.read'
19
+ /** Modify org-wide trust policies (independent mode only — Platform-attached PATCH refuses). */
20
+ | 'ci_trust.admin';
17
21
  /**
18
22
  * Error thrown when a role lacks the required permission.
19
23
  */
@@ -17,6 +17,12 @@
17
17
  * access is denied, or `null` to let the handler continue. The middleware
18
18
  * mounted in each admin route file is responsible for calling
19
19
  * `c.set('routingKey', tokenInfo.routingKey)` so these helpers can read it.
20
+ *
21
+ * NOT a scope name. `requested` must be a routing key (`<provider>:<id>`) read
22
+ * from a row or an explicit request field. Secret scope names live in a
23
+ * different namespace — a path whose `:` is reserved as the backend qualifier —
24
+ * and must never be passed here. Secret routes have no per-routing-key slice;
25
+ * they use `requireUnscopedToken` instead.
20
26
  */
21
27
  import type { Context } from 'hono';
22
28
  /**
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Backend-qualified scope routing.
3
+ *
4
+ * A secret scope travels over the wire in *qualified* form -- `<backend>:<path>`
5
+ * -- while every `SecretStore` implementation is addressed with the bare
6
+ * `<path>`. This module owns the single split between the two forms so the two
7
+ * write planes (the dashboard WebSocket handler and the HTTP admin API) can
8
+ * never drift apart on where the qualifier is stripped.
9
+ *
10
+ * The registered-backend map IS the whitelist: a head before the first `:` is a
11
+ * backend qualifier only when it names a registered backend. Anything else --
12
+ * an unregistered head, a leading `:`, no `:` at all -- stays whole and is
13
+ * routed to the default store, where the ordinary scope-name validation
14
+ * rejects it if it is malformed. That is what keeps routing keys
15
+ * (`<provider>:<id>`) out of the secret-scope namespace: `github:42` names no
16
+ * backend, so it stays whole and is rejected as a scope path.
17
+ */
18
+ /**
19
+ * The subset of `SecretStore` a scope-taking route or WS handler needs.
20
+ *
21
+ * Deliberately narrower than the full `SecretStore` from `@kici-dev/engine`:
22
+ * routing only needs the scope-addressed methods, so a caller may pass a
23
+ * partial store (the degraded store below, a unit-test fake) without
24
+ * implementing value resolution.
25
+ */
26
+ export interface ScopedSecretStore {
27
+ listScopes(orgId: string): Promise<string[]>;
28
+ listKeys(orgId: string, scope: string): Promise<string[]>;
29
+ setSecret(orgId: string, scope: string, key: string, value: string): Promise<void>;
30
+ deleteSecret(orgId: string, scope: string, key: string): Promise<void>;
31
+ createScope?(orgId: string, scope: string): Promise<void>;
32
+ renameScope?(orgId: string, oldScope: string, newScope: string): Promise<void>;
33
+ deleteScope?(orgId: string, scope: string): Promise<void>;
34
+ }
35
+ /**
36
+ * Raised when a secret write is issued against an orchestrator that has no
37
+ * secret store configured.
38
+ *
39
+ * The message is operator-facing: the dashboard write planes relay it verbatim
40
+ * as the `error` on their response, so it names the deployment condition rather
41
+ * than the internal cause.
42
+ */
43
+ export declare class SecretsUnavailableError extends Error {
44
+ constructor();
45
+ }
46
+ /**
47
+ * The store an orchestrator serves the dashboard from when it has no secret
48
+ * store configured.
49
+ *
50
+ * The read/write asymmetry is deliberate. `listScopes` / `listKeys` return
51
+ * empty because "this deployment holds no secrets" is true and complete.
52
+ * `setSecret` / `deleteSecret` reject, because a write that resolved here would
53
+ * be discarded while the dashboard reported the secret as stored -- and a
54
+ * delete that resolved would leave a credential the operator believes is
55
+ * revoked. The optional scope methods stay unimplemented: the write planes
56
+ * already refuse a scope operation a store does not support.
57
+ */
58
+ export declare function createUnavailableSecretStore(): ScopedSecretStore;
59
+ /** Backend name assumed when a wire scope carries no recognised qualifier. */
60
+ export declare const DEFAULT_BACKEND_NAME = "pg";
61
+ /** Outcome of resolving a wire-form scope against the registered backends. */
62
+ export interface ResolvedScope<S> {
63
+ /** The store the operation must be issued against. */
64
+ store: S;
65
+ /** The backend the scope resolved to (the default name when unqualified). */
66
+ backendName: string;
67
+ /** The bare scope path to pass to the store -- never carries a qualifier. */
68
+ path: string;
69
+ /** True when the wire scope carried a recognised `<backend>:` qualifier. */
70
+ qualified: boolean;
71
+ }
72
+ /**
73
+ * The one method of the secret-backend registry that store loading needs.
74
+ *
75
+ * Structural on purpose: keeping the concrete registry out of this module lets
76
+ * both write planes -- and their unit tests -- supply their own loader without
77
+ * dragging a database-backed registry into a pure routing module.
78
+ */
79
+ export interface BackendStoreRegistry<S, L> {
80
+ loadAllStores(auditLogger: L): Promise<Map<string, S>>;
81
+ }
82
+ /**
83
+ * Load the registered secret backends for one operation.
84
+ *
85
+ * Never cache the result: a backend's credentials can rotate, and a backend can
86
+ * be added or removed, between operations -- a stale store would write to the
87
+ * wrong place. A registry failure propagates rather than degrading to the
88
+ * default store, because a misrouted secret write is worse than a failed one.
89
+ *
90
+ * The default-backend entry is ALWAYS `defaultStore`, overriding whatever the
91
+ * registry returned. The registry builds its own `PgSecretStore` for the seeded
92
+ * `pg` row, and that instance carries none of the orchestrator's configuration:
93
+ * `customerSecretsEnabled` defaults to true (so it would ignore an operator's
94
+ * `pgCustomerSecrets: false`), its key version is hardcoded to 1, and it has no
95
+ * old-master-key fallback (so it cannot decrypt rows written before a
96
+ * rotation). Overriding only when the registry omitted the entry is dead code
97
+ * -- the default row is seeded at startup -- and would let `pg:<path>` and
98
+ * `<path>` behave differently, which is the very defect this routing exists to
99
+ * fix.
100
+ *
101
+ * @param registry - Backend registry, or undefined when none is configured.
102
+ * @param auditLogger - Audit logger handed to the registry's store factory.
103
+ * @param defaultStore - Configured store for the default backend.
104
+ * @param defaultBackendName - Name the default store is registered under.
105
+ */
106
+ export declare function loadRoutableStores<S, L>(registry: BackendStoreRegistry<S, L> | undefined, auditLogger: L, defaultStore: S, defaultBackendName?: string): Promise<Map<string, S>>;
107
+ /**
108
+ * Split a wire-form scope into the store that owns it and the bare path.
109
+ *
110
+ * Pure: takes the already-loaded store map rather than loading it, so both
111
+ * planes can unit-test routing without a database.
112
+ *
113
+ * @param wireScope - Scope as supplied by the caller, possibly `<backend>:<path>`.
114
+ * @param stores - Registered backends, keyed by backend name.
115
+ * @param defaultStore - Store used when the scope carries no recognised qualifier.
116
+ * @param defaultBackendName - Backend name reported for an unqualified scope.
117
+ */
118
+ export declare function resolveScope<S>(wireScope: string, stores: Map<string, S>, defaultStore: S, defaultBackendName?: string): ResolvedScope<S>;
119
+ /**
120
+ * Join a backend name and a bare path back into wire form.
121
+ *
122
+ * Used for audit records and cross-backend listings, so an operator reading the
123
+ * audit log sees the same qualified string the caller sent.
124
+ */
125
+ export declare function toWireScope(backendName: string, path: string): string;
126
+ //# sourceMappingURL=scope-routing.d.ts.map
@@ -7,7 +7,7 @@
7
7
  * 2. Gets bindings for that context
8
8
  * 3. Queries ALL registered backend stores for secrets
9
9
  * 4. Prefixes each secret's scope with the backend name (e.g., pg:aws/prod)
10
- * 5. Uses resolveSecretsForContext to match bindings against prefixed secrets
10
+ * 5. Uses resolveSecretsWithProvenance to match bindings against prefixed secrets
11
11
  * 6. Returns a flat decrypted key-value map
12
12
  *
13
13
  * unreachable backends cause job failure (not silent skip).
@@ -148,18 +148,5 @@ export declare class SecretResolver implements SecretResolverApi {
148
148
  * jobs referencing only healthy backends succeed normally.
149
149
  */
150
150
  private checkScopedFailure;
151
- /**
152
- * Find the winning secret for a given key, mirroring the engine scope
153
- * resolver's host-aware matching and `(host specificity, scope depth)`
154
- * precedence so the enriched metadata reports the same secret the flat
155
- * resolution selected.
156
- */
157
- private findWinningSecret;
158
- /**
159
- * Resolve the effective scope pattern a binding contributes for a host,
160
- * applying the host gate and per-child scope templating. Mirrors the engine
161
- * scope resolver's `bindingScopeForHost`. Returns `null` to skip the binding.
162
- */
163
- private bindingScopeForHost;
164
151
  }
165
152
  //# sourceMappingURL=secret-resolver.d.ts.map
@@ -16,15 +16,19 @@ export declare class TokenManager {
16
16
  * @param label - Human-readable label for this token.
17
17
  * @param role - Role to assign (owner, admin, auditor).
18
18
  * @param routingKey - Optional routing key scope (null = all).
19
+ * @param expiresAt - Optional absolute expiry. When omitted the token
20
+ * never expires (null); `validate()` already enforces the column.
19
21
  * @returns The plaintext token (shown once) and the row ID.
20
22
  */
21
- generateToken(label: string, role: Role, routingKey?: string | null): Promise<{
23
+ generateToken(label: string, role: Role, routingKey?: string | null, expiresAt?: Date | null): Promise<{
22
24
  token: string;
23
25
  id: string;
24
26
  }>;
25
27
  /**
26
28
  * Validate a plaintext token against stored hashes.
27
29
  *
30
+ * On success, fires a non-blocking update to last_used_at.
31
+ *
28
32
  * @param token - The plaintext token to validate.
29
33
  * @returns Token info if valid, null if invalid/expired/revoked.
30
34
  */
@@ -5,18 +5,26 @@
5
5
  * Uses a 15-minute TTL and 10,000 max entries.
6
6
  */
7
7
  import type { ContributorResolver, ContributorInfo } from '@kici-dev/engine';
8
+ import type { ClusterSettingsReader } from '../cluster/cluster-settings-reader.js';
8
9
  /**
9
10
  * Caches ContributorResolver results in an LRU cache.
10
11
  *
11
12
  * Cache key format: `{provider}:{repoFullName}:{username}`
12
- * TTL: 15 minutes (configurable for testing).
13
+ * TTL: cluster-configurable (`cluster_settings.contributor_cache_ttl_ms`,
14
+ * default 15 minutes). The TTL is resolved at each `set()` and applied
15
+ * per-entry, so a live override affects newly-cached entries without a restart.
13
16
  */
14
17
  export declare class ContributorCache {
15
18
  private readonly cache;
19
+ private readonly clusterSettings?;
20
+ private readonly defaultTtlMs;
16
21
  constructor(options?: {
17
22
  ttlMs?: number;
18
23
  maxEntries?: number;
24
+ clusterSettings?: ClusterSettingsReader;
19
25
  });
26
+ /** Resolve the fleet-wide contributor-cache TTL (ms), falling back to the config default. */
27
+ private ttlMs;
20
28
  /**
21
29
  * Build the cache key from provider, repo, and username.
22
30
  */
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Org trust-policy gate — turns the Platform-owned policy plus three per-PR
3
+ * signals into exactly one outcome.
4
+ *
5
+ * Pure: no I/O, no DB, no clock. The caller supplies the effective policy (see
6
+ * `resolveEffectivePolicy`) and the signals; enforcement lives in the dispatch
7
+ * gate.
8
+ *
9
+ * Scope: the caller only invokes this for sources whose provider bundle carries
10
+ * a `ContributorResolver` (GitHub today). Every other source is trusted by
11
+ * construction and never reaches here.
12
+ */
13
+ import { z } from 'zod';
14
+ import type { OrchestratorMode, TrustPolicy, TrustTier } from '@kici-dev/engine';
15
+ import { SecurityHoldReason } from '../contexts/held-runs.js';
16
+ import type { StoredTrustPolicy } from './trust-policy-store.js';
17
+ /**
18
+ * Which arm of the gate is actually in force for an org — the vocabulary the
19
+ * admin API reports and `kici-admin trust-policy show` renders.
20
+ *
21
+ * `policy` means `resolveEffectivePolicy` produced a policy and all three arms
22
+ * apply; `legacy` means it produced `null`, so only the legacy
23
+ * workflow-modification rule runs and there are no policy values to report.
24
+ * Named here, next to the resolver that decides between them, so the route and
25
+ * the CLI cannot drift apart on a bare string literal.
26
+ */
27
+ export declare const TrustPolicyEnforcement: z.ZodEnum<{
28
+ legacy: "legacy";
29
+ policy: "policy";
30
+ }>;
31
+ export type TrustPolicyEnforcement = z.infer<typeof TrustPolicyEnforcement>;
32
+ /** The per-PR facts the policy is evaluated against. */
33
+ export interface TrustPolicySignals {
34
+ /** Resolved contributor tier; undefined when trust resolution failed. */
35
+ tier: TrustTier | undefined;
36
+ /** The PR's head repo differs from its base repo. */
37
+ isForkPR: boolean;
38
+ /** The PR changes `.kici/` workflow definitions. */
39
+ hasWorkflowModifications: boolean;
40
+ }
41
+ /**
42
+ * The reasons the ORG TRUST POLICY itself can raise — its three arms.
43
+ *
44
+ * `context_trust` is excluded at the type level rather than merely by
45
+ * convention: that reason belongs to the per-context minimum-trust gate, which
46
+ * holds an individual job under its real name. Narrowing here is what lets
47
+ * `SECURITY_HOLD_JOB_IDS` drop its phantom `context_trust` sentinel — a value
48
+ * that existed only to satisfy a `Record<SecurityHoldReason, ...>` and was never
49
+ * written to a single row.
50
+ */
51
+ export type TrustPolicyHoldReason = Exclude<SecurityHoldReason, 'context_trust'>;
52
+ export type TrustPolicyOutcome = {
53
+ action: 'pass';
54
+ } | {
55
+ action: 'hold';
56
+ reason: TrustPolicyHoldReason;
57
+ message: string;
58
+ /**
59
+ * Hours the resulting hold stays approvable, taken from the SAME policy
60
+ * that produced this verdict. `null` in independent mode, where there is
61
+ * no upstream policy and therefore no operator-set window.
62
+ *
63
+ * Carried on the outcome rather than re-read at the hold site: a second,
64
+ * independent read bypassed `resolveEffectivePolicy`, so it was both a
65
+ * TOCTOU (the policy could change between deciding and sizing) and a
66
+ * divergence — independent mode got the 72h default where the decision
67
+ * path deliberately has no policy at all.
68
+ */
69
+ approvalExpiryHours: number | null;
70
+ } | {
71
+ action: 'reject';
72
+ reason: TrustPolicyHoldReason;
73
+ message: string;
74
+ };
75
+ /**
76
+ * The policy a Platform-attached orchestrator applies when it has no stored
77
+ * row. Every arm holds — a hold is recoverable by approval, and these are the
78
+ * documented org defaults, so an org that never changed its policy gets the
79
+ * behavior its dashboard shows.
80
+ *
81
+ * This is NOT necessarily a brief transient. The Platform sends
82
+ * `trust_policy.update` only when the org has a `trust_policies` row, and that
83
+ * row is created lazily on a dashboard read — so an org that has never opened
84
+ * Settings > CI trust receives no push at all and stays on these values
85
+ * indefinitely. The expiry is therefore the generous documented default rather
86
+ * than a short one: a short window would auto-fail legitimate runs.
87
+ */
88
+ export declare const FAIL_CLOSED_POLICY: TrustPolicy;
89
+ /**
90
+ * Pick the policy to evaluate. A stored row always wins. Without one, a
91
+ * Platform-attached orchestrator fails closed (a push is imminent); an
92
+ * independent orchestrator has no upstream authority at all, so it gets `null`
93
+ * and the evaluator applies only the legacy rule — which is what keeps this
94
+ * change from silently gating existing independent deployments on upgrade.
95
+ *
96
+ * `PLATFORM_CONNECTED_MODES` is the shared definition of "expects a Platform
97
+ * push", so a mode added there is fail-closed here without a second edit.
98
+ */
99
+ export declare function resolveEffectivePolicy(stored: StoredTrustPolicy | null, mode: OrchestratorMode): TrustPolicy | null;
100
+ /**
101
+ * Evaluate the policy.
102
+ *
103
+ * Arms are evaluated in a fixed order — workflow_modification, fork_pr,
104
+ * unknown_contributor — and then any `reject` beats any `hold`, with the first
105
+ * arm in that order supplying the reason among equals. That makes a PR tripping
106
+ * several arms produce one outcome with a stable reason rather than a verdict
107
+ * that depends on evaluation accident.
108
+ *
109
+ * An unresolved tier (`undefined`) counts as `unknown`, never as a pass: a
110
+ * trust resolution that could not be answered is not evidence of trust.
111
+ *
112
+ * A `null` policy applies only the legacy rule (workflow modifications by a
113
+ * non-trusted contributor hold), reproducing behavior from before the policy was
114
+ * enforced.
115
+ */
116
+ export declare function evaluateTrustPolicy(policy: TrustPolicy | null, signals: TrustPolicySignals): TrustPolicyOutcome;
117
+ //# sourceMappingURL=trust-policy-gate.d.ts.map