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.
- package/package.json +76 -10
- package/site/content/docs/ai/mcp.mdx +0 -1
- package/site/content/docs/deployment/docker-swarm.mdx +48 -111
- package/site/content/docs/deployment/docker.mdx +43 -36
- package/site/content/docs/deployment/index.mdx +9 -9
- package/site/content/docs/deployment/kubernetes.mdx +4 -4
- package/site/content/docs/elements/ai.mdx +7 -13
- package/site/content/docs/elements/channel.mdx +9 -13
- package/site/content/docs/elements/clock.mdx +8 -14
- package/site/content/docs/elements/flow.mdx +46 -54
- package/site/content/docs/elements/gate.mdx +6 -11
- package/site/content/docs/elements/signal.mdx +2 -8
- package/site/content/docs/elements/store.mdx +79 -93
- package/site/content/docs/elements/vault.mdx +89 -76
- package/site/content/docs/get-started/basic-usage.mdx +8 -14
- package/site/content/docs/get-started/installation.mdx +36 -36
- package/site/content/docs/get-started/introduction.mdx +11 -0
- package/site/content/docs/get-started/why.mdx +3 -4
- package/site/content/docs/index.mdx +0 -1
- package/site/content/docs/meta.json +0 -1
- package/site/content/docs/plugins/anonymous.mdx +1 -1
- package/site/content/docs/plugins/magic-link.mdx +11 -11
- package/site/content/docs/plugins/otp.mdx +2 -2
- package/site/content/docs/plugins/passkey.mdx +1 -1
- package/site/content/docs/plugins/two-factor.mdx +1 -1
- package/site/content/docs/plugins/username.mdx +1 -1
- package/site/content/docs/recipes/caddy.mdx +1 -1
- package/site/content/docs/recipes/cockroachdb.mdx +2 -2
- package/site/content/docs/recipes/dragonfly.mdx +1 -1
- package/site/content/docs/recipes/index.mdx +1 -2
- package/site/content/docs/recipes/llama-cpp.mdx +21 -23
- package/site/content/docs/recipes/mailpit.mdx +11 -11
- package/site/content/docs/recipes/meilisearch.mdx +10 -10
- package/site/content/docs/recipes/meta.json +0 -1
- package/site/content/docs/recipes/ollama.mdx +1 -1
- package/site/content/docs/recipes/pgdog.mdx +12 -9
- package/site/content/docs/recipes/postgres.mdx +3 -3
- package/site/content/docs/recipes/redis.mdx +2 -2
- package/site/content/docs/recipes/rustfs.mdx +10 -7
- package/site/content/docs/recipes/sglang.mdx +1 -1
- package/site/content/docs/recipes/supabase-docker.mdx +1 -1
- package/site/content/docs/recipes/timescale.mdx +2 -2
- package/site/content/docs/recipes/valkey.mdx +1 -1
- package/site/content/docs/recipes/vllm.mdx +1 -1
- package/site/content/docs/recipes/yugabytedb.mdx +2 -2
- package/site/content/docs/reference/cli.md +61 -38
- package/site/content/docs/reference/configuration.mdx +145 -70
- package/site/content/docs/reference/environment-variables.mdx +36 -28
- package/site/content/docs/reference/errors.mdx +28 -29
- package/site/content/docs/reference/fx.mdx +14 -7
- package/site/content/docs/reference/i18n.mdx +17 -6
- package/site/content/docs/reference/index.mdx +5 -0
- package/site/content/docs/reference/meta.json +1 -0
- package/site/content/docs/reference/migrating-environments.mdx +158 -0
- package/site/content/docs/reference/plugins.mdx +2 -2
- package/src/auth/gate-auth.test.ts +12 -10
- package/src/cli/ai-setup/ai-setup.test.ts +30 -16
- package/src/cli/ai-setup/apply.ts +111 -15
- package/src/cli/ai-setup/catalog.ts +3 -3
- package/src/cli/ai-setup/index.ts +1 -1
- package/src/cli/ai-setup/prompts.ts +1 -1
- package/src/cli/ai-setup/recommend.test.ts +1 -1
- package/src/cli/ask-seed.test.ts +3 -3
- package/src/cli/build.ts +8 -9
- package/src/cli/db-auto-push.test.ts +6 -3
- package/src/cli/db-auto-push.ts +7 -5
- package/src/cli/db-seed.ts +7 -8
- package/src/cli/db.test.ts +70 -71
- package/src/cli/db.ts +86 -12
- package/src/cli/dev-controller.test.ts +35 -0
- package/src/cli/dev-controller.ts +298 -0
- package/src/cli/dev-controls.ts +11 -65
- package/src/cli/dev-db-push.test.ts +47 -15
- package/src/cli/dev-schema-sync.test.ts +11 -11
- package/src/cli/dev-schema-sync.ts +10 -10
- package/src/cli/dev-session-lock.test.ts +106 -0
- package/src/cli/dev-session-lock.ts +209 -0
- package/src/cli/dev.test.ts +246 -114
- package/src/cli/dev.ts +153 -205
- package/src/cli/doc-staleness.test.ts +3 -6
- package/src/cli/docker-clean.test.ts +33 -1
- package/src/cli/docker-clean.ts +28 -33
- package/src/cli/docker-cli.test.ts +12 -11
- package/src/cli/docker.ts +95 -20
- package/src/cli/doctor.test.ts +40 -0
- package/src/cli/doctor.ts +142 -9
- package/src/cli/drizzle-env.test.ts +11 -13
- package/src/cli/drizzle-env.ts +18 -11
- package/src/cli/ensure-drizzle-config.ts +11 -14
- package/src/cli/hero-meta.test.ts +15 -15
- package/src/cli/hero-meta.ts +10 -9
- package/src/cli/index.ts +36 -6
- package/src/cli/load-config.images.test.ts +44 -10
- package/src/cli/load-config.source.test.ts +50 -0
- package/src/cli/load-config.ts +35 -29
- package/src/cli/meilisearch-local.ts +1 -2
- package/src/cli/mode.ts +7 -58
- package/src/cli/registry.ts +175 -19
- package/src/cli/resolve-dev-sql-env.test.ts +8 -16
- package/src/cli/resolve-dev-sql-env.ts +13 -15
- package/src/cli/safe-defaults.test.ts +29 -11
- package/src/cli/schema.ts +65 -16
- package/src/cli/test.ts +58 -0
- package/src/cli/tui/App.tsx +252 -0
- package/src/cli/tui/DevLive.tsx +116 -0
- package/src/cli/tui/components/ConfirmDialog.tsx +48 -0
- package/src/cli/tui/components/HeaderBar.tsx +67 -0
- package/src/cli/tui/components/LogStream.tsx +47 -0
- package/src/cli/tui/components/PanelCard.tsx +39 -0
- package/src/cli/tui/components/SelectRow.tsx +37 -0
- package/src/cli/tui/components/SlashPalette.tsx +172 -0
- package/src/cli/tui/components/Spinner.tsx +32 -0
- package/src/cli/tui/components/StatusBar.tsx +51 -0
- package/src/cli/tui/components/StatusDot.tsx +37 -0
- package/src/cli/tui/components/TabBar.tsx +49 -0
- package/src/cli/tui/components/Wordmark.tsx +43 -0
- package/src/cli/tui/format.ts +38 -0
- package/src/cli/tui/keys.test.ts +18 -0
- package/src/cli/tui/keys.ts +26 -0
- package/src/cli/tui/launch.test.ts +18 -0
- package/src/cli/tui/launch.ts +57 -0
- package/src/cli/tui/panels/Dashboard.tsx +201 -0
- package/src/cli/tui/panels/Database.tsx +198 -0
- package/src/cli/tui/panels/Dev.tsx +257 -0
- package/src/cli/tui/panels/Docker.tsx +357 -0
- package/src/cli/tui/panels/Navigator.test.ts +22 -0
- package/src/cli/tui/panels/Navigator.tsx +213 -0
- package/src/cli/tui/slash-catalog.test.ts +31 -0
- package/src/cli/tui/slash-catalog.ts +184 -0
- package/src/cli/tui/slash-run.ts +54 -0
- package/src/cli/tui/state/ports.ts +95 -0
- package/src/cli/tui/theme.ts +24 -0
- package/src/cli/vault-cmd.test.ts +402 -0
- package/src/cli/vault-cmd.ts +727 -69
- package/src/cli/vault-secure-input.test.ts +56 -0
- package/src/cli/vault-secure-input.ts +124 -0
- package/src/compiler/effects-infer.ts +7 -0
- package/src/compiler/extract.ts +12 -0
- package/src/compiler/fixtures/skyport/oke.config.ts +7 -5
- package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -1
- package/src/compiler/fixtures/skyport.expected.json +1 -1
- package/src/compiler/generate-adopt.ts +27 -1
- package/src/compiler-entry.ts +7 -0
- package/src/config/define-config.test.ts +111 -47
- package/src/config/driver-defaults.test.ts +115 -0
- package/src/config/driver-defaults.ts +156 -0
- package/src/config/index.ts +246 -131
- package/src/config/resolve-driver.test.ts +14 -19
- package/src/console/server/app.ts +4 -2
- package/src/console/server/console.test.ts +58 -1
- package/src/console/server/flows.ts +22 -2
- package/src/console/server/index.ts +3 -0
- package/src/console/server/operator-db.test.ts +55 -13
- package/src/console/server/operator-db.ts +305 -263
- package/src/console/server/serve.ts +16 -7
- package/src/console/server/state.ts +31 -9
- package/src/console/server/vault.test.ts +120 -5
- package/src/console/server/vault.ts +208 -12
- package/src/console/ui/dist/assets/{index-D-9KFce5.js → index--Y0Uaz-m.js} +2 -2
- package/src/console/ui/dist/assets/panel-vault-BkZdJPX8.js +1 -0
- package/src/console/ui/dist/assets/style-C3L349iZ.css +3 -0
- package/src/console/ui/dist/index.html +2 -2
- package/src/console/ui/shell/client.ts +16 -0
- package/src/console/ui/shell/panels/vault/VaultPanel.tsx +54 -1
- package/src/console/ui/vault/VaultA11yView.tsx +33 -1
- package/src/console/ui/vault/backend.test.ts +75 -0
- package/src/console/ui/vault/backend.ts +117 -0
- package/src/console/ui/vault/fixture.ts +21 -2
- package/src/console/ui/vault/index.ts +11 -1
- package/src/console/ui/vault/types.ts +26 -0
- package/src/docker/compose.ts +164 -61
- package/src/docker/derive.ts +106 -12
- package/src/docker/docker.test.ts +156 -110
- package/src/docker/helpers.ts +98 -0
- package/src/docker/images-config.test.ts +163 -0
- package/src/docker/index.ts +30 -5
- package/src/docker/recipes/index.ts +0 -3
- package/src/docker/recipes/llama-cpp.ts +4 -4
- package/src/docker/recipes/pgdog.ts +9 -2
- package/src/docker/resources.test.ts +71 -0
- package/src/docker/resources.ts +176 -0
- package/src/docker/stack-id.test.ts +11 -4
- package/src/docker/stack-id.ts +42 -32
- package/src/docker/stack.integration.test.ts +4 -15
- package/src/docker/types.ts +35 -3
- package/src/drivers/ai-ollama.integration.test.ts +2 -2
- package/src/drivers/conformance.test.ts +11 -12
- package/src/drivers/drizzle-dialect.test.ts +0 -4
- package/src/drivers/drizzle-dialect.ts +7 -13
- package/src/drivers/index.ts +24 -7
- package/src/drivers/journal-postgres.test.ts +3 -1
- package/src/drivers/journal-postgres.ts +4 -2
- package/src/drivers/meilisearch.ts +1 -1
- package/src/drivers/pglite.ts +28 -5
- package/src/drivers/types.ts +9 -11
- package/src/drivers/vault-aws-secrets-manager.test.ts +159 -0
- package/src/drivers/vault-aws-secrets-manager.ts +333 -0
- package/src/drivers/vault-builtin.test.ts +110 -0
- package/src/drivers/vault-builtin.ts +184 -0
- package/src/drivers/vault-driver-removal.test.ts +13 -0
- package/src/drivers/vault-managed.test.ts +95 -0
- package/src/drivers/vault-managed.ts +101 -25
- package/src/drivers/vault-types.ts +25 -5
- package/src/elements/ai/runtime.ts +1 -1
- package/src/elements/clock/chaos.test.ts +4 -1
- package/src/elements/clock/durable.ts +57 -4
- package/src/elements/clock.test.ts +13 -14
- package/src/elements/gate/constants.ts +18 -0
- package/src/elements/gate.test.ts +1 -1
- package/src/elements/gate.ts +2 -2
- package/src/elements/store/domain-ddl.test.ts +5 -12
- package/src/elements/store/emit-drizzle.ts +44 -19
- package/src/elements/store/index-boot.test.ts +15 -116
- package/src/elements/store/load-plugin-tables.ts +1 -1
- package/src/elements/store/resource-list-docs.fixture.ts +12 -6
- package/src/elements/store/resource-list-docs.test.ts +64 -44
- package/src/elements/store/resource.test.ts +17 -10
- package/src/elements/store/runtime.ts +9 -12
- package/src/elements/store/schema-decl.test.ts +16 -32
- package/src/elements/store/seed.test.ts +1 -2
- package/src/elements/store/seed.ts +7 -8
- package/src/elements/store/sql-condition.test.ts +2 -2
- package/src/elements/store/sql-session.test.ts +8 -10
- package/src/elements/store/sql-session.ts +10 -2
- package/src/elements/store.test.ts +13 -13
- package/src/elements/vault/audit.ts +233 -0
- package/src/elements/vault/boot-chain.test.ts +78 -0
- package/src/elements/vault/boot-chain.ts +43 -39
- package/src/elements/vault/builtin-adapter.test.ts +479 -0
- package/src/elements/vault/builtin-adapter.ts +1184 -0
- package/src/elements/vault/crypto.test.ts +237 -0
- package/src/elements/vault/crypto.ts +431 -0
- package/src/elements/vault/declare.ts +164 -3
- package/src/elements/vault/errors.ts +56 -0
- package/src/elements/vault/kms-unseal.test.ts +76 -0
- package/src/elements/vault/kms-unseal.ts +181 -0
- package/src/elements/vault/path.ts +90 -0
- package/src/elements/vault/resilience.test.ts +102 -0
- package/src/elements/vault/resilience.ts +107 -0
- package/src/elements/vault/runtime.ts +36 -4
- package/src/elements/vault/security-checklist.test.ts +130 -0
- package/src/elements/vault/storage.ts +448 -0
- package/src/elements/vault/types.ts +288 -0
- package/src/elements/vault/unseal.ts +150 -0
- package/src/elements/vault.test.ts +72 -4
- package/src/elements/vault.ts +91 -2
- package/src/full.ts +248 -0
- package/src/http.ts +41 -0
- package/src/i18n/interpolate-simple.ts +37 -0
- package/src/i18n/messages.ts +51 -4
- package/src/i18n-entry.ts +7 -0
- package/src/index.ts +35 -145
- package/src/journal-entry.ts +20 -0
- package/src/kernel/adopt-barrel-fresh.test.ts +25 -10
- package/src/kernel/app.ts +40 -42
- package/src/kernel/auto-registry.test.ts +2 -2
- package/src/kernel/boot-bind/ai.test.ts +5 -5
- package/src/kernel/boot-bind/ai.ts +2 -1
- package/src/kernel/boot-bind/channel.test.ts +6 -6
- package/src/kernel/boot-bind/channel.ts +5 -4
- package/src/kernel/boot-bind/clock.ts +5 -5
- package/src/kernel/boot-bind/gate.ts +6 -7
- package/src/kernel/boot-bind/honor-config.test.ts +42 -42
- package/src/kernel/boot-bind/journal.ts +5 -5
- package/src/kernel/boot-bind/signal.ts +3 -1
- package/src/kernel/boot-bind/store.test.ts +55 -37
- package/src/kernel/boot-bind/store.ts +24 -34
- package/src/kernel/boot-bind/vault.ts +19 -4
- package/src/kernel/boot.test.ts +12 -4
- package/src/kernel/boot.ts +31 -19
- package/src/kernel/budget-entry.ts +1 -1
- package/src/kernel/compensate.test.ts +288 -1
- package/src/kernel/compensate.ts +126 -0
- package/src/kernel/concurrency.test.ts +10 -9
- package/src/kernel/effects-stamping.test.ts +27 -2
- package/src/kernel/element-registries.ts +5 -3
- package/src/kernel/flow.ts +4 -2
- package/src/kernel/fx.test.ts +119 -3
- package/src/kernel/fx.ts +215 -40
- package/src/kernel/index.ts +14 -0
- package/src/kernel/journal.ts +130 -7
- package/src/kernel/pipeline.test.ts +20 -6
- package/src/kernel/redacted.test.ts +35 -0
- package/src/kernel/redacted.ts +24 -2
- package/src/kernel/router/create-default.ts +16 -0
- package/src/kernel/router/create-edge.ts +18 -0
- package/src/kernel/router/create.ts +23 -0
- package/src/kernel/router/index.ts +23 -0
- package/src/kernel/router/linear.ts +88 -0
- package/src/kernel/router/regexp.ts +188 -0
- package/src/kernel/router/smart.ts +120 -0
- package/src/kernel/router/trie.ts +108 -0
- package/src/kernel/router/types.ts +56 -0
- package/src/kernel/router.ts +18 -532
- package/src/kernel-entry.ts +43 -0
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/fixtures/skyport.manifest.json +1 -1
- package/src/plugins/config-source.test.ts +7 -7
- package/src/release/build-lib.ts +58 -0
- package/src/release/exports.test.ts +4 -2
- package/src/release/exports.ts +30 -4
- package/src/release/measure.ts +101 -22
- package/src/runs/duckdb.ts +7 -2
- package/src/shared/optional-peer.ts +41 -0
- package/src/term.test.ts +3 -44
- package/src/test/create-test-app.ts +12 -0
- package/src/test/provisions.integration.test.ts +1 -1
- package/src/test/reset-element-registries.ts +2 -0
- package/src/upgrade/codemods.test.ts +7 -20
- package/src/upgrade/codemods.ts +93 -60
- package/site/content/docs/console/access.mdx +0 -29
- package/site/content/docs/console/ai.mdx +0 -35
- package/site/content/docs/console/architecture.mdx +0 -35
- package/site/content/docs/console/channels.mdx +0 -37
- package/site/content/docs/console/clock.mdx +0 -51
- package/site/content/docs/console/flows.mdx +0 -31
- package/site/content/docs/console/gates.mdx +0 -73
- package/site/content/docs/console/index.mdx +0 -54
- package/site/content/docs/console/manifest-diff.mdx +0 -34
- package/site/content/docs/console/meta.json +0 -24
- package/site/content/docs/console/overview.mdx +0 -40
- package/site/content/docs/console/plugins.mdx +0 -41
- package/site/content/docs/console/privacy.mdx +0 -32
- package/site/content/docs/console/runs.mdx +0 -50
- package/site/content/docs/console/signals.mdx +0 -40
- package/site/content/docs/console/store.mdx +0 -32
- package/site/content/docs/console/tenancy.mdx +0 -32
- package/site/content/docs/console/traces.mdx +0 -38
- package/site/content/docs/console/vault.mdx +0 -41
- package/site/content/docs/recipes/openbao.mdx +0 -141
- package/src/cli/ask-dev-mode.ts +0 -40
- package/src/cli/dev-mode.test.ts +0 -45
- package/src/cli/dev-mode.ts +0 -78
- package/src/cli/openbao-bootstrap.test.ts +0 -150
- package/src/cli/openbao-bootstrap.ts +0 -321
- package/src/cli/openbao-restart.integration.test.ts +0 -145
- package/src/console/ui/dist/assets/panel-vault-Za1GyJfM.js +0 -1
- package/src/console/ui/dist/assets/style-C8MxEWPd.css +0 -3
- package/src/docker/recipes/openbao.ts +0 -47
- package/src/drivers/libsql.ts +0 -179
- package/src/drivers/sqlite.ts +0 -44
- package/src/drivers/vault-openbao.test.ts +0 -97
- 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 /
|
|
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
|
|
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 === "
|
|
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 ·
|
|
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
|
|
73
|
-
const
|
|
74
|
-
const
|
|
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: {
|
|
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 "
|
|
117
|
-
|
|
118
|
-
|
|
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:
|
|
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)}`);
|