@kici-dev/orchestrator 0.1.26 → 0.2.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 (310) 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 +69 -8
  19. package/dist/approvals/apply-decision.d.ts +1 -1
  20. package/dist/approvals/step-approval-bridge.d.ts +1 -1
  21. package/dist/artifacts/artifact-store.d.ts +233 -0
  22. package/dist/artifacts/failure-messages.d.ts +46 -0
  23. package/dist/audit/access-log.d.ts +18 -1
  24. package/dist/cache/dep-cache.d.ts +15 -0
  25. package/dist/cache/pending-inits.d.ts +4 -4
  26. package/dist/cache/user-cache.d.ts +37 -0
  27. package/dist/cancel/cancel-run.d.ts +10 -3
  28. package/dist/cancel/dashboard-cancel-handler.d.ts +19 -0
  29. package/dist/cli/api-client.d.ts +51 -5
  30. package/dist/cli/commands/agent-package.d.ts +34 -0
  31. package/dist/cli/commands/check-run.d.ts +26 -0
  32. package/dist/cli/commands/cluster-settings.d.ts +55 -0
  33. package/dist/cli/commands/context.d.ts +25 -0
  34. package/dist/cli/commands/dashboard-encryption-key.d.ts +3 -0
  35. package/dist/cli/commands/db-backup.d.ts +71 -0
  36. package/dist/cli/commands/debug-bundle.d.ts +1 -1
  37. package/dist/cli/commands/orchestrator-service/drain.d.ts +31 -0
  38. package/dist/cli/commands/orchestrator-service/index.d.ts +7 -4
  39. package/dist/cli/commands/orchestrator-service/install-env.d.ts +58 -0
  40. package/dist/cli/commands/secret.d.ts +45 -1
  41. package/dist/cli/commands/shared/admin-cli-access-log.d.ts +46 -0
  42. package/dist/cli/commands/shared/versioned-upgrade.d.ts +65 -2
  43. package/dist/cli/commands/signing-key.d.ts +3 -0
  44. package/dist/cli/commands/source.d.ts +12 -0
  45. package/dist/cli/commands/token.d.ts +9 -0
  46. package/dist/cli/commands/trust-policy.d.ts +48 -0
  47. package/dist/cli/commands/variable.d.ts +6 -6
  48. package/dist/cli/join.d.ts +1 -1
  49. package/dist/cli/service/index.d.ts +2 -2
  50. package/dist/cli/service/instance/manifest.d.ts +17 -0
  51. package/dist/cli/service/instance/resolve.d.ts +11 -0
  52. package/dist/cli/service/windows.d.ts +6 -0
  53. package/dist/cli/wizard/orchestrator-wizard.d.ts +39 -11
  54. package/dist/cli.js +10263 -3667
  55. package/dist/cluster/cluster-settings-reader.d.ts +78 -0
  56. package/dist/cluster/coordinator.d.ts +81 -9
  57. package/dist/cluster/join-client.d.ts +1 -1
  58. package/dist/cluster/leader-gated-scheduler.d.ts +50 -0
  59. package/dist/cluster/orphan-recovery.d.ts +14 -0
  60. package/dist/cluster/peer-client.d.ts +12 -2
  61. package/dist/cluster/peer-handler.d.ts +15 -4
  62. package/dist/cluster/peer-registry.d.ts +12 -0
  63. package/dist/cluster/verified-issuer-poller.d.ts +11 -0
  64. package/dist/cluster/verified-issuer.d.ts +63 -0
  65. package/dist/cold-store/tables/access-log.d.ts +1 -1
  66. package/dist/cold-store/tables/event-log.d.ts +1 -1
  67. package/dist/cold-store/tables/execution-jobs.d.ts +1 -1
  68. package/dist/cold-store/tables/execution-runs.d.ts +1 -1
  69. package/dist/cold-store/tables/execution-steps.d.ts +1 -1
  70. package/dist/cold-store/tables/secret-audit-log.d.ts +1 -1
  71. package/dist/config/loader.d.ts +1 -1
  72. package/dist/config/resolver.d.ts +2 -1
  73. package/dist/config/schema.d.ts +8 -6
  74. package/dist/config/types.d.ts +3 -2
  75. package/dist/config.d.ts +372 -46
  76. package/dist/contexts/binding-store.d.ts +36 -0
  77. package/dist/contexts/context-store.d.ts +100 -0
  78. package/dist/contexts/glob-specificity.d.ts +30 -0
  79. package/dist/{environments → contexts}/held-runs.d.ts +64 -32
  80. package/dist/{environments → contexts}/index.d.ts +1 -1
  81. package/dist/contexts/protection/aggregate.d.ts +43 -0
  82. package/dist/contexts/protection/branch-gate.d.ts +5 -0
  83. package/dist/contexts/protection/concurrency-gate.d.ts +4 -0
  84. package/dist/{environments → contexts}/protection/pipeline.d.ts +3 -3
  85. package/dist/contexts/protection/reviewer-gate.d.ts +4 -0
  86. package/dist/{environments → contexts}/protection/satisfiability.d.ts +22 -22
  87. package/dist/contexts/protection/trust-gate.d.ts +4 -0
  88. package/dist/contexts/protection/wait-timer-gate.d.ts +4 -0
  89. package/dist/contexts/variable-store.d.ts +39 -0
  90. package/dist/cron/cron-scheduler.d.ts +24 -4
  91. package/dist/cron/cron-store.d.ts +21 -7
  92. package/dist/dashboard/attestation-filters.d.ts +94 -74
  93. package/dist/dashboard/handler.d.ts +63 -3
  94. package/dist/db/migration-test-harness.d.ts +41 -0
  95. package/dist/db/migrations/067_environments_to_contexts.d.ts +36 -0
  96. package/dist/db/migrations/068_request_idempotency.d.ts +17 -0
  97. package/dist/db/migrations/069_reroute_tunables.d.ts +21 -0
  98. package/dist/db/migrations/070_execution_runs_failure_class.d.ts +4 -0
  99. package/dist/db/migrations/071_batch_accumulation.d.ts +26 -0
  100. package/dist/db/migrations/072_dispatch_queue_run_id_index.d.ts +15 -0
  101. package/dist/db/migrations/073_org_settings_ingest_concurrency.d.ts +13 -0
  102. package/dist/db/migrations/074_normalize_zero_concurrency_limit.d.ts +13 -0
  103. package/dist/db/migrations/075_ingest_overflow_buffer.d.ts +16 -0
  104. package/dist/db/migrations/076_artifacts.d.ts +19 -0
  105. package/dist/db/migrations/077_backup_runs.d.ts +13 -0
  106. package/dist/db/migrations/078_org_settings_backup_staleness.d.ts +12 -0
  107. package/dist/db/migrations/079_org_settings_scaler_spawn_timeout.d.ts +14 -0
  108. package/dist/db/migrations/080_cluster_settings.d.ts +17 -0
  109. package/dist/db/migrations/081_org_settings_queue_timeout.d.ts +19 -0
  110. package/dist/db/migrations/082_host_s3_reachable.d.ts +16 -0
  111. package/dist/db/migrations/083_org_settings_artifact_caps.d.ts +18 -0
  112. package/dist/db/migrations/084_orchestrator_signing_keys.d.ts +20 -0
  113. package/dist/db/migrations/085_cluster_settings_reroute_flap_grace_ms.d.ts +12 -0
  114. package/dist/db/migrations/086_cluster_settings_max_fanout_hosts.d.ts +12 -0
  115. package/dist/db/migrations/087_cluster_settings_event_router_rate_limit.d.ts +12 -0
  116. package/dist/db/migrations/088_cluster_settings_cache_max_tarball_bytes.d.ts +12 -0
  117. package/dist/db/migrations/089_cluster_settings_cache_ttl_days.d.ts +12 -0
  118. package/dist/db/migrations/090_cluster_settings_concurrency_wait_timeout_ms.d.ts +12 -0
  119. package/dist/db/migrations/091_cluster_settings_agent_token_ttl_ms.d.ts +12 -0
  120. package/dist/db/migrations/092_cluster_settings_version.d.ts +16 -0
  121. package/dist/db/migrations/093_org_settings_sandbox_allowlist.d.ts +4 -0
  122. package/dist/db/migrations/094_dashboard_encryption_keys.d.ts +21 -0
  123. package/dist/db/migrations/095_dashboard_write_policy_tristate.d.ts +20 -0
  124. package/dist/db/migrations/096_multi_schedule_cron_last_fired.d.ts +4 -0
  125. package/dist/db/migrations/097_execution_runs_pr_number.d.ts +4 -0
  126. package/dist/db/migrations/098_execution_runs_customer_id.d.ts +4 -0
  127. package/dist/db/migrations/099_cluster_settings_dashboard_verified_issuer.d.ts +21 -0
  128. package/dist/db/migrations/100_held_runs_hold_type_vocabulary.d.ts +31 -0
  129. package/dist/db/migrations/101_contexts_hold_expiry_drop_default.d.ts +31 -0
  130. package/dist/db/migrations/102_dispatch_queue_agent_id.d.ts +20 -0
  131. package/dist/db/migrations/103_cluster_settings_ownership_db_check_timeout_ms.d.ts +20 -0
  132. package/dist/db/migrations/104_check_run_terminal_sent.d.ts +22 -0
  133. package/dist/db/migrations/105_org_trust_policy.d.ts +19 -0
  134. package/dist/db/migrations/106_cluster_settings_check_run_tracking_ttl_days.d.ts +18 -0
  135. package/dist/db/migrations/107_check_run_tracking_updated_at_index.d.ts +23 -0
  136. package/dist/db/repos/dashboard-encryption-keys-repo.d.ts +48 -0
  137. package/dist/db/repos/signing-keys-repo.d.ts +34 -0
  138. package/dist/db/types.d.ts +499 -66
  139. package/dist/deployment/deployment-identity.d.ts +87 -2
  140. package/dist/diagnostics/checks/backup.d.ts +18 -0
  141. package/dist/diagnostics/checks/index.d.ts +2 -1
  142. package/dist/diagnostics/fleet-collector.d.ts +1 -1
  143. package/dist/drain/drain-controller.d.ts +52 -0
  144. package/dist/events/batch-accumulator.d.ts +63 -0
  145. package/dist/events/circuit-breaker.d.ts +9 -3
  146. package/dist/events/event-emitter.d.ts +31 -0
  147. package/dist/events/event-retry-scanner.d.ts +12 -2
  148. package/dist/events/event-router.d.ts +29 -0
  149. package/dist/firecracker/host-network.d.ts +2 -0
  150. package/dist/firecracker/net-interfaces.d.ts +14 -0
  151. package/dist/github-app-name-refresher/github-app-name-refresher.d.ts +19 -9
  152. package/dist/index.d.ts +2 -0
  153. package/dist/index.js +625 -22
  154. package/dist/lockfile-cache.d.ts +4 -0
  155. package/dist/lockfile-validate.d.ts +16 -9
  156. package/dist/metrics/prometheus.d.ts +114 -15
  157. package/dist/oidc/aws-kms-signer.d.ts +37 -0
  158. package/dist/oidc/command-signer.d.ts +23 -0
  159. package/dist/oidc/db-signer.d.ts +48 -0
  160. package/dist/oidc/id-token-claims.d.ts +76 -0
  161. package/dist/oidc/jwt.d.ts +18 -0
  162. package/dist/oidc/local-dev-signer.d.ts +31 -0
  163. package/dist/oidc/local-mint.d.ts +77 -0
  164. package/dist/oidc/oidc-mint-registration.d.ts +65 -0
  165. package/dist/oidc/orchestrator-mint.d.ts +97 -0
  166. package/dist/oidc/orchestrator-signer-factory.d.ts +33 -0
  167. package/dist/oidc/reconcile-signing-key.d.ts +21 -0
  168. package/dist/oidc/signer.d.ts +25 -0
  169. package/dist/oidc/signing-key-status.d.ts +23 -0
  170. package/dist/orchestrator-core.d.ts +42 -2
  171. package/dist/pipeline/decorating-secret-resolver.d.ts +5 -4
  172. package/dist/pipeline/dispatch-matched-workflow.d.ts +44 -3
  173. package/dist/pipeline/inline-eval.d.ts +2 -2
  174. package/dist/pipeline/install-secrets-resolver.d.ts +25 -14
  175. package/dist/pipeline/{job-environments.d.ts → job-contexts.d.ts} +23 -23
  176. package/dist/pipeline/manual-schedule.d.ts +28 -14
  177. package/dist/pipeline/pending-workflow-context.d.ts +1 -1
  178. package/dist/pipeline/process-webhook.d.ts +57 -2
  179. package/dist/pipeline/processor.d.ts +49 -13
  180. package/dist/pipeline/request-idempotency.d.ts +28 -0
  181. package/dist/pipeline/rerun.d.ts +20 -13
  182. package/dist/pipeline/resolve-sandbox-grant.d.ts +28 -0
  183. package/dist/pipeline/resume-workflow.d.ts +1 -1
  184. package/dist/pipeline/route-or-dispatch-jobs.d.ts +71 -0
  185. package/dist/pipeline/sandbox-allowlist-reader.d.ts +33 -0
  186. package/dist/pipeline/test-pipeline.d.ts +2 -2
  187. package/dist/policy/dashboard-write-policy.d.ts +9 -4
  188. package/dist/provenance/backfill-run.d.ts +1 -0
  189. package/dist/provenance/trust-root.d.ts +20 -0
  190. package/dist/provider-registry.d.ts +8 -0
  191. package/dist/providers/generic/normalizer.d.ts +1 -1
  192. package/dist/providers/github/auth.d.ts +1 -1
  193. package/dist/providers/github/changed-files.d.ts +14 -6
  194. package/dist/providers/github/check-status-poster.d.ts +19 -3
  195. package/dist/providers/github/contributor-resolver.d.ts +1 -1
  196. package/dist/providers/github/lock-file.d.ts +1 -1
  197. package/dist/providers/github/normalizer.d.ts +1 -1
  198. package/dist/providers/github/repo-url.d.ts +1 -1
  199. package/dist/providers/local/index.d.ts +1 -0
  200. package/dist/providers/local/local-source-config.d.ts +1 -0
  201. package/dist/providers/local/lock-file-fetcher.d.ts +1 -1
  202. package/dist/providers/local/normalizer.d.ts +1 -1
  203. package/dist/providers/local/repo-url-builder.d.ts +1 -1
  204. package/dist/providers/universal-git/changed-files.d.ts +8 -7
  205. package/dist/providers/universal-git/clone-token.d.ts +1 -1
  206. package/dist/providers/universal-git/config.d.ts +4 -4
  207. package/dist/providers/universal-git/index.d.ts +5 -1
  208. package/dist/providers/universal-git/lock-file.d.ts +6 -1
  209. package/dist/providers/universal-git/normalizer.d.ts +1 -1
  210. package/dist/providers/universal-git/repo-url.d.ts +1 -1
  211. package/dist/queue/cleanup.d.ts +69 -8
  212. package/dist/queue/job-queue.d.ts +94 -14
  213. package/dist/queue/scheduled-job.d.ts +2 -2
  214. package/dist/registration/registration-index.d.ts +1 -1
  215. package/dist/reporting/agent-failure-category.d.ts +4 -1
  216. package/dist/reporting/check-run-reporter.d.ts +34 -14
  217. package/dist/reporting/check-run-tracking-store.d.ts +70 -8
  218. package/dist/reporting/execution-tracker.d.ts +173 -17
  219. package/dist/reporting/fs-log-storage.d.ts +31 -2
  220. package/dist/reporting/job-check-run-completion.d.ts +50 -0
  221. package/dist/reporting/log-chunk-sink.d.ts +47 -0
  222. package/dist/reporting/log-retention.d.ts +16 -0
  223. package/dist/reporting/log-storage.d.ts +64 -4
  224. package/dist/reporting/log-writer.d.ts +22 -7
  225. package/dist/reporting/peer-log-normalize.d.ts +14 -0
  226. package/dist/reporting/run-aggregator.d.ts +36 -36
  227. package/dist/reporting/s3-log-storage.d.ts +102 -8
  228. package/dist/routes/admin-auth.d.ts +90 -0
  229. package/dist/routes/admin-cluster-settings.d.ts +31 -0
  230. package/dist/routes/admin-contexts.d.ts +47 -0
  231. package/dist/routes/admin-events.d.ts +3 -0
  232. package/dist/routes/admin-orchestrator-drain.d.ts +35 -0
  233. package/dist/routes/admin-registrations.d.ts +2 -2
  234. package/dist/routes/admin-runs.d.ts +9 -0
  235. package/dist/routes/admin-sources.d.ts +7 -0
  236. package/dist/routes/admin-trust-policy.d.ts +49 -0
  237. package/dist/routes/admin.d.ts +15 -1
  238. package/dist/routes/github-webhook.d.ts +9 -3
  239. package/dist/routes/provenance-oidc.d.ts +38 -0
  240. package/dist/routes/verify-attestation.d.ts +21 -0
  241. package/dist/scaler/bare-metal-backend.d.ts +9 -2
  242. package/dist/scaler/config.d.ts +25 -4
  243. package/dist/scaler/container-backend.d.ts +9 -1
  244. package/dist/scaler/firecracker-backend.d.ts +29 -2
  245. package/dist/scaler/index.d.ts +1 -1
  246. package/dist/scaler/manager.d.ts +166 -8
  247. package/dist/scaler/pending-scale-sweeper.d.ts +35 -0
  248. package/dist/scaler/types.d.ts +75 -6
  249. package/dist/secrets/backend-registry.d.ts +32 -1
  250. package/dist/secrets/context-secret-resolver.d.ts +30 -0
  251. package/dist/secrets/dashboard-encryption-key.d.ts +48 -0
  252. package/dist/secrets/ephemeral-keys.d.ts +16 -0
  253. package/dist/secrets/index.d.ts +1 -1
  254. package/dist/secrets/pg-secret-store.d.ts +13 -3
  255. package/dist/secrets/rbac.d.ts +5 -1
  256. package/dist/secrets/routing-key-scope.d.ts +6 -0
  257. package/dist/secrets/scope-routing.d.ts +126 -0
  258. package/dist/secrets/secret-resolver.d.ts +19 -32
  259. package/dist/secrets/token-manager.d.ts +5 -1
  260. package/dist/security/comment-handler.d.ts +1 -1
  261. package/dist/security/contributor-cache.d.ts +9 -1
  262. package/dist/security/trust-policy-gate.d.ts +117 -0
  263. package/dist/security/trust-policy-store.d.ts +78 -0
  264. package/dist/server.js +44012 -32721
  265. package/dist/sources/source-manager.d.ts +24 -0
  266. package/dist/stale-detector/stale-run-detector.d.ts +8 -1
  267. package/dist/standalone.js +44106 -33690
  268. package/dist/storage/blob-routes.d.ts +16 -0
  269. package/dist/storage/filesystem.d.ts +17 -0
  270. package/dist/storage/key-discriminator.d.ts +20 -0
  271. package/dist/storage/s3.d.ts +2 -0
  272. package/dist/storage/types.d.ts +16 -0
  273. package/dist/webhook/dedup.d.ts +9 -1
  274. package/dist/webhook/event-log.d.ts +13 -2
  275. package/dist/webhook/generic-sources-listener.d.ts +4 -0
  276. package/dist/webhook/ingest-admission.d.ts +140 -0
  277. package/dist/webhook/ingest-overflow-buffer.d.ts +27 -0
  278. package/dist/webhook/ingest-overflow-replayer.d.ts +49 -0
  279. package/dist/webhook/ingest-overflow-types.d.ts +73 -0
  280. package/dist/webhook/loop-lag-source.d.ts +40 -0
  281. package/dist/webhook/observed-relay-guard.d.ts +40 -0
  282. package/dist/webhook/org-ingest-cap-reader.d.ts +24 -0
  283. package/dist/webhook/register-source-bundle.d.ts +3 -0
  284. package/dist/webhook/relay-reinject.d.ts +43 -0
  285. package/dist/worker/in-memory-job-queue.d.ts +8 -3
  286. package/dist/worker-core.d.ts +10 -0
  287. package/dist/ws/agent-api-registry.d.ts +20 -0
  288. package/dist/ws/agent-handler.d.ts +63 -7
  289. package/dist/ws/bringup-api.d.ts +99 -0
  290. package/dist/ws/{dashboard-env-handler.d.ts → dashboard-context-handler.d.ts} +43 -25
  291. package/dist/ws/dashboard-run-state-handler.d.ts +31 -0
  292. package/dist/ws/failure-messages.d.ts +29 -0
  293. package/dist/ws/oidc-token-relay.d.ts +15 -0
  294. package/dist/ws/ownership-gate.d.ts +22 -0
  295. package/dist/ws/platform-client.d.ts +96 -1
  296. package/dist/ws/replay-chunker.d.ts +37 -0
  297. package/installer-image-digests.json +3 -3
  298. package/package.json +22 -21
  299. package/sbom.spdx.json +1245 -1793
  300. package/dist/cli/commands/environment.d.ts +0 -25
  301. package/dist/environments/binding-store.d.ts +0 -36
  302. package/dist/environments/environment-store.d.ts +0 -87
  303. package/dist/environments/protection/aggregate.d.ts +0 -43
  304. package/dist/environments/protection/branch-gate.d.ts +0 -5
  305. package/dist/environments/protection/concurrency-gate.d.ts +0 -7
  306. package/dist/environments/protection/reviewer-gate.d.ts +0 -7
  307. package/dist/environments/protection/trust-gate.d.ts +0 -7
  308. package/dist/environments/protection/wait-timer-gate.d.ts +0 -7
  309. package/dist/environments/variable-store.d.ts +0 -39
  310. package/dist/routes/admin-environments.d.ts +0 -47
@@ -10,6 +10,27 @@ import type { ResourceRequest } from '@kici-dev/engine';
10
10
  import type { BackendFailureSummary } from './failure-tracker.js';
11
11
  import type { ScalerBackend, ScalerConfig, ScaleResult, ScalerEvent, ResourceCap, ValidationResult } from './types.js';
12
12
  import type { ScalerStateStore, ScalerStateRecovery } from './scaler-state-store.js';
13
+ /**
14
+ * Counting semaphore that throttles the number of concurrent async operations.
15
+ *
16
+ * Used to bound how many `backend.spawn` provisioning operations (image pull +
17
+ * container create + start) run at once per backend, so a burst of in-cap jobs
18
+ * cannot storm the container socket / registry.
19
+ *
20
+ * Slots are handed directly to the next waiter on release (rather than bumping a
21
+ * counter the woken task re-decrements), so a task arriving in the microtask gap
22
+ * between a release and a woken waiter cannot jump the queue and transiently
23
+ * exceed the cap. The slot is always released in `run`'s `finally`, so a failed
24
+ * or throwing operation never leaks a slot and wedges the queue.
25
+ */
26
+ export declare class SpawnSemaphore {
27
+ private available;
28
+ private readonly waiters;
29
+ constructor(max: number);
30
+ private acquire;
31
+ private release;
32
+ run<T>(fn: () => Promise<T>): Promise<T>;
33
+ }
13
34
  /**
14
35
  * Resolved per-job resource amounts (cpus + bytes) for both `requests` and
15
36
  * `limits`. The scaler manager produces this from the job's declared resources
@@ -115,6 +136,10 @@ export declare class ScalerManager {
115
136
  private readonly globalUsage;
116
137
  /** Per-scaler machine-pool name (set when scalers reference a pool). */
117
138
  private readonly scalerMachinePools;
139
+ /** Per-scaler cap on concurrent `backend.spawn` operations (provisioning-rate throttle). */
140
+ private readonly maxConcurrentSpawns;
141
+ /** Per-scaler spawn throttles, created lazily from `maxConcurrentSpawns`. */
142
+ private readonly spawnSemaphores;
118
143
  /** Outstanding reservations keyed by agentId; used to release on disconnect. */
119
144
  private readonly reservations;
120
145
  /**
@@ -160,6 +185,23 @@ export declare class ScalerManager {
160
185
  * External callback for relaying correlated scaler events (e.g. to execution tracker).
161
186
  */
162
187
  private readonly onScalerEvent?;
188
+ /** Coordinator drain predicate; when true, requestScale() no-ops (no fresh
189
+ * agents spawned for the held Pending backlog). Defaults to never-draining. */
190
+ private readonly isDraining;
191
+ /**
192
+ * Optional callback fired (debounced) whenever scaler capacity frees — an
193
+ * ephemeral agent released its reservation on disconnect, a spawn failed, or a
194
+ * managed agent completed its job. Wired by the composition roots to the
195
+ * dispatcher's capacity-freed re-drive so jobs that got an `at-capacity`
196
+ * verdict get re-offered to the scaler the moment a slot opens, instead of
197
+ * sitting pending until they time out. Assigned after construction because it
198
+ * references the dispatcher, which is built after the manager.
199
+ */
200
+ onCapacityFreed?: () => void;
201
+ /** Trailing-debounce timer coalescing a burst of releases into one re-drive. */
202
+ private capacityFreedTimer;
203
+ /** Trailing debounce window for {@link notifyCapacityFreed}. */
204
+ private static readonly CAPACITY_FREED_DEBOUNCE_MS;
163
205
  private readonly warmPool;
164
206
  /**
165
207
  * Optional DB-backed state store. When wired (production path), every
@@ -169,6 +211,10 @@ export declare class ScalerManager {
169
211
  * Unit tests can omit the store and operate from in-memory Maps only.
170
212
  */
171
213
  private readonly stateStore?;
214
+ /** Cluster-wide default deadline (ms) for a single `backend.spawn`. */
215
+ private readonly spawnTimeoutMs;
216
+ /** Optional per-org spawn-deadline resolver (production path; DB-backed). */
217
+ private readonly resolveSpawnTimeoutMs?;
172
218
  constructor(deps: {
173
219
  config: ScalerConfig;
174
220
  backends: Array<{
@@ -194,17 +240,64 @@ export declare class ScalerManager {
194
240
  /** Orchestrator instance id (used in ledger rows for ownership). */
195
241
  instanceId: string;
196
242
  };
243
+ /** Coordinator drain predicate. When true, requestScale() declines to spawn
244
+ * fresh capacity for the held Pending backlog. Defaults to never-draining. */
245
+ isDraining?: () => boolean;
246
+ /**
247
+ * Cluster-wide default deadline (ms) for a single `backend.spawn`. Always
248
+ * supplied (from config.scalerSpawnTimeoutMs); the per-org resolver, when
249
+ * present, overrides it per tenant.
250
+ */
251
+ spawnTimeoutMs: number;
252
+ /**
253
+ * Optional per-org resolver for the spawn deadline: given the job's org
254
+ * (jobConfig.cacheOrgId, undefined for warm-pool spawns), returns the
255
+ * effective timeout, falling back to the cluster default internally. Wired
256
+ * in orchestrator-core (has DB); omitted by the worker + unit tests → the
257
+ * cluster default spawnTimeoutMs is used.
258
+ */
259
+ resolveSpawnTimeoutMs?: (orgId: string | undefined) => Promise<number>;
197
260
  });
198
261
  /** Per-scaler mandatoryLabels (taint-style opt-in gate). */
199
262
  private readonly scalerMandatoryLabels;
263
+ /** Declared structured platform per scaler (undefined = host-derive / linux default). */
264
+ private readonly scalerPlatform;
265
+ /**
266
+ * Warn when a pool declares a plain platform-ish label (matched by the legacy
267
+ * denylist) but omits the structured `platform` field. The denylist is a
268
+ * migration shim; declaring `platform` is the canonical way to taint a pool.
269
+ */
270
+ private warnOnUnstructuredPlatformLabels;
271
+ /**
272
+ * Resolve the pool's platform for label + taint derivation. Precedence:
273
+ * 1. A declared `platform` field always wins (even on a linux host).
274
+ * 2. Otherwise a bare-metal pool derives its platform from the host OS/arch.
275
+ * 3. Otherwise (container / firecracker, undeclared) returns null — those
276
+ * pools run linux agents and are not auto-tainted; only an explicit
277
+ * declared platform or a legacy denylist label taints them.
278
+ * Returns null when a bare-metal host's OS/arch is not a supported enum value
279
+ * (the caller falls back to the raw host-label derivation for labels).
280
+ */
281
+ private resolveScalerPlatform;
282
+ /**
283
+ * Effective taint gate for a scaler: its configured mandatoryLabels plus the
284
+ * platform-taint labels derived from the pool's resolved structured platform,
285
+ * unioned with the legacy plain-label denylist shim. A pool declaring a
286
+ * non-default platform (`windows`, `macos`, `arm64`, …) only accepts jobs that
287
+ * request that platform. Container / firecracker pools resolve to linux and
288
+ * carry no taint; calling it uniformly is safe.
289
+ */
290
+ private effectiveMandatoryLabels;
200
291
  /**
201
292
  * Build enriched scaler entries with auto-labels injected into each label set.
202
293
  * This ensures label matching accounts for auto-injected labels (kici:role:*,
203
294
  * kici:os:*, kici:arch:*, kici:agent:*, kici:scaler:*) that agents receive
204
295
  * at spawn time.
205
296
  *
206
- * Mandatory labels are surfaced unchanged from the per-scaler config so the
207
- * label matcher can apply the gate alongside subset matching.
297
+ * The os/arch labels derive from the pool's resolved structured platform
298
+ * (declared field wins, else host-derive for bare-metal, else linux), and the
299
+ * mandatory labels combine the per-scaler config gate with the platform taint,
300
+ * so the label matcher applies the gate alongside subset matching.
208
301
  */
209
302
  private getEnrichedScalerEntries;
210
303
  /**
@@ -214,12 +307,28 @@ export declare class ScalerManager {
214
307
  * back to scaler defaults). Used by per-scaler / per-orchestrator / per-machine
215
308
  * resource caps; the cap math is wired up by ScalerManager itself.
216
309
  */
217
- requestScale(labels: string[], jobId: string, runId: string, excludeLabels?: string[], resources?: ResourceRequest): Promise<ScaleResult>;
310
+ /**
311
+ * Run a single backend spawn under the resolved spawn deadline. Returns the
312
+ * ManagedAgent on success. On deadline: aborts the signal (so the backend's
313
+ * threaded container-runtime/HTTP calls cancel and its own catch cleans up)
314
+ * AND rejects, so the caller's semaphore `run()` finally releases the slot
315
+ * even if the backend's unwind stalls in a non-abortable spot. The backing
316
+ * spawn promise gets a no-op catch attached so a late abort-rejection doesn't
317
+ * surface as an unhandled rejection.
318
+ */
319
+ private runSpawnWithTimeout;
320
+ requestScale(labels: string[], jobId: string, runId: string, excludeLabels?: string[], resources?: ResourceRequest, orgId?: string): Promise<ScaleResult>;
218
321
  /**
219
322
  * Run a critical section under the reservation lock. Serializes concurrent
220
323
  * `requestScale()` calls so the check+reserve sequence is atomic.
221
324
  */
222
325
  private runWithReservationLock;
326
+ /**
327
+ * Lazily resolve the per-backend spawn throttle, sized by the scaler's
328
+ * `maxConcurrentSpawns` (falling back to the cluster default). One semaphore
329
+ * per backend name, since each backend has its own container socket.
330
+ */
331
+ private spawnSemaphoreFor;
223
332
  /**
224
333
  * Resolve the effective `{ requests, limits }` for a job at this scaler.
225
334
  *
@@ -259,6 +368,15 @@ export declare class ScalerManager {
259
368
  * references a pool.
260
369
  */
261
370
  private releaseAll;
371
+ /**
372
+ * Signal that scaler capacity freed. Trailing-debounced by
373
+ * {@link CAPACITY_FREED_DEBOUNCE_MS} so a burst of simultaneous releases (and
374
+ * the onJobComplete → onAgentDisconnect pair for a single-use agent) coalesces
375
+ * into one re-drive pass that runs after the last release settles. No-op when
376
+ * no callback is wired. The timer is `unref`'d so it never keeps the process
377
+ * alive, and cleared on shutdown.
378
+ */
379
+ private notifyCapacityFreed;
262
380
  /**
263
381
  * Subtract the given `requests` from the per-scaler and global in-memory
264
382
  * counters. Used both by `releaseAll()` and by the rollback path when a
@@ -284,7 +402,9 @@ export declare class ScalerManager {
284
402
  * Used by the caller to eagerly dispatch the bound job before the
285
403
  * agent's idle timer fires, skipping the generic queue drain race.
286
404
  * - `mandatoryLabels` (always populated for scaler-managed agents): the
287
- * spawning scaler's `mandatoryLabels` gate. Threaded into the
405
+ * spawning scaler's effective `mandatoryLabels` gate its configured
406
+ * labels plus the platform taint derived from the pool's declared OS/arch.
407
+ * Threaded into the
288
408
  * AgentRegistry so the queue-drain path (`onAgentAvailable` →
289
409
  * `dequeueForLabels`) and the eager-dispatch path
290
410
  * (`dispatchBoundJob` → `dequeueById`) both reject queued jobs whose
@@ -359,6 +479,29 @@ export declare class ScalerManager {
359
479
  * Firecracker backend's `getBridgeConfig()`).
360
480
  */
361
481
  getBackend(name: string): ScalerBackend | undefined;
482
+ /**
483
+ * Whether some configured backend could spawn capacity for this label set —
484
+ * the same `findBackendForLabels` match `requestScale` makes, asked without
485
+ * spawning anything.
486
+ *
487
+ * Read by the queue-expiry sweep to tell a fleet/label problem apart from a
488
+ * capacity one: a job whose labels no agent AND no backend can serve could
489
+ * never have run (`unroutable`), while a job whose backend matched but whose
490
+ * spawn kept failing is a provisioning/capacity problem (`timed_out_stale`),
491
+ * and mislabelling the latter would tell an operator to fix a `runsOn` that
492
+ * is perfectly correct.
493
+ *
494
+ * Exact labels only — the scaler's own routing (`requestScale`) matches on
495
+ * exact labels, so a regex `runsOn` matcher is not expressible here. On a
496
+ * scaler-configured orchestrator that makes the answer conservative for a
497
+ * pattern-only `runsOn`: a backend whose labelSets carry no mandatory labels
498
+ * matches the empty exact set, so such a job is reported routable and settles
499
+ * `timed_out_stale` rather than `unroutable`. That loses precision, never
500
+ * safety — the job is still terminal and the run still fails, which is the
501
+ * invariant that matters. Tightening it means teaching scaler routing about
502
+ * patterns, which would change where jobs actually spawn.
503
+ */
504
+ hasBackendForLabels(labels: string[], excludeLabels?: string[]): boolean;
362
505
  /**
363
506
  * Get scaler-specific configuration metadata for a managed agent.
364
507
  * Returns undefined for non-scaler-managed (static) agents.
@@ -370,10 +513,25 @@ export declare class ScalerManager {
370
513
  */
371
514
  start(): void;
372
515
  /**
373
- * Remove spawning entries older than 5 minutes.
374
- * These represent agents that were spawned but never registered via WS
375
- * (e.g., process/container crashed on startup). Without cleanup, these
376
- * entries would leak in spawningAgents forever.
516
+ * Provision/heal every backend's host prerequisites before spawning starts.
517
+ * Awaits each backend's optional ensureHostReady, catching per-backend so one
518
+ * scaler's host-prep failure degrades only that scaler (its spawns will fail
519
+ * with clear errors + the firecracker-network diagnostic reports it) rather
520
+ * than aborting orchestrator startup.
521
+ */
522
+ ensureHostsReady(): Promise<void>;
523
+ /**
524
+ * Remove spawning entries whose `backend.spawn` started more than 5 minutes
525
+ * ago but never registered via WS (e.g., process/container crashed on
526
+ * startup). Without cleanup, these entries would leak in spawningAgents
527
+ * forever.
528
+ *
529
+ * The window is measured from `spawnStartedAt` (when the throttled spawn
530
+ * actually began), NOT from `spawnedAt` (enqueue time): a spawn still waiting
531
+ * behind the per-backend spawn semaphore has not started and must not be
532
+ * reaped mid-queue during a large burst. Recovered orphan entries carry
533
+ * `spawnStartedAt` set to their persisted enqueue time, so they are subject to
534
+ * the normal window.
377
535
  */
378
536
  private pruneStaleSpawningEntries;
379
537
  private persistSpawningAgent;
@@ -0,0 +1,35 @@
1
+ export interface PendingScaleSweeperOptions {
2
+ /**
3
+ * Re-drive callback — the dispatcher's `retryPendingScaleRequests` bound to
4
+ * the `sweep` trigger. Returns the number of jobs re-driven (logged when > 0).
5
+ */
6
+ redrive: () => Promise<number>;
7
+ /** Sweep interval in milliseconds. */
8
+ intervalMs: number;
9
+ }
10
+ /**
11
+ * Leader-gated periodic backstop for the scaler capacity-freed re-drive.
12
+ *
13
+ * The capacity-freed hook (`ScalerManager.onCapacityFreed`) handles the common
14
+ * case with near-zero latency, but it can miss edge cases: a spawn that failed
15
+ * silently, a reservation freed on a non-leader coordinator, or a lost event.
16
+ * This sweeper re-runs the SAME `retryPendingScaleRequests` on a timer so a
17
+ * pending at-capacity job is never stranded past one interval.
18
+ *
19
+ * Modeled on `HostRosterReaper` / `EventRetryScanner`: started/stopped via the
20
+ * Raft leadership callbacks, a single timer cleared on `stop()`. Leader-only so
21
+ * multiple coordinators don't each drive the same queue.
22
+ */
23
+ export declare class PendingScaleSweeper {
24
+ private readonly redrive;
25
+ private readonly intervalMs;
26
+ private timer;
27
+ private isLeader;
28
+ constructor(opts: PendingScaleSweeperOptions);
29
+ onBecomeLeader(): void;
30
+ onLoseLeadership(): void;
31
+ stop(): void;
32
+ /** One sweep pass. Public for tests. Never throws (logs and keeps ticking). */
33
+ tick(): Promise<void>;
34
+ }
35
+ //# sourceMappingURL=pending-scale-sweeper.d.ts.map
@@ -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,30 @@
1
+ /**
2
+ * Shared factory for the dispatch-time `SecretResolver` bound to the orchestrator's
3
+ * DB-backed context/binding/secret stores.
4
+ *
5
+ * Both boot paths use it: `server.ts` (platform/hybrid) always builds it, and
6
+ * `standalone.ts` (independent) builds it only when dispatch-time context-scoped
7
+ * secret resolution is explicitly opted in (the local dev plane). Keeping the
8
+ * ~one construction in one place stops the two call sites from drifting.
9
+ */
10
+ import type { Kysely } from 'kysely';
11
+ import type { SecretStore } from '@kici-dev/engine';
12
+ import type { Logger } from '@kici-dev/shared';
13
+ import type { Database } from '../db/types.js';
14
+ import type { AuditLogger } from './audit-logger.js';
15
+ import type { PgSecretStore } from './pg-secret-store.js';
16
+ import { SecretResolver } from './secret-resolver.js';
17
+ export interface ContextSecretResolverDeps {
18
+ pgSecretStore: PgSecretStore;
19
+ backendStores: Map<string, SecretStore>;
20
+ db: Kysely<Database>;
21
+ auditLogger: AuditLogger;
22
+ logger: Logger;
23
+ }
24
+ /**
25
+ * Build a `SecretResolver` over the org's contexts, bindings, and registered
26
+ * secret backends. The `pg` backend decrypts through the master key; external
27
+ * backends (Vault) return plaintext, so their decrypt is identity.
28
+ */
29
+ export declare function buildContextSecretResolver(deps: ContextSecretResolverDeps): SecretResolver;
30
+ //# sourceMappingURL=context-secret-resolver.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
@@ -9,7 +9,7 @@ export { AuditLogger } from './audit-logger.js';
9
9
  export { loadMasterKey, loadOldMasterKey, loadSecretStoreConfig, type SecretStoreConfig, } from './config.js';
10
10
  export { encrypt, decrypt, deriveKey, generateMasterKey, type EncryptedValue, } from '@kici-dev/shared';
11
11
  export { VaultSecretStore, type VaultConfig } from './vault-secret-store.js';
12
- export { SecretResolver, type SecretResolverDeps, type ResolvedSecretMeta, type EnvironmentStoreLike, type BindingStoreLike, type SecretStoreLike, } from './secret-resolver.js';
12
+ export { SecretResolver, type SecretResolverDeps, type ResolvedSecretMeta, type ContextStoreLike, type BindingStoreLike, type SecretStoreLike, } from './secret-resolver.js';
13
13
  export { BackendSyncManager } from './backend-sync.js';
14
14
  export { RbacEnforcer, PermissionDeniedError, type Role, type Permission } from './rbac.js';
15
15
  export { TokenManager } from './token-manager.js';
@@ -12,13 +12,23 @@ import type { SecretStore } from '@kici-dev/engine';
12
12
  import type { AuditLogger } from './audit-logger.js';
13
13
  /**
14
14
  * Thrown by `renameScope` when the named scope has no secret rows and no
15
- * environment binding — i.e. there is nothing to rename. Consumers map this to
15
+ * context binding — i.e. there is nothing to rename. Consumers map this to
16
16
  * a 404 (admin HTTP route) or a structured not-found response (dashboard path).
17
17
  */
18
18
  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).
@@ -93,11 +103,11 @@ export declare class PgSecretStore implements SecretStore {
93
103
  */
94
104
  createScope(orgId: string, scope: string): Promise<void>;
95
105
  /**
96
- * Rename a scope -- atomically update scoped_secrets and environment_bindings.
106
+ * Rename a scope -- atomically update scoped_secrets and context_bindings.
97
107
  */
98
108
  renameScope(orgId: string, oldScope: string, newScope: string): Promise<void>;
99
109
  /**
100
- * Delete a scope and all its secrets, plus any environment bindings referencing it.
110
+ * Delete a scope and all its secrets, plus any context bindings referencing it.
101
111
  */
102
112
  deleteScope(orgId: string, scope: string): Promise<void>;
103
113
  /**
@@ -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' | '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
  */