okengine 0.10.2 → 0.11.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 (343) hide show
  1. package/package.json +76 -10
  2. package/site/content/docs/ai/mcp.mdx +0 -1
  3. package/site/content/docs/deployment/docker-swarm.mdx +48 -111
  4. package/site/content/docs/deployment/docker.mdx +43 -36
  5. package/site/content/docs/deployment/index.mdx +9 -9
  6. package/site/content/docs/deployment/kubernetes.mdx +4 -4
  7. package/site/content/docs/elements/ai.mdx +7 -13
  8. package/site/content/docs/elements/channel.mdx +9 -13
  9. package/site/content/docs/elements/clock.mdx +8 -14
  10. package/site/content/docs/elements/flow.mdx +46 -54
  11. package/site/content/docs/elements/gate.mdx +6 -11
  12. package/site/content/docs/elements/signal.mdx +2 -8
  13. package/site/content/docs/elements/store.mdx +79 -93
  14. package/site/content/docs/elements/vault.mdx +89 -76
  15. package/site/content/docs/get-started/basic-usage.mdx +8 -14
  16. package/site/content/docs/get-started/installation.mdx +36 -36
  17. package/site/content/docs/get-started/introduction.mdx +11 -0
  18. package/site/content/docs/get-started/why.mdx +3 -4
  19. package/site/content/docs/index.mdx +0 -1
  20. package/site/content/docs/meta.json +0 -1
  21. package/site/content/docs/plugins/anonymous.mdx +1 -1
  22. package/site/content/docs/plugins/magic-link.mdx +11 -11
  23. package/site/content/docs/plugins/otp.mdx +2 -2
  24. package/site/content/docs/plugins/passkey.mdx +1 -1
  25. package/site/content/docs/plugins/two-factor.mdx +1 -1
  26. package/site/content/docs/plugins/username.mdx +1 -1
  27. package/site/content/docs/recipes/caddy.mdx +1 -1
  28. package/site/content/docs/recipes/cockroachdb.mdx +2 -2
  29. package/site/content/docs/recipes/dragonfly.mdx +1 -1
  30. package/site/content/docs/recipes/index.mdx +1 -2
  31. package/site/content/docs/recipes/llama-cpp.mdx +21 -23
  32. package/site/content/docs/recipes/mailpit.mdx +11 -11
  33. package/site/content/docs/recipes/meilisearch.mdx +10 -10
  34. package/site/content/docs/recipes/meta.json +0 -1
  35. package/site/content/docs/recipes/ollama.mdx +1 -1
  36. package/site/content/docs/recipes/pgdog.mdx +12 -9
  37. package/site/content/docs/recipes/postgres.mdx +3 -3
  38. package/site/content/docs/recipes/redis.mdx +2 -2
  39. package/site/content/docs/recipes/rustfs.mdx +10 -7
  40. package/site/content/docs/recipes/sglang.mdx +1 -1
  41. package/site/content/docs/recipes/supabase-docker.mdx +1 -1
  42. package/site/content/docs/recipes/timescale.mdx +2 -2
  43. package/site/content/docs/recipes/valkey.mdx +1 -1
  44. package/site/content/docs/recipes/vllm.mdx +1 -1
  45. package/site/content/docs/recipes/yugabytedb.mdx +2 -2
  46. package/site/content/docs/reference/cli.md +61 -38
  47. package/site/content/docs/reference/configuration.mdx +145 -70
  48. package/site/content/docs/reference/environment-variables.mdx +36 -28
  49. package/site/content/docs/reference/errors.mdx +28 -29
  50. package/site/content/docs/reference/fx.mdx +14 -7
  51. package/site/content/docs/reference/i18n.mdx +17 -6
  52. package/site/content/docs/reference/index.mdx +5 -0
  53. package/site/content/docs/reference/meta.json +1 -0
  54. package/site/content/docs/reference/migrating-environments.mdx +158 -0
  55. package/site/content/docs/reference/plugins.mdx +2 -2
  56. package/src/auth/gate-auth.test.ts +12 -10
  57. package/src/cli/ai-setup/ai-setup.test.ts +30 -16
  58. package/src/cli/ai-setup/apply.ts +111 -15
  59. package/src/cli/ai-setup/catalog.ts +3 -3
  60. package/src/cli/ai-setup/index.ts +1 -1
  61. package/src/cli/ai-setup/prompts.ts +1 -1
  62. package/src/cli/ai-setup/recommend.test.ts +1 -1
  63. package/src/cli/ask-seed.test.ts +3 -3
  64. package/src/cli/build.ts +8 -9
  65. package/src/cli/db-auto-push.test.ts +6 -3
  66. package/src/cli/db-auto-push.ts +7 -5
  67. package/src/cli/db-seed.ts +7 -8
  68. package/src/cli/db.test.ts +70 -71
  69. package/src/cli/db.ts +86 -12
  70. package/src/cli/dev-controller.test.ts +35 -0
  71. package/src/cli/dev-controller.ts +298 -0
  72. package/src/cli/dev-controls.ts +11 -65
  73. package/src/cli/dev-db-push.test.ts +47 -15
  74. package/src/cli/dev-schema-sync.test.ts +11 -11
  75. package/src/cli/dev-schema-sync.ts +10 -10
  76. package/src/cli/dev-session-lock.test.ts +106 -0
  77. package/src/cli/dev-session-lock.ts +209 -0
  78. package/src/cli/dev.test.ts +246 -114
  79. package/src/cli/dev.ts +153 -205
  80. package/src/cli/doc-staleness.test.ts +3 -6
  81. package/src/cli/docker-clean.test.ts +33 -1
  82. package/src/cli/docker-clean.ts +28 -33
  83. package/src/cli/docker-cli.test.ts +12 -11
  84. package/src/cli/docker.ts +95 -20
  85. package/src/cli/doctor.test.ts +40 -0
  86. package/src/cli/doctor.ts +142 -9
  87. package/src/cli/drizzle-env.test.ts +11 -13
  88. package/src/cli/drizzle-env.ts +18 -11
  89. package/src/cli/ensure-drizzle-config.ts +11 -14
  90. package/src/cli/hero-meta.test.ts +15 -15
  91. package/src/cli/hero-meta.ts +10 -9
  92. package/src/cli/index.ts +36 -6
  93. package/src/cli/load-config.images.test.ts +44 -10
  94. package/src/cli/load-config.source.test.ts +50 -0
  95. package/src/cli/load-config.ts +35 -29
  96. package/src/cli/meilisearch-local.ts +1 -2
  97. package/src/cli/mode.ts +7 -58
  98. package/src/cli/registry.ts +175 -19
  99. package/src/cli/resolve-dev-sql-env.test.ts +8 -16
  100. package/src/cli/resolve-dev-sql-env.ts +13 -15
  101. package/src/cli/safe-defaults.test.ts +29 -11
  102. package/src/cli/schema.ts +65 -16
  103. package/src/cli/test.ts +58 -0
  104. package/src/cli/tui/App.tsx +252 -0
  105. package/src/cli/tui/DevLive.tsx +116 -0
  106. package/src/cli/tui/components/ConfirmDialog.tsx +48 -0
  107. package/src/cli/tui/components/HeaderBar.tsx +67 -0
  108. package/src/cli/tui/components/LogStream.tsx +47 -0
  109. package/src/cli/tui/components/PanelCard.tsx +39 -0
  110. package/src/cli/tui/components/SelectRow.tsx +37 -0
  111. package/src/cli/tui/components/SlashPalette.tsx +172 -0
  112. package/src/cli/tui/components/Spinner.tsx +32 -0
  113. package/src/cli/tui/components/StatusBar.tsx +51 -0
  114. package/src/cli/tui/components/StatusDot.tsx +37 -0
  115. package/src/cli/tui/components/TabBar.tsx +49 -0
  116. package/src/cli/tui/components/Wordmark.tsx +43 -0
  117. package/src/cli/tui/format.ts +38 -0
  118. package/src/cli/tui/keys.test.ts +18 -0
  119. package/src/cli/tui/keys.ts +26 -0
  120. package/src/cli/tui/launch.test.ts +18 -0
  121. package/src/cli/tui/launch.ts +57 -0
  122. package/src/cli/tui/panels/Dashboard.tsx +201 -0
  123. package/src/cli/tui/panels/Database.tsx +198 -0
  124. package/src/cli/tui/panels/Dev.tsx +257 -0
  125. package/src/cli/tui/panels/Docker.tsx +357 -0
  126. package/src/cli/tui/panels/Navigator.test.ts +22 -0
  127. package/src/cli/tui/panels/Navigator.tsx +213 -0
  128. package/src/cli/tui/slash-catalog.test.ts +31 -0
  129. package/src/cli/tui/slash-catalog.ts +184 -0
  130. package/src/cli/tui/slash-run.ts +54 -0
  131. package/src/cli/tui/state/ports.ts +95 -0
  132. package/src/cli/tui/theme.ts +24 -0
  133. package/src/cli/vault-cmd.test.ts +402 -0
  134. package/src/cli/vault-cmd.ts +727 -69
  135. package/src/cli/vault-secure-input.test.ts +56 -0
  136. package/src/cli/vault-secure-input.ts +124 -0
  137. package/src/compiler/effects-infer.ts +7 -0
  138. package/src/compiler/extract.ts +12 -0
  139. package/src/compiler/fixtures/skyport/oke.config.ts +7 -5
  140. package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -1
  141. package/src/compiler/fixtures/skyport.expected.json +1 -1
  142. package/src/compiler/generate-adopt.ts +27 -1
  143. package/src/compiler-entry.ts +7 -0
  144. package/src/config/define-config.test.ts +111 -47
  145. package/src/config/driver-defaults.test.ts +115 -0
  146. package/src/config/driver-defaults.ts +156 -0
  147. package/src/config/index.ts +246 -131
  148. package/src/config/resolve-driver.test.ts +14 -19
  149. package/src/console/server/app.ts +4 -2
  150. package/src/console/server/console.test.ts +58 -1
  151. package/src/console/server/flows.ts +22 -2
  152. package/src/console/server/index.ts +3 -0
  153. package/src/console/server/operator-db.test.ts +55 -13
  154. package/src/console/server/operator-db.ts +305 -263
  155. package/src/console/server/serve.ts +16 -7
  156. package/src/console/server/state.ts +31 -9
  157. package/src/console/server/vault.test.ts +120 -5
  158. package/src/console/server/vault.ts +208 -12
  159. package/src/console/ui/dist/assets/{index-D-9KFce5.js → index--Y0Uaz-m.js} +2 -2
  160. package/src/console/ui/dist/assets/panel-vault-BkZdJPX8.js +1 -0
  161. package/src/console/ui/dist/assets/style-C3L349iZ.css +3 -0
  162. package/src/console/ui/dist/index.html +2 -2
  163. package/src/console/ui/shell/client.ts +16 -0
  164. package/src/console/ui/shell/panels/vault/VaultPanel.tsx +54 -1
  165. package/src/console/ui/vault/VaultA11yView.tsx +33 -1
  166. package/src/console/ui/vault/backend.test.ts +75 -0
  167. package/src/console/ui/vault/backend.ts +117 -0
  168. package/src/console/ui/vault/fixture.ts +21 -2
  169. package/src/console/ui/vault/index.ts +11 -1
  170. package/src/console/ui/vault/types.ts +26 -0
  171. package/src/docker/compose.ts +164 -61
  172. package/src/docker/derive.ts +106 -12
  173. package/src/docker/docker.test.ts +156 -110
  174. package/src/docker/helpers.ts +98 -0
  175. package/src/docker/images-config.test.ts +163 -0
  176. package/src/docker/index.ts +30 -5
  177. package/src/docker/recipes/index.ts +0 -3
  178. package/src/docker/recipes/llama-cpp.ts +4 -4
  179. package/src/docker/recipes/pgdog.ts +9 -2
  180. package/src/docker/resources.test.ts +71 -0
  181. package/src/docker/resources.ts +176 -0
  182. package/src/docker/stack-id.test.ts +11 -4
  183. package/src/docker/stack-id.ts +42 -32
  184. package/src/docker/stack.integration.test.ts +4 -15
  185. package/src/docker/types.ts +35 -3
  186. package/src/drivers/ai-ollama.integration.test.ts +2 -2
  187. package/src/drivers/conformance.test.ts +11 -12
  188. package/src/drivers/drizzle-dialect.test.ts +0 -4
  189. package/src/drivers/drizzle-dialect.ts +7 -13
  190. package/src/drivers/index.ts +24 -7
  191. package/src/drivers/journal-postgres.test.ts +3 -1
  192. package/src/drivers/journal-postgres.ts +4 -2
  193. package/src/drivers/meilisearch.ts +1 -1
  194. package/src/drivers/pglite.ts +28 -5
  195. package/src/drivers/types.ts +9 -11
  196. package/src/drivers/vault-aws-secrets-manager.test.ts +159 -0
  197. package/src/drivers/vault-aws-secrets-manager.ts +333 -0
  198. package/src/drivers/vault-builtin.test.ts +110 -0
  199. package/src/drivers/vault-builtin.ts +184 -0
  200. package/src/drivers/vault-driver-removal.test.ts +13 -0
  201. package/src/drivers/vault-managed.test.ts +95 -0
  202. package/src/drivers/vault-managed.ts +101 -25
  203. package/src/drivers/vault-types.ts +25 -5
  204. package/src/elements/ai/runtime.ts +1 -1
  205. package/src/elements/clock/chaos.test.ts +4 -1
  206. package/src/elements/clock/durable.ts +57 -4
  207. package/src/elements/clock.test.ts +13 -14
  208. package/src/elements/gate/constants.ts +18 -0
  209. package/src/elements/gate.test.ts +1 -1
  210. package/src/elements/gate.ts +2 -2
  211. package/src/elements/store/domain-ddl.test.ts +5 -12
  212. package/src/elements/store/emit-drizzle.ts +44 -19
  213. package/src/elements/store/index-boot.test.ts +15 -116
  214. package/src/elements/store/load-plugin-tables.ts +1 -1
  215. package/src/elements/store/resource-list-docs.fixture.ts +12 -6
  216. package/src/elements/store/resource-list-docs.test.ts +64 -44
  217. package/src/elements/store/resource.test.ts +17 -10
  218. package/src/elements/store/runtime.ts +9 -12
  219. package/src/elements/store/schema-decl.test.ts +16 -32
  220. package/src/elements/store/seed.test.ts +1 -2
  221. package/src/elements/store/seed.ts +7 -8
  222. package/src/elements/store/sql-condition.test.ts +2 -2
  223. package/src/elements/store/sql-session.test.ts +8 -10
  224. package/src/elements/store/sql-session.ts +10 -2
  225. package/src/elements/store.test.ts +13 -13
  226. package/src/elements/vault/audit.ts +233 -0
  227. package/src/elements/vault/boot-chain.test.ts +78 -0
  228. package/src/elements/vault/boot-chain.ts +43 -39
  229. package/src/elements/vault/builtin-adapter.test.ts +479 -0
  230. package/src/elements/vault/builtin-adapter.ts +1184 -0
  231. package/src/elements/vault/crypto.test.ts +237 -0
  232. package/src/elements/vault/crypto.ts +431 -0
  233. package/src/elements/vault/declare.ts +164 -3
  234. package/src/elements/vault/errors.ts +56 -0
  235. package/src/elements/vault/kms-unseal.test.ts +76 -0
  236. package/src/elements/vault/kms-unseal.ts +181 -0
  237. package/src/elements/vault/path.ts +90 -0
  238. package/src/elements/vault/resilience.test.ts +102 -0
  239. package/src/elements/vault/resilience.ts +107 -0
  240. package/src/elements/vault/runtime.ts +36 -4
  241. package/src/elements/vault/security-checklist.test.ts +130 -0
  242. package/src/elements/vault/storage.ts +448 -0
  243. package/src/elements/vault/types.ts +288 -0
  244. package/src/elements/vault/unseal.ts +150 -0
  245. package/src/elements/vault.test.ts +72 -4
  246. package/src/elements/vault.ts +91 -2
  247. package/src/full.ts +248 -0
  248. package/src/http.ts +41 -0
  249. package/src/i18n/interpolate-simple.ts +37 -0
  250. package/src/i18n/messages.ts +51 -4
  251. package/src/i18n-entry.ts +7 -0
  252. package/src/index.ts +35 -145
  253. package/src/journal-entry.ts +20 -0
  254. package/src/kernel/adopt-barrel-fresh.test.ts +25 -10
  255. package/src/kernel/app.ts +40 -42
  256. package/src/kernel/auto-registry.test.ts +2 -2
  257. package/src/kernel/boot-bind/ai.test.ts +5 -5
  258. package/src/kernel/boot-bind/ai.ts +2 -1
  259. package/src/kernel/boot-bind/channel.test.ts +6 -6
  260. package/src/kernel/boot-bind/channel.ts +5 -4
  261. package/src/kernel/boot-bind/clock.ts +5 -5
  262. package/src/kernel/boot-bind/gate.ts +6 -7
  263. package/src/kernel/boot-bind/honor-config.test.ts +42 -42
  264. package/src/kernel/boot-bind/journal.ts +5 -5
  265. package/src/kernel/boot-bind/signal.ts +3 -1
  266. package/src/kernel/boot-bind/store.test.ts +55 -37
  267. package/src/kernel/boot-bind/store.ts +24 -34
  268. package/src/kernel/boot-bind/vault.ts +19 -4
  269. package/src/kernel/boot.test.ts +12 -4
  270. package/src/kernel/boot.ts +31 -19
  271. package/src/kernel/budget-entry.ts +1 -1
  272. package/src/kernel/compensate.test.ts +288 -1
  273. package/src/kernel/compensate.ts +126 -0
  274. package/src/kernel/concurrency.test.ts +10 -9
  275. package/src/kernel/effects-stamping.test.ts +27 -2
  276. package/src/kernel/element-registries.ts +5 -3
  277. package/src/kernel/flow.ts +4 -2
  278. package/src/kernel/fx.test.ts +119 -3
  279. package/src/kernel/fx.ts +215 -40
  280. package/src/kernel/index.ts +14 -0
  281. package/src/kernel/journal.ts +130 -7
  282. package/src/kernel/pipeline.test.ts +20 -6
  283. package/src/kernel/redacted.test.ts +35 -0
  284. package/src/kernel/redacted.ts +24 -2
  285. package/src/kernel/router/create-default.ts +16 -0
  286. package/src/kernel/router/create-edge.ts +18 -0
  287. package/src/kernel/router/create.ts +23 -0
  288. package/src/kernel/router/index.ts +23 -0
  289. package/src/kernel/router/linear.ts +88 -0
  290. package/src/kernel/router/regexp.ts +188 -0
  291. package/src/kernel/router/smart.ts +120 -0
  292. package/src/kernel/router/trie.ts +108 -0
  293. package/src/kernel/router/types.ts +56 -0
  294. package/src/kernel/router.ts +18 -532
  295. package/src/kernel-entry.ts +43 -0
  296. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  297. package/src/manifest/fixtures/skyport.manifest.json +1 -1
  298. package/src/plugins/config-source.test.ts +7 -7
  299. package/src/release/build-lib.ts +58 -0
  300. package/src/release/exports.test.ts +4 -2
  301. package/src/release/exports.ts +30 -4
  302. package/src/release/measure.ts +101 -22
  303. package/src/runs/duckdb.ts +7 -2
  304. package/src/shared/optional-peer.ts +41 -0
  305. package/src/term.test.ts +3 -44
  306. package/src/test/create-test-app.ts +12 -0
  307. package/src/test/provisions.integration.test.ts +1 -1
  308. package/src/test/reset-element-registries.ts +2 -0
  309. package/src/upgrade/codemods.test.ts +7 -20
  310. package/src/upgrade/codemods.ts +93 -60
  311. package/site/content/docs/console/access.mdx +0 -29
  312. package/site/content/docs/console/ai.mdx +0 -35
  313. package/site/content/docs/console/architecture.mdx +0 -35
  314. package/site/content/docs/console/channels.mdx +0 -37
  315. package/site/content/docs/console/clock.mdx +0 -51
  316. package/site/content/docs/console/flows.mdx +0 -31
  317. package/site/content/docs/console/gates.mdx +0 -73
  318. package/site/content/docs/console/index.mdx +0 -54
  319. package/site/content/docs/console/manifest-diff.mdx +0 -34
  320. package/site/content/docs/console/meta.json +0 -24
  321. package/site/content/docs/console/overview.mdx +0 -40
  322. package/site/content/docs/console/plugins.mdx +0 -41
  323. package/site/content/docs/console/privacy.mdx +0 -32
  324. package/site/content/docs/console/runs.mdx +0 -50
  325. package/site/content/docs/console/signals.mdx +0 -40
  326. package/site/content/docs/console/store.mdx +0 -32
  327. package/site/content/docs/console/tenancy.mdx +0 -32
  328. package/site/content/docs/console/traces.mdx +0 -38
  329. package/site/content/docs/console/vault.mdx +0 -41
  330. package/site/content/docs/recipes/openbao.mdx +0 -141
  331. package/src/cli/ask-dev-mode.ts +0 -40
  332. package/src/cli/dev-mode.test.ts +0 -45
  333. package/src/cli/dev-mode.ts +0 -78
  334. package/src/cli/openbao-bootstrap.test.ts +0 -150
  335. package/src/cli/openbao-bootstrap.ts +0 -321
  336. package/src/cli/openbao-restart.integration.test.ts +0 -145
  337. package/src/console/ui/dist/assets/panel-vault-Za1GyJfM.js +0 -1
  338. package/src/console/ui/dist/assets/style-C8MxEWPd.css +0 -3
  339. package/src/docker/recipes/openbao.ts +0 -47
  340. package/src/drivers/libsql.ts +0 -179
  341. package/src/drivers/sqlite.ts +0 -44
  342. package/src/drivers/vault-openbao.test.ts +0 -97
  343. package/src/drivers/vault-openbao.ts +0 -143
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Vault audit trail — a tamper-evident hash chain of *operations*.
3
+ *
4
+ * An audit row records that something happened to a path, never what the
5
+ * value was. Each row hashes its own payload together with the previous
6
+ * row's hash, so removing or editing a row breaks every hash after it
7
+ * (`verifyAuditChain` in `storage.ts` walks the chain).
8
+ */
9
+
10
+ import { VaultError } from "./errors.ts";
11
+ import type { VaultErrorCode } from "./errors.ts";
12
+ import type { VaultActorType } from "./types.ts";
13
+ import type { VaultAuditSinkKind } from "./types.ts";
14
+
15
+ /** Operations recorded in the audit chain. */
16
+ export type AuditAction =
17
+ | "get"
18
+ | "set"
19
+ | "delete"
20
+ | "rotate"
21
+ | "list"
22
+ | "seal"
23
+ | "unseal"
24
+ | "initialize"
25
+ | "rewrap"
26
+ | "purge";
27
+
28
+ /** Hash-chain genesis marker used for the first row. */
29
+ export const AUDIT_GENESIS_HASH = "genesis";
30
+
31
+ /** One operation to append to the chain. */
32
+ export interface AuditEntry {
33
+ /** What happened. */
34
+ readonly action: AuditAction;
35
+ /** Canonical path, when the operation targets one. */
36
+ readonly path?: string;
37
+ /** Actor class. */
38
+ readonly actorType: VaultActorType;
39
+ /** Actor id within its class. */
40
+ readonly actorId?: string;
41
+ /** Whether the operation succeeded. */
42
+ readonly success: boolean;
43
+ /** Failure reason when `success` is `false`. */
44
+ readonly errorCode?: VaultErrorCode;
45
+ /** Safe, secret-free failure description. */
46
+ readonly errorMessage?: string;
47
+ /** Correlation id for the enclosing request/run. */
48
+ readonly requestId?: string;
49
+ /** Event time. Defaults to now at append time. */
50
+ readonly at?: Date;
51
+ }
52
+
53
+ /**
54
+ * Exact field set covered by a row hash.
55
+ *
56
+ * Normalized (`null` rather than `undefined`, ISO-8601 timestamps) so a row
57
+ * read back from SQL hashes identically to the row that was written.
58
+ */
59
+ export interface AuditHashPayload {
60
+ /** What happened. */
61
+ readonly action: AuditAction;
62
+ /** Canonical path or `null`. */
63
+ readonly path: string | null;
64
+ /** Actor class. */
65
+ readonly actorType: VaultActorType;
66
+ /** Actor id or `null`. */
67
+ readonly actorId: string | null;
68
+ /** Whether the operation succeeded. */
69
+ readonly success: boolean;
70
+ /** Failure reason or `null`. */
71
+ readonly errorCode: VaultErrorCode | null;
72
+ /** Failure description or `null`. */
73
+ readonly errorMessage: string | null;
74
+ /** Correlation id or `null`. */
75
+ readonly requestId: string | null;
76
+ /** ISO-8601 event time. */
77
+ readonly createdAt: string;
78
+ }
79
+
80
+ /** Destination for audit rows. */
81
+ export interface AuditSink {
82
+ /** Sink kind, mirroring the configured `audit.sink`. */
83
+ readonly kind: VaultAuditSinkKind;
84
+ /**
85
+ * Append one operation.
86
+ *
87
+ * @param entry - Operation to record
88
+ */
89
+ append(entry: AuditEntry): Promise<void>;
90
+ /** Release sink resources, if any. */
91
+ close?(): Promise<void>;
92
+ }
93
+
94
+ /**
95
+ * Backend-side audit writer.
96
+ *
97
+ * `storage.ts` implements this over `oke_vault_audit`; the `db` sink is a
98
+ * thin adapter so the audit module never imports SQL.
99
+ */
100
+ export interface AuditWriter {
101
+ /**
102
+ * Persist one operation, computing and linking its row hash.
103
+ *
104
+ * @param entry - Operation to record
105
+ */
106
+ appendAuditEntry(entry: AuditEntry): Promise<void>;
107
+ }
108
+
109
+ /** Options accepted by {@link createAuditSink}. */
110
+ export interface CreateAuditSinkOptions {
111
+ /** Required for the `db` sink. */
112
+ readonly writer?: AuditWriter;
113
+ /** Required for the `webhook` sink (not yet implemented). */
114
+ readonly webhookUrl?: string;
115
+ /** Line writer for the `stdout` sink (tests). */
116
+ readonly write?: (line: string) => void;
117
+ /** Clock for `stdout` timestamps (tests). */
118
+ readonly now?: () => Date;
119
+ }
120
+
121
+ /**
122
+ * Normalize an entry into the exact fields a row hash covers.
123
+ *
124
+ * @param entry - Operation to record
125
+ * @param createdAt - Event time
126
+ */
127
+ export function toAuditHashPayload(entry: AuditEntry, createdAt: Date): AuditHashPayload {
128
+ return {
129
+ action: entry.action,
130
+ path: entry.path ?? null,
131
+ actorType: entry.actorType,
132
+ actorId: entry.actorId ?? null,
133
+ success: entry.success,
134
+ errorCode: entry.errorCode ?? null,
135
+ errorMessage: entry.errorMessage ?? null,
136
+ requestId: entry.requestId ?? null,
137
+ createdAt: createdAt.toISOString(),
138
+ };
139
+ }
140
+
141
+ /**
142
+ * Hash one audit row into the chain.
143
+ *
144
+ * Fields are joined with NUL in a fixed order — no JSON key-order or
145
+ * whitespace ambiguity — and prefixed with the previous row's hash.
146
+ *
147
+ * @param prevHash - Previous row hash, or `null` / {@link AUDIT_GENESIS_HASH} for the first row
148
+ * @param payload - Normalized row fields
149
+ * @returns Lowercase hex SHA-256 digest
150
+ */
151
+ export async function computeAuditRowHash(
152
+ prevHash: string | null,
153
+ payload: AuditHashPayload,
154
+ ): Promise<string> {
155
+ const parts = [
156
+ "oke-vault-audit-v1",
157
+ prevHash ?? AUDIT_GENESIS_HASH,
158
+ payload.action,
159
+ payload.path ?? "",
160
+ payload.actorType,
161
+ payload.actorId ?? "",
162
+ payload.success ? "1" : "0",
163
+ payload.errorCode ?? "",
164
+ payload.errorMessage ?? "",
165
+ payload.requestId ?? "",
166
+ payload.createdAt,
167
+ ];
168
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(parts.join("\0")));
169
+ return Buffer.from(new Uint8Array(digest)).toString("hex");
170
+ }
171
+
172
+ /**
173
+ * Build an audit sink.
174
+ *
175
+ * - `db` delegates to an {@link AuditWriter} supplied by storage.
176
+ * - `stdout` writes one secret-free JSON line per operation.
177
+ * - `webhook` is not implemented yet and throws `UNSUPPORTED`.
178
+ *
179
+ * @param kind - Sink kind from `audit.sink`
180
+ * @param opts - Writer / webhook URL / test seams
181
+ * @throws VaultError `UNSUPPORTED` for `webhook`, or `MISSING_PEER` when `db` has no writer
182
+ */
183
+ export function createAuditSink(
184
+ kind: VaultAuditSinkKind,
185
+ opts: CreateAuditSinkOptions = {},
186
+ ): AuditSink {
187
+ if (kind === "webhook") {
188
+ throw new VaultError("UNSUPPORTED", "vault: webhook audit sink is not implemented");
189
+ }
190
+
191
+ if (kind === "db") {
192
+ const writer = opts.writer;
193
+ if (!writer) {
194
+ throw new VaultError("MISSING_PEER", "vault: db audit sink requires a storage writer");
195
+ }
196
+ return {
197
+ kind: "db",
198
+ append(entry) {
199
+ return writer.appendAuditEntry(entry);
200
+ },
201
+ };
202
+ }
203
+
204
+ const write = opts.write ?? ((line: string) => void process.stdout.write(`${line}\n`));
205
+ const now = opts.now ?? (() => new Date());
206
+ return {
207
+ kind: "stdout",
208
+ async append(entry) {
209
+ // Only normalized metadata is serialized — an entry never holds a value.
210
+ write(
211
+ JSON.stringify({
212
+ sink: "oke.vault.audit",
213
+ ...toAuditHashPayload(entry, entry.at ?? now()),
214
+ }),
215
+ );
216
+ },
217
+ };
218
+ }
219
+
220
+ /**
221
+ * Sink that drops every entry (`audit.enabled: false`).
222
+ *
223
+ * Reports `kind: "stdout"` because {@link VaultAuditSinkKind} has no
224
+ * "off" member — callers gate on config, not on this field.
225
+ */
226
+ export function createNullAuditSink(): AuditSink {
227
+ return {
228
+ kind: "stdout",
229
+ async append() {
230
+ // Intentionally empty — auditing is disabled.
231
+ },
232
+ };
233
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Vault boot chain — managed provider wiring and driver-id normalization.
3
+ */
4
+
5
+ import { afterEach, describe, expect, test } from "bun:test";
6
+ import type { VaultOpenOptions } from "../../drivers/vault-types.ts";
7
+ import { buildVaultBootChain, normalizeVaultDriverId } from "./boot-chain.ts";
8
+
9
+ /** Env keys these tests own. */
10
+ const OWNED = [
11
+ "OKE_VAULT_PROVIDER",
12
+ "OKE_VAULT_URL",
13
+ "OKE_VAULT_TOKEN",
14
+ "OKE_VAULT_MOUNT",
15
+ "OKE_VAULT_REGION",
16
+ ] as const;
17
+
18
+ afterEach(() => {
19
+ for (const key of OWNED) delete process.env[key];
20
+ });
21
+
22
+ describe("managed vault boot chain", () => {
23
+ test("no provider stays a single platform-injected layer", () => {
24
+ const chain = buildVaultBootChain({ driverId: "managed", env: "test", seed: { A: "1" } });
25
+ expect(chain).toHaveLength(1);
26
+ expect(chain[0]?.driver.id).toBe("managed");
27
+ });
28
+
29
+ test("a provider puts the env layers in front of the managed layer", () => {
30
+ process.env.OKE_VAULT_PROVIDER = "aws-secrets-manager";
31
+ process.env.OKE_VAULT_REGION = "eu-central-1";
32
+ process.env.OKE_VAULT_MOUNT = "oke/prod/";
33
+
34
+ const chain = buildVaultBootChain({ driverId: "managed", env: "prod" });
35
+ expect(chain[0]?.driver.id).toBe("env");
36
+ const last = chain.at(-1);
37
+ expect(last?.driver.id).toBe("managed");
38
+ const options = last?.options as VaultOpenOptions;
39
+ expect(options.provider).toBe("aws-secrets-manager");
40
+ expect(options.region).toBe("eu-central-1");
41
+ expect(options.mount).toBe("oke/prod/");
42
+ });
43
+
44
+ test("aws-secrets-manager carries region and prefix without inventing a mount", () => {
45
+ process.env.OKE_VAULT_PROVIDER = "aws-secrets-manager";
46
+ process.env.OKE_VAULT_REGION = "eu-central-1";
47
+
48
+ const chain = buildVaultBootChain({ driverId: "managed", env: "prod" });
49
+ const options = chain.at(-1)?.options as VaultOpenOptions;
50
+ expect(options.region).toBe("eu-central-1");
51
+ expect(options.mount).toBeUndefined();
52
+ });
53
+
54
+ test("built-in vault sits behind env layers", () => {
55
+ const chain = buildVaultBootChain({ driverId: "vault", env: "prod" });
56
+ expect(chain.map((l) => l.driver.id)).toContain("env");
57
+ expect(chain.at(-1)?.driver.id).toBe("vault");
58
+ });
59
+ });
60
+
61
+ describe("normalizeVaultDriverId", () => {
62
+ test("maps legacy labels onto protocol ids", () => {
63
+ expect(normalizeVaultDriverId("dotenv")).toBe("env");
64
+ expect(normalizeVaultDriverId("builtin")).toBe("vault");
65
+ expect(normalizeVaultDriverId("managed")).toBe("managed");
66
+ expect(normalizeVaultDriverId("vault")).toBe("vault");
67
+ });
68
+
69
+ test("rejects an unknown label", () => {
70
+ expect(() => normalizeVaultDriverId("acme")).toThrow(/unknown vault driver/);
71
+ });
72
+
73
+ test("rejects removed external vault driver id", () => {
74
+ const removed = ["open", "bao"].join("");
75
+ expect(() => normalizeVaultDriverId(removed)).toThrow(/unknown vault driver/);
76
+ expect(() => normalizeVaultDriverId(removed)).toThrow(/aws-secrets-manager/);
77
+ });
78
+ });
@@ -2,17 +2,17 @@
2
2
  * Shared Vault resolution-chain assembly for app boot and Console.
3
3
  *
4
4
  * Order (first hit wins): process.env → .env.local → compose .env.docker →
5
- * backend layer (`env` seed / openbao / memory / managed).
5
+ * backend layer (`env` seed / vault / memory / managed).
6
6
  */
7
7
 
8
8
  import { existsSync, readFileSync } from "node:fs";
9
9
  import { resolve } from "node:path";
10
10
  import type { ConfigEnv } from "../../config/index.ts";
11
11
  import {
12
+ builtinVaultDriver,
12
13
  envVaultDriver,
13
14
  managedVaultDriver,
14
15
  memoryVaultDriver,
15
- openbaoVaultDriver,
16
16
  } from "../../drivers/index.ts";
17
17
  import { parseDotenv } from "../../drivers/vault-dotenv-parse.ts";
18
18
  import type { VaultDriverId } from "../../drivers/vault-types.ts";
@@ -25,32 +25,30 @@ export interface BuildVaultBootChainOptions {
25
25
  readonly cwd?: string;
26
26
  /** Resolved `drivers.vault` id for the active env. */
27
27
  readonly driverId: VaultDriverId;
28
- /** Active config env — controls fail-loud vs soft fallback for openbao. */
28
+ /** Active config env. */
29
29
  readonly env?: ConfigEnv;
30
30
  /** Seed secrets for the terminal memory / managed layer. */
31
31
  readonly seed?: Readonly<Record<string, string>>;
32
- /**
33
- * When `openbao` is selected but credentials are missing:
34
- * - `"throw"` — fail loud (default for `prod` / `docker`)
35
- * - `"memory"` — soft-fallback to a seeded memory bag (Console / local)
36
- */
37
- readonly missingOpenbao?: "throw" | "memory";
38
32
  }
39
33
 
40
34
  /**
41
35
  * Normalize a config label to a {@link VaultDriverId}.
42
36
  *
43
- * Accepts legacy `"dotenv"` as an alias for `"env"`.
37
+ * Accepts legacy `"dotenv"` as an alias for `"env"`, and `"builtin"` as an
38
+ * alias for the built-in `"vault"` store.
44
39
  *
45
40
  * @param raw - Config string
46
41
  */
47
42
  export function normalizeVaultDriverId(raw: string): VaultDriverId {
48
43
  if (raw === "dotenv") return "env";
49
- if (raw === "env" || raw === "openbao" || raw === "memory" || raw === "managed") {
44
+ if (raw === "builtin") return "vault";
45
+ if (raw === "env" || raw === "vault" || raw === "memory" || raw === "managed") {
50
46
  return raw;
51
47
  }
52
48
  throw new Error(
53
- `oke boot: unknown vault driver "${raw}" (expected env · openbao · memory · managed)`,
49
+ `oke boot: unknown vault driver "${raw}" (expected env · vault · memory · managed). ` +
50
+ 'Official backends: built-in vault (drivers.vault: "vault"), ENV, or managed with ' +
51
+ 'provider "aws-secrets-manager".',
54
52
  );
55
53
  }
56
54
 
@@ -69,9 +67,11 @@ export function buildVaultBootChain(options: BuildVaultBootChainOptions): VaultC
69
67
  composeText = readFileSync(composeEnv.path, "utf8").toString();
70
68
  }
71
69
  const envMap = parseDotenv(composeText);
72
- const openbaoUrl = process.env.OKE_VAULT_URL ?? envMap.get("OKE_VAULT_URL");
73
- const openbaoToken = process.env.OKE_VAULT_TOKEN ?? envMap.get("OKE_VAULT_TOKEN");
74
- const openbaoMount = process.env.OKE_VAULT_MOUNT ?? envMap.get("OKE_VAULT_MOUNT") ?? "secret";
70
+ const vaultUrl = process.env.OKE_VAULT_URL ?? envMap.get("OKE_VAULT_URL");
71
+ const vaultToken = process.env.OKE_VAULT_TOKEN ?? envMap.get("OKE_VAULT_TOKEN");
72
+ const vaultMount = process.env.OKE_VAULT_MOUNT ?? envMap.get("OKE_VAULT_MOUNT");
73
+ const vaultProvider = process.env.OKE_VAULT_PROVIDER ?? envMap.get("OKE_VAULT_PROVIDER");
74
+ const vaultRegion = process.env.OKE_VAULT_REGION ?? envMap.get("OKE_VAULT_REGION");
75
75
 
76
76
  const envLayers: VaultChainLayer[] = [
77
77
  { driver: envVaultDriver, source: "process.env" },
@@ -96,14 +96,36 @@ export function buildVaultBootChain(options: BuildVaultBootChainOptions): VaultC
96
96
  options: { secrets: seed },
97
97
  },
98
98
  ];
99
- case "managed":
99
+ case "managed": {
100
+ // No provider: the platform injected the values as env vars, so the
101
+ // driver's own env+seed bag is the whole chain.
102
+ if (vaultProvider === undefined || vaultProvider === "") {
103
+ return [
104
+ {
105
+ driver: managedVaultDriver,
106
+ source: "driver",
107
+ options: { secrets: seed },
108
+ },
109
+ ];
110
+ }
111
+ // With a remote provider the bag is remote-only, so the env layers go
112
+ // in front — an operator override in `process.env` still wins.
100
113
  return [
114
+ ...envLayers,
101
115
  {
102
116
  driver: managedVaultDriver,
103
117
  source: "driver",
104
- options: { secrets: seed },
118
+ options: {
119
+ provider: vaultProvider,
120
+ secrets: seed,
121
+ ...(vaultUrl === undefined ? {} : { url: vaultUrl }),
122
+ ...(vaultToken === undefined ? {} : { token: vaultToken }),
123
+ ...(vaultMount === undefined ? {} : { mount: vaultMount }),
124
+ ...(vaultRegion === undefined ? {} : { region: vaultRegion }),
125
+ },
105
126
  },
106
127
  ];
128
+ }
107
129
  case "env":
108
130
  return [
109
131
  ...envLayers,
@@ -113,35 +135,17 @@ export function buildVaultBootChain(options: BuildVaultBootChainOptions): VaultC
113
135
  options: { secrets: seed },
114
136
  },
115
137
  ];
116
- case "openbao": {
117
- if (openbaoUrl && openbaoToken) {
118
- return [
119
- ...envLayers,
120
- {
121
- driver: openbaoVaultDriver,
122
- source: "driver",
123
- options: { url: openbaoUrl, token: openbaoToken, mount: openbaoMount },
124
- },
125
- ];
126
- }
127
- const env = options.env ?? "local";
128
- const missing =
129
- options.missingOpenbao ?? (env === "prod" || env === "docker" ? "throw" : "memory");
130
- if (missing === "throw") {
131
- throw new Error(
132
- 'oke boot: vault driver "openbao" needs OKE_VAULT_URL and OKE_VAULT_TOKEN ' +
133
- "(did `oke dev -d` bootstrap OpenBao / write docker/.env.docker?)",
134
- );
135
- }
138
+ case "vault":
139
+ // The built-in store sits behind the env layers: an operator override
140
+ // in `process.env` still wins, exactly as it does for every driver.
136
141
  return [
137
142
  ...envLayers,
138
143
  {
139
- driver: memoryVaultDriver,
144
+ driver: builtinVaultDriver,
140
145
  source: "driver",
141
146
  options: { secrets: seed },
142
147
  },
143
148
  ];
144
- }
145
149
  default: {
146
150
  const _exhaustive: never = options.driverId;
147
151
  throw new Error(`oke boot: unhandled vault driver ${String(_exhaustive)}`);