okengine 0.10.3 → 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/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 -7
- package/site/content/docs/elements/channel.mdx +9 -7
- package/site/content/docs/elements/clock.mdx +8 -8
- package/site/content/docs/elements/flow.mdx +46 -47
- package/site/content/docs/elements/gate.mdx +6 -5
- package/site/content/docs/elements/signal.mdx +2 -2
- package/site/content/docs/elements/store.mdx +71 -78
- package/site/content/docs/elements/vault.mdx +89 -70
- package/site/content/docs/get-started/basic-usage.mdx +8 -8
- 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 +2 -2
- 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 +11 -4
- 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 +27 -15
- 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 +1 -1
- 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 +166 -121
- package/src/cli/dev.ts +138 -192
- 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 +55 -15
- 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 +16 -12
- package/src/cli/load-config.source.test.ts +50 -0
- package/src/cli/load-config.ts +34 -28
- 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 +28 -10
- 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/fixtures/skyport/oke.config.ts +3 -3
- package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -1
- package/src/compiler/fixtures/skyport.expected.json +1 -1
- package/src/compiler-entry.ts +7 -0
- package/src/config/define-config.test.ts +111 -47
- package/src/config/driver-defaults.test.ts +16 -23
- package/src/config/driver-defaults.ts +33 -63
- package/src/config/index.ts +169 -144
- 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 +3 -8
- 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 +3 -10
- package/src/kernel/boot-bind/clock.ts +2 -2
- package/src/kernel/boot-bind/gate.ts +5 -9
- package/src/kernel/boot-bind/honor-config.test.ts +42 -42
- package/src/kernel/boot-bind/journal.ts +2 -2
- package/src/kernel/boot-bind/store.test.ts +43 -44
- package/src/kernel/boot-bind/store.ts +16 -41
- package/src/kernel/boot-bind/vault.ts +16 -1
- 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/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 @@
|
|
|
1
|
+
import{a as e,r as t}from"./rolldown-runtime-B0Z9INg1.js";import{C as n,Q as r,Z as i,a,b as o,c as s,d as c,et as l,g as u,nt as d,o as f,tt as p,u as m,w as h,y as g}from"./panel-access-ri1X9Otj.js";import{n as _}from"./panel-channels-BDYWX29p.js";var v=g({q:o().optional(),name:o().optional(),action:u([`set`,`rotate`]).optional()});function y(e){let t=v.safeParse(e);return t.success?t.data:{}}function b(e){let t={};return e.q&&(t.q=e.q),e.name&&(t.name=e.name),e.action&&(t.action=e.action),t}function x(e,t){return{...e,name:t,action:void 0}}var S={vault:`okengine's own store — encrypted at rest, sealed until unsealed with the master key`,env:`Environment layers only — process.env, .env.local, docker/.env.docker`,managed:`Managed KMS / provider secret store`,memory:`In-memory bag — test only, nothing survives restart`};function C(e){if(!e)return null;let t=`Backend ${e.driverId}`,n=S[e.driverId]??`Custom vault backend`;if(!e.builtin)return{title:t,description:n,badges:[],facts:[],hint:null};let r=e.status;if(!r)return{title:t,description:n,badges:[{id:`unreachable`,label:`status unavailable`,tone:`warn`}],facts:[],hint:e.unavailable??"Run `oke vault status` to inspect the backend directly"};if(!r.initialized)return{title:t,description:n,badges:[{id:`uninitialized`,label:`not initialized`,tone:`warn`}],facts:[],hint:"Run `oke vault init` to create the vault and print its master key once"};let i=[{id:`initialized`,label:`initialized`,tone:`ok`},r.sealed?{id:`sealed`,label:`sealed`,tone:`warn`}:{id:`unsealed`,label:`unsealed`,tone:`ok`}];r.rewrapTargetKekVersion!==null&&i.push({id:`rewrap`,label:`rewrap → kek v${r.rewrapTargetKekVersion}`,tone:`warn`});let a=[{label:`KEK generation`,value:`v${r.kekVersion}`},{label:`Secrets stored`,value:String(r.secretCount)},{label:`Seal count`,value:String(r.sealCount)}];return r.lastUnsealedAt!==null&&a.push({label:`Last unsealed`,value:new Date(r.lastUnsealedAt).toISOString()}),r.lastSealedAt!==null&&a.push({label:`Last sealed`,value:new Date(r.lastSealedAt).toISOString()}),{title:t,description:n,badges:i,facts:a,hint:r.sealed?"This process holds no master key — export OKE_VAULT_MASTER_KEY or run `oke vault unseal`":null}}function w(e,t=``){let n=t.trim().toLowerCase(),r=n?e.filter(e=>e.name.toLowerCase().includes(n)||(e.description?.toLowerCase().includes(n)??!1)):e,i=[`secret`,`config`],a={secret:`Secrets`,config:`Config`};return i.map(e=>({kind:e,label:a[e],secrets:r.filter(t=>t.kind===e)})).filter(e=>e.secrets.length>0)}function T(e={production:!0}){return e.production?{kind:`typed`,phrase:`SET`,requireReason:!0}:{kind:`undo`,windowMs:15e3}}function E(e={production:!0}){return{kind:`typed`,phrase:`ROTATE`,requireReason:!0}}function D(e){if(e.count===0)return{summary:`No in-flight durable runs hold this secret`,detail:null,warn:!1};let t=e.longestOutstandingMs==null?null:O(e.longestOutstandingMs);return{summary:`${e.count} in-flight durable run(s) will wake holding a new key`,detail:t?`Longest outstanding wake in ${t}`:e.longestWakeAt==null?null:`Longest wake at ${new Date(e.longestWakeAt).toISOString()}`,warn:!0}}function O(e){if(e<1e3)return`${e}ms`;let t=Math.floor(e/1e3);if(t<60)return`${t}s`;let n=Math.floor(t/60);if(n<60)return`${n}m`;let r=Math.floor(n/60);return r<48?`${r}h`:`${Math.floor(r/24)}d`}function k(e){return{name:e.name,kind:e.kind,sensitive:e.sensitive,description:e.description??null,rotate:e.rotate??null,fingerprints:{...e.fingerprints},fingerprint:e.fingerprint,cleartext:e.sensitive?null:e.cleartext,winner:e.winner,resolution:e.resolution.map(e=>({...e})),readers:[...e.readers],blastRadius:{count:e.blastRadius.count,longestWakeAt:e.blastRadius.longestWakeAt,longestOutstandingMs:e.blastRadius.longestOutstandingMs,runIds:[...e.blastRadius.runIds]},lastReadAt:e.lastReadAt,sharedFingerprintEnvs:[...e.sharedFingerprintEnvs]}}function A(e){return JSON.stringify(e.map(e=>k(e)),null,2)}var j=e(d(),1),M=p();function N(){let e=h({from:`/vault`}),t=n({from:`/vault`}),o=l(),[u,d]=(0,j.useState)(``),[p,g]=(0,j.useState)(``),[v,y]=(0,j.useState)(``),[S,O]=(0,j.useState)(null),k=e=>{t({search:b(e),replace:!0})},N=r({queryKey:[`console.vault.list`],queryFn:async()=>{let e=await c.vaultList();if(e.error)throw Error(e.error.code);return e.data},refetchInterval:1e4}),P=N.data?.secrets??[],F=N.data?.env??`local`,I=N.data?.backend??null,L=(0,j.useMemo)(()=>C(I),[I]),R=(0,j.useMemo)(()=>w(P,e.q??``),[P,e.q]),z=P.find(t=>t.name===e.name),B=z?D(z.blastRadius):null,V=T({production:!0}),H=E({production:!0}),U=e.action;(0,j.useEffect)(()=>{d(``),g(``),y(``),O(null)},[z?.name,U]);let W=i({mutationFn:async()=>{if(!z)throw Error(`no secret`);if(V.kind===`typed`){let e=a({typed:u,reason:p,phrase:V.phrase});if(e)throw Error(e.typed??e.reason??`confirm`)}let e=await c.vaultSet({name:z.name,value:v,confirmation:V.kind===`typed`?u:void 0,reason:p||void 0});if(e.error)throw Error(e.error.code);return e.data},onSuccess:async()=>{y(``),d(``),g(``),k({...e,action:void 0}),await o.invalidateQueries({queryKey:[`console.vault.list`]})}}),G=i({mutationFn:async()=>{if(!z)throw Error(`no secret`);let e=a({typed:u,reason:p,phrase:H.kind===`typed`?H.phrase:`ROTATE`});if(e)throw Error(e.typed??e.reason??`confirm`);let t=await c.vaultRotate({name:z.name,value:v,confirmation:u,reason:p});if(t.error)throw Error(t.error.code);return t.data},onSuccess:async()=>{y(``),d(``),g(``),k({...e,action:void 0}),await o.invalidateQueries({queryKey:[`console.vault.list`]})}});return(0,M.jsxs)(`div`,{className:`flex h-full min-h-0 flex-col`,children:[(0,M.jsxs)(`header`,{className:`flex shrink-0 flex-wrap items-end gap-3 border-b border-[var(--oke-line)] px-4 py-3`,children:[(0,M.jsxs)(`div`,{children:[(0,M.jsx)(`h1`,{className:`text-lg font-medium text-[var(--oke-fg)]`,children:`Vault`}),(0,M.jsx)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:`Fingerprints only — secrets are write-only`})]}),(0,M.jsxs)(`p`,{className:`text-sm text-[var(--oke-muted)]`,role:`status`,children:[`Environment `,F]}),(0,M.jsxs)(`label`,{className:`ml-auto flex min-w-[12rem] flex-col gap-1 text-sm`,children:[(0,M.jsx)(`span`,{className:`text-[var(--oke-muted)]`,children:`Filter vault`}),(0,M.jsx)(s,{"aria-label":`Filter vault`,value:e.q??``,onChange:t=>k({...e,q:t.currentTarget.value||void 0})})]}),(0,M.jsx)(f,{type:`button`,variant:`ghost`,onClick:()=>{let e=A(P);navigator.clipboard?.writeText(e),O(`Exported fingerprints only (no secret values)`)},children:`Export`})]}),S?(0,M.jsx)(`p`,{className:`px-4 py-2 text-sm text-[var(--oke-muted)]`,role:`status`,children:S}):null,L?(0,M.jsxs)(`section`,{"aria-label":`Vault backend`,className:`shrink-0 border-b border-[var(--oke-line)] px-4 py-3`,children:[(0,M.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,M.jsx)(`h2`,{className:`text-sm font-medium text-[var(--oke-fg)]`,children:L.title}),L.badges.map(e=>(0,M.jsx)(`span`,{role:e.tone===`warn`?`alert`:`status`,className:m(`border border-[var(--oke-line)] px-2 py-0.5 text-xs`,e.tone===`warn`?`text-[var(--oke-danger)]`:e.tone===`ok`?`text-[var(--oke-fg)]`:`text-[var(--oke-muted)]`),children:e.label},e.id))]}),(0,M.jsx)(`p`,{className:`mt-1 text-sm text-[var(--oke-muted)]`,children:L.description}),L.facts.length>0?(0,M.jsx)(`dl`,{className:`mt-2 flex flex-wrap gap-x-6 gap-y-1 text-sm`,children:L.facts.map(e=>(0,M.jsxs)(`div`,{className:`flex gap-2`,children:[(0,M.jsx)(`dt`,{className:`text-[var(--oke-muted)]`,children:e.label}),(0,M.jsx)(`dd`,{className:`font-mono`,children:e.value})]},e.label))}):null,L.hint?(0,M.jsx)(`p`,{className:`mt-1 text-sm text-[var(--oke-muted)]`,role:`status`,children:L.hint}):null,I?.builtin?(0,M.jsxs)(`p`,{className:`mt-1 text-sm text-[var(--oke-muted)]`,children:[`Every read, write, seal and rotate is recorded in a hash-chained audit log. Read it with `,(0,M.jsx)(`code`,{className:`font-mono`,children:`oke vault audit`}),`; verify the chain with`,` `,(0,M.jsx)(`code`,{className:`font-mono`,children:`oke vault audit verify`}),`.`]}):null]}):null,(0,M.jsxs)(`div`,{className:`flex min-h-0 flex-1`,children:[(0,M.jsxs)(`section`,{"aria-label":`Vault list`,className:`w-80 shrink-0 overflow-y-auto border-r border-[var(--oke-line)]`,children:[(0,M.jsx)(`h2`,{className:`sr-only`,children:`Contracts`}),N.isLoading?(0,M.jsx)(`p`,{className:`p-4 text-sm text-[var(--oke-muted)]`,children:`Loading…`}):null,R.map(t=>(0,M.jsxs)(`section`,{"aria-label":t.label,className:`py-2`,children:[(0,M.jsx)(`h3`,{className:`px-4 py-1 text-xs uppercase tracking-wide text-[var(--oke-muted)]`,children:t.label}),(0,M.jsx)(`ul`,{children:t.secrets.map(t=>(0,M.jsx)(`li`,{children:(0,M.jsxs)(`button`,{type:`button`,"aria-pressed":t.name===z?.name,className:m(`flex min-h-10 w-full flex-col items-start px-4 py-2 text-left text-sm`,t.name===z?.name?`bg-[var(--oke-line)] text-[var(--oke-fg)]`:`text-[var(--oke-muted)] hover:text-[var(--oke-fg)]`),onClick:()=>k(x(e,t.name)),children:[(0,M.jsx)(`span`,{children:_(t.name,t.description)}),t.description?(0,M.jsx)(`span`,{className:`font-mono text-xs text-[var(--oke-muted)]`,children:t.name}):null,(0,M.jsx)(`span`,{className:`truncate text-xs`,children:t.sensitive?t.fingerprint??`unset`:t.cleartext??`unset`}),t.blastRadius.count>0?(0,M.jsxs)(`span`,{role:`status`,className:`text-xs text-[var(--oke-danger)]`,children:[`blast `,t.blastRadius.count]}):null,t.sharedFingerprintEnvs.length>0?(0,M.jsx)(`span`,{role:`status`,className:`text-xs`,children:`shared fingerprint`}):null]})},t.name))})]},t.kind))]}),(0,M.jsx)(`section`,{"aria-label":`Vault detail`,"aria-live":`polite`,className:`min-w-0 flex-1 overflow-y-auto p-4`,children:z?(0,M.jsxs)(`div`,{className:`flex max-w-2xl flex-col gap-6`,children:[(0,M.jsxs)(`div`,{children:[(0,M.jsx)(`h2`,{className:`text-lg text-[var(--oke-fg)]`,children:_(z.name,z.description)}),z.description?(0,M.jsx)(`p`,{className:`font-mono text-sm text-[var(--oke-muted)]`,children:z.name}):null,z.rotate?(0,M.jsxs)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:[`Rotate hint: `,z.rotate]}):null]}),(0,M.jsxs)(`section`,{"aria-label":`Fingerprints by environment`,children:[(0,M.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Fingerprints`}),z.sensitive?(0,M.jsxs)(`ul`,{className:`space-y-1 font-mono text-sm`,children:[Object.entries(z.fingerprints).map(([e,t])=>(0,M.jsxs)(`li`,{children:[(0,M.jsxs)(`span`,{className:`text-[var(--oke-muted)]`,children:[e,`:`]}),` `,t,z.sharedFingerprintEnvs.includes(e)?(0,M.jsxs)(`span`,{role:`status`,className:`ml-2 text-[var(--oke-warn,var(--oke-muted))]`,children:[`(matches `,F,` — warning, may be deliberate)`]}):null]},e)),Object.keys(z.fingerprints).length===0?(0,M.jsx)(`li`,{className:`text-[var(--oke-muted)]`,children:`Unset`}):null]}):(0,M.jsx)(`p`,{className:`font-mono text-sm`,role:`status`,children:z.cleartext??`unset`})]}),(0,M.jsxs)(`section`,{"aria-label":`Resolution chain`,children:[(0,M.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Resolution chain`}),(0,M.jsx)(`ol`,{className:`list-decimal space-y-1 pl-5 text-sm`,children:z.resolution.map(e=>(0,M.jsxs)(`li`,{className:e.won?`text-[var(--oke-fg)]`:`text-[var(--oke-muted)]`,children:[(0,M.jsx)(`span`,{className:`font-mono`,children:e.source}),e.won?` — won`:e.present?` — present (lost)`:` — absent`]},e.source))}),(0,M.jsxs)(`p`,{className:`mt-2 text-sm`,role:`status`,children:[`Winner: `,(0,M.jsx)(`span`,{className:`font-mono`,children:z.winner??`none`})]})]}),(0,M.jsxs)(`section`,{"aria-label":`Readers`,children:[(0,M.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Readers`}),(0,M.jsxs)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:[`Flows that declare `,(0,M.jsxs)(`code`,{className:`font-mono`,children:[`fx.vault.get(`,z.name,`)`]})]}),(0,M.jsx)(`ul`,{className:`mt-1 list-disc pl-5 font-mono text-sm`,children:z.readers.length===0?(0,M.jsx)(`li`,{className:`text-[var(--oke-muted)]`,children:`none`}):z.readers.map(e=>(0,M.jsx)(`li`,{children:e},e))})]}),(0,M.jsxs)(`section`,{"aria-label":`Rotation blast radius`,children:[(0,M.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Rotation blast radius`}),B?(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(`p`,{className:`text-sm`,role:B.warn?`alert`:`status`,children:B.summary}),B.detail?(0,M.jsx)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:B.detail}):null,z.blastRadius.runIds.length>0?(0,M.jsx)(`p`,{className:`mt-1 font-mono text-xs text-[var(--oke-muted)]`,children:z.blastRadius.runIds.join(`, `)}):null]}):null]}),(0,M.jsxs)(`section`,{"aria-label":`Last read`,children:[(0,M.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Last read`}),(0,M.jsx)(`p`,{className:`text-sm`,role:`status`,children:z.lastReadAt==null?`Never read — possible dead secret`:new Date(z.lastReadAt).toISOString()})]}),(0,M.jsxs)(`section`,{"aria-label":`Set or rotate`,className:`space-y-3`,children:[(0,M.jsx)(`h3`,{className:`text-sm font-medium`,children:`Set / rotate`}),(0,M.jsx)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:`Write-only. Values are never revealed after submit. No preview.`}),(0,M.jsxs)(`div`,{className:`flex gap-2`,children:[(0,M.jsx)(f,{type:`button`,variant:U===`set`?`primary`:`ghost`,"aria-pressed":U===`set`,onClick:()=>k({...e,action:`set`}),children:`Set`}),(0,M.jsx)(f,{type:`button`,variant:U===`rotate`?`danger`:`ghost`,"aria-pressed":U===`rotate`,onClick:()=>k({...e,action:`rotate`}),children:`Rotate`})]}),U?(0,M.jsxs)(`div`,{className:`space-y-3 border border-[var(--oke-line)] p-3`,children:[(0,M.jsxs)(`label`,{className:`flex flex-col gap-1 text-sm`,children:[(0,M.jsx)(`span`,{children:`New value`}),(0,M.jsx)(s,{"aria-label":`New vault value`,type:`password`,autoComplete:`off`,value:v,onChange:e=>y(e.currentTarget.value)})]}),(U===`rotate`||V.kind===`typed`)&&(0,M.jsxs)(M.Fragment,{children:[(0,M.jsxs)(`label`,{className:`flex flex-col gap-1 text-sm`,children:[(0,M.jsxs)(`span`,{children:[`Type`,` `,U===`rotate`?H.kind===`typed`?H.phrase:`ROTATE`:V.kind===`typed`?V.phrase:`SET`,` `,`to confirm`]}),(0,M.jsx)(s,{"aria-label":`Confirmation phrase`,value:u,onChange:e=>d(e.currentTarget.value)})]}),(0,M.jsxs)(`label`,{className:`flex flex-col gap-1 text-sm`,children:[(0,M.jsx)(`span`,{children:`Reason`}),(0,M.jsx)(s,{"aria-label":`Reason for vault write`,value:p,onChange:e=>g(e.currentTarget.value)})]})]}),(0,M.jsx)(f,{type:`button`,variant:U===`rotate`?`danger`:`primary`,disabled:!v||(U===`set`?W.isPending:G.isPending),onClick:()=>{U===`set`?W.mutate():G.mutate()},children:U===`set`?`Commit set`:`Commit rotate`}),(W.isError||G.isError)&&(0,M.jsx)(`p`,{role:`alert`,className:`text-sm text-[var(--oke-danger)]`,children:(W.error??G.error)?.message??`Failed`})]}):null]})]}):(0,M.jsx)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:`Select a contract to inspect fingerprints, resolution, and readers.`})})]})]})}var P=t({default:()=>N});export{y as n,P as t};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-outline-style:solid;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-amber-800:oklch(47.3% .137 46.201);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-2xl:42rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--leading-snug:1.375;--leading-relaxed:1.625;--radius-sm:.25rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{inset-block:0}.top-0{top:0}.right-\[min\(28\%\,20rem\)\]{right:min(28%,20rem)}.left-\[min\(28\%\,20rem\)\]{left:min(28%,20rem)}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.mx-auto{margin-inline:auto}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-auto{margin-top:auto}.mr-2{margin-right:calc(var(--spacing) * 2)}.mr-3{margin-right:calc(var(--spacing) * 3)}.mr-auto{margin-right:auto}.mb-1{margin-bottom:var(--spacing)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.ml-1{margin-left:var(--spacing)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.size-1\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-4{height:calc(var(--spacing) * 4)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-12{height:calc(var(--spacing) * 12)}.h-16{height:calc(var(--spacing) * 16)}.h-40{height:calc(var(--spacing) * 40)}.h-64{height:calc(var(--spacing) * 64)}.h-\[calc\(100vh-3rem\)\]{height:calc(100vh - 3rem)}.h-auto{height:auto}.h-full{height:100%}.max-h-48{max-height:calc(var(--spacing) * 48)}.min-h-0{min-height:0}.min-h-2{min-height:calc(var(--spacing) * 2)}.min-h-8{min-height:calc(var(--spacing) * 8)}.min-h-10{min-height:calc(var(--spacing) * 10)}.min-h-20{min-height:calc(var(--spacing) * 20)}.min-h-24{min-height:calc(var(--spacing) * 24)}.w-2{width:calc(var(--spacing) * 2)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-16{width:calc(var(--spacing) * 16)}.w-24{width:calc(var(--spacing) * 24)}.w-56{width:calc(var(--spacing) * 56)}.w-64{width:calc(var(--spacing) * 64)}.w-72{width:calc(var(--spacing) * 72)}.w-80{width:calc(var(--spacing) * 80)}.w-auto{width:auto}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.max-w-prose{max-width:65ch}.max-w-sm{max-width:var(--container-sm)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:0}.min-w-2{min-width:calc(var(--spacing) * 2)}.min-w-8{min-width:calc(var(--spacing) * 8)}.min-w-\[4px\]{min-width:4px}.min-w-\[8rem\]{min-width:8rem}.min-w-\[12rem\]{min-width:12rem}.min-w-\[16rem\]{min-width:16rem}.flex-1{flex:1}.shrink-0{flex-shrink:0}.basis-full{flex-basis:100%}.border-collapse{border-collapse:collapse}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[minmax\(0\,8rem\)_1fr\]{grid-template-columns:minmax(0,8rem) 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0{gap:0}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-8{gap:calc(var(--spacing) * 8)}.gap-px{gap:1px}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-x-6{column-gap:calc(var(--spacing) * 6)}.gap-y-1{row-gap:var(--spacing)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-\[var\(--oke-line\)\]>:not(:last-child)){border-color:var(--oke-line)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:2147483647px}.rounded-sm{border-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-\[var\(--oke-accent\)\]{border-color:var(--oke-accent)}.border-\[var\(--oke-external\)\]{border-color:var(--oke-external)}.border-\[var\(--oke-line\)\],.border-\[var\(--oke-line\)\]\/50{border-color:var(--oke-line)}@supports (color:color-mix(in lab, red, red)){.border-\[var\(--oke-line\)\]\/50{border-color:color-mix(in oklab, var(--oke-line) 50%, transparent)}}.border-\[var\(--oke-muted\)\]{border-color:var(--oke-muted)}.bg-\[color-mix\(in_oklab\,var\(--oke-accent\)_55\%\,transparent\)\]{background-color:var(--oke-accent)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_oklab\,var\(--oke-accent\)_55\%\,transparent\)\]{background-color:color-mix(in oklab,var(--oke-accent) 55%,transparent)}}.bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_3\%\,transparent\)\]{background-color:var(--oke-fg)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_3\%\,transparent\)\]{background-color:color-mix(in oklab,var(--oke-fg) 3%,transparent)}}.bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_6\%\,transparent\)\]{background-color:var(--oke-fg)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_6\%\,transparent\)\]{background-color:color-mix(in oklab,var(--oke-fg) 6%,transparent)}}.bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_35\%\,transparent\)\]{background-color:var(--oke-fg)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_35\%\,transparent\)\]{background-color:color-mix(in oklab,var(--oke-fg) 35%,transparent)}}.bg-\[var\(--oke-accent\)\],.bg-\[var\(--oke-accent\)\]\/15{background-color:var(--oke-accent)}@supports (color:color-mix(in lab, red, red)){.bg-\[var\(--oke-accent\)\]\/15{background-color:color-mix(in oklab, var(--oke-accent) 15%, transparent)}}.bg-\[var\(--oke-bg\)\]{background-color:var(--oke-bg)}.bg-\[var\(--oke-danger\)\],.bg-\[var\(--oke-danger\)\]\/10{background-color:var(--oke-danger)}@supports (color:color-mix(in lab, red, red)){.bg-\[var\(--oke-danger\)\]\/10{background-color:color-mix(in oklab, var(--oke-danger) 10%, transparent)}}.bg-\[var\(--oke-external\)\]{background-color:var(--oke-external)}.bg-\[var\(--oke-fg\)\]{background-color:var(--oke-fg)}.bg-\[var\(--oke-line\)\],.bg-\[var\(--oke-line\)\]\/40{background-color:var(--oke-line)}@supports (color:color-mix(in lab, red, red)){.bg-\[var\(--oke-line\)\]\/40{background-color:color-mix(in oklab, var(--oke-line) 40%, transparent)}}.bg-black\/20{background-color:#0003}@supports (color:color-mix(in lab, red, red)){.bg-black\/20{background-color:color-mix(in oklab, var(--color-black) 20%, transparent)}}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab, red, red)){.bg-black\/50{background-color:color-mix(in oklab, var(--color-black) 50%, transparent)}}.bg-transparent{background-color:#0000}.fill-\[var\(--oke-fg\)\]{fill:var(--oke-fg)}.fill-\[var\(--oke-muted\)\]{fill:var(--oke-muted)}.p-0{padding:0}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-16{padding-block:calc(var(--spacing) * 16)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pb-1{padding-bottom:var(--spacing)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-5{padding-left:calc(var(--spacing) * 5)}.text-center{text-align:center}.text-left{text-align:left}.align-top{vertical-align:top}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[13px\]{font-size:13px}.leading-10{--tw-leading:calc(var(--spacing) * 10);line-height:calc(var(--spacing) * 10)}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.2em\]{--tw-tracking:.2em;letter-spacing:.2em}.tracking-\[0\.14em\]{--tw-tracking:.14em;letter-spacing:.14em}.tracking-\[0\.15em\]{--tw-tracking:.15em;letter-spacing:.15em}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-all{word-break:break-all}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[var\(--oke-accent\)\]{color:var(--oke-accent)}.text-\[var\(--oke-danger\)\]{color:var(--oke-danger)}.text-\[var\(--oke-external\)\]{color:var(--oke-external)}.text-\[var\(--oke-fg\)\]{color:var(--oke-fg)}.text-\[var\(--oke-muted\)\]{color:var(--oke-muted)}.text-\[var\(--oke-warn\,var\(--oke-muted\)\)\]{color:var(--oke-warn,var(--oke-muted))}.text-amber-800{color:var(--color-amber-800)}.text-black{color:var(--color-black)}.text-red-600{color:var(--color-red-600)}.text-red-700{color:var(--color-red-700)}.text-white{color:var(--color-white)}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.underline{text-decoration-line:underline}.decoration-\[var\(--oke-line\)\]{-webkit-text-decoration-color:var(--oke-line);-webkit-text-decoration-color:var(--oke-line);text-decoration-color:var(--oke-line)}.underline-offset-2{text-underline-offset:2px}.opacity-40{opacity:.4}.opacity-70{opacity:.7}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.outline-2{outline-style:var(--tw-outline-style);outline-width:2px}.outline-\[var\(--oke-danger\)\]{outline-color:var(--oke-danger)}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.placeholder\:text-\[var\(--oke-muted\)\]::placeholder{color:var(--oke-muted)}@media (hover:hover){.hover\:bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_3\%\,transparent\)\]:hover{background-color:var(--oke-fg)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_3\%\,transparent\)\]:hover{background-color:color-mix(in oklab,var(--oke-fg) 3%,transparent)}}.hover\:bg-\[var\(--oke-line\)\]\/20:hover{background-color:var(--oke-line)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-\[var\(--oke-line\)\]\/20:hover{background-color:color-mix(in oklab, var(--oke-line) 20%, transparent)}}.hover\:bg-\[var\(--oke-line\)\]\/40:hover{background-color:var(--oke-line)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-\[var\(--oke-line\)\]\/40:hover{background-color:color-mix(in oklab, var(--oke-line) 40%, transparent)}}.hover\:text-\[var\(--oke-fg\)\]:hover{color:var(--oke-fg)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:not-sr-only:focus{clip-path:none;white-space:normal;width:auto;height:auto;margin:0;padding:0;position:static;overflow:visible}.focus\:absolute:focus{position:absolute}.focus\:top-2:focus{top:calc(var(--spacing) * 2)}.focus\:left-2:focus{left:calc(var(--spacing) * 2)}.focus\:z-50:focus{z-index:50}.focus\:bg-\[var\(--oke-bg\)\]:focus{background-color:var(--oke-bg)}.focus\:px-3:focus{padding-inline:calc(var(--spacing) * 3)}.focus\:py-2:focus{padding-block:calc(var(--spacing) * 2)}.disabled\:opacity-40:disabled{opacity:.4}@media (width>=40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (width>=48rem){.md\:max-w-xs{max-width:var(--container-xs)}.md\:grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,1\.4fr\)\]{grid-template-columns:minmax(0,1fr) minmax(0,1.4fr)}.md\:grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,1\.5fr\)\]{grid-template-columns:minmax(0,1fr) minmax(0,1.5fr)}}@media (width>=64rem){.lg\:w-80{width:calc(var(--spacing) * 80)}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-\[1fr_1fr_1\.2fr\]{grid-template-columns:1fr 1fr 1.2fr}.lg\:grid-cols-\[14rem_1fr_18rem\]{grid-template-columns:14rem 1fr 18rem}.lg\:grid-cols-\[minmax\(0\,1\.2fr\)_minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,1.2fr) minmax(0,1fr)}.lg\:flex-row{flex-direction:row}.lg\:border-t-0{border-top-style:var(--tw-border-style);border-top-width:0}.lg\:border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.lg\:border-b-0{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.lg\:border-l{border-left-style:var(--tw-border-style);border-left-width:1px}}}:root{--oke-bg:#0e1116;--oke-fg:#e8eaed;--oke-muted:#9aa3b2;--oke-line:var(--oke-fg)}@supports (color:color-mix(in lab, red, red)){:root{--oke-line:color-mix(in oklab, var(--oke-fg) 12%, transparent)}}:root{--oke-accent:#3d9a6a;--oke-external:#d97706;--oke-danger:#c44b4b;--oke-font:"IBM Plex Sans", "Segoe UI", sans-serif;--oke-mono:"IBM Plex Mono", ui-monospace, monospace;--oke-dim:.38}@font-face{font-family:IBM Plex Sans;font-style:normal;font-weight:400 600;font-display:swap;src:local(IBM Plex Sans)}html,body,#root{height:100%}body{font-family:var(--oke-font);background:radial-gradient(1200px 600px at 10% -10%, #1a2433 0%, transparent 55%), radial-gradient(900px 500px at 100% 0%, #13201a 0%, transparent 50%), var(--oke-bg);color:var(--oke-fg);font-variant-numeric:tabular-nums;margin:0}*{box-sizing:border-box}a{color:inherit;text-decoration:none}:focus-visible{outline:2px solid var(--oke-accent);outline-offset:2px}@media (prefers-reduced-motion:reduce){*,:before,:after{transition:none!important;animation:none!important}}.sr-only{clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-duration{syntax:"*";inherits:false}
|
|
3
|
+
/*$vite$:1*/
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
|
7
7
|
<title>oke Console</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index--Y0Uaz-m.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-B0Z9INg1.js">
|
|
10
|
-
<link rel="stylesheet" crossorigin href="/assets/style-
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/assets/style-C3L349iZ.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
13
|
<div id="root"></div>
|
|
@@ -484,6 +484,22 @@ interface ConsoleClient {
|
|
|
484
484
|
sharedFingerprintEnvs: string[];
|
|
485
485
|
}>;
|
|
486
486
|
env: string;
|
|
487
|
+
backend: {
|
|
488
|
+
driverId: "env" | "vault" | "managed" | "memory";
|
|
489
|
+
builtin: boolean;
|
|
490
|
+
status: {
|
|
491
|
+
initialized: boolean;
|
|
492
|
+
sealed: boolean;
|
|
493
|
+
masterKeyPresent: boolean;
|
|
494
|
+
kekVersion: number;
|
|
495
|
+
secretCount: number;
|
|
496
|
+
sealCount: number;
|
|
497
|
+
lastSealedAt: number | null;
|
|
498
|
+
lastUnsealedAt: number | null;
|
|
499
|
+
rewrapTargetKekVersion: number | null;
|
|
500
|
+
} | null;
|
|
501
|
+
unavailable: string | null;
|
|
502
|
+
} | null;
|
|
487
503
|
}>;
|
|
488
504
|
vaultSet: (input: {
|
|
489
505
|
name: string;
|
|
@@ -11,6 +11,7 @@ import { useEffect, useMemo, useState } from "react";
|
|
|
11
11
|
import {
|
|
12
12
|
exportSafeList,
|
|
13
13
|
formatBlastRadius,
|
|
14
|
+
formatVaultBackend,
|
|
14
15
|
groupByKind,
|
|
15
16
|
openVault,
|
|
16
17
|
rotateConfirmation,
|
|
@@ -55,6 +56,8 @@ export function VaultPanel() {
|
|
|
55
56
|
|
|
56
57
|
const secrets = listQuery.data?.secrets ?? [];
|
|
57
58
|
const env = listQuery.data?.env ?? "local";
|
|
59
|
+
const backend = listQuery.data?.backend ?? null;
|
|
60
|
+
const backendCard = useMemo(() => formatVaultBackend(backend), [backend]);
|
|
58
61
|
const groups = useMemo(() => groupByKind(secrets, search.q ?? ""), [secrets, search.q]);
|
|
59
62
|
const open = secrets.find((s) => s.name === search.name);
|
|
60
63
|
const blast = open ? formatBlastRadius(open.blastRadius) : null;
|
|
@@ -164,6 +167,56 @@ export function VaultPanel() {
|
|
|
164
167
|
</p>
|
|
165
168
|
) : null}
|
|
166
169
|
|
|
170
|
+
{backendCard ? (
|
|
171
|
+
<section
|
|
172
|
+
aria-label="Vault backend"
|
|
173
|
+
className="shrink-0 border-b border-[var(--oke-line)] px-4 py-3"
|
|
174
|
+
>
|
|
175
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
176
|
+
<h2 className="text-sm font-medium text-[var(--oke-fg)]">{backendCard.title}</h2>
|
|
177
|
+
{backendCard.badges.map((badge) => (
|
|
178
|
+
<span
|
|
179
|
+
key={badge.id}
|
|
180
|
+
role={badge.tone === "warn" ? "alert" : "status"}
|
|
181
|
+
className={clsx(
|
|
182
|
+
"border border-[var(--oke-line)] px-2 py-0.5 text-xs",
|
|
183
|
+
badge.tone === "warn"
|
|
184
|
+
? "text-[var(--oke-danger)]"
|
|
185
|
+
: badge.tone === "ok"
|
|
186
|
+
? "text-[var(--oke-fg)]"
|
|
187
|
+
: "text-[var(--oke-muted)]",
|
|
188
|
+
)}
|
|
189
|
+
>
|
|
190
|
+
{badge.label}
|
|
191
|
+
</span>
|
|
192
|
+
))}
|
|
193
|
+
</div>
|
|
194
|
+
<p className="mt-1 text-sm text-[var(--oke-muted)]">{backendCard.description}</p>
|
|
195
|
+
{backendCard.facts.length > 0 ? (
|
|
196
|
+
<dl className="mt-2 flex flex-wrap gap-x-6 gap-y-1 text-sm">
|
|
197
|
+
{backendCard.facts.map((fact) => (
|
|
198
|
+
<div key={fact.label} className="flex gap-2">
|
|
199
|
+
<dt className="text-[var(--oke-muted)]">{fact.label}</dt>
|
|
200
|
+
<dd className="font-mono">{fact.value}</dd>
|
|
201
|
+
</div>
|
|
202
|
+
))}
|
|
203
|
+
</dl>
|
|
204
|
+
) : null}
|
|
205
|
+
{backendCard.hint ? (
|
|
206
|
+
<p className="mt-1 text-sm text-[var(--oke-muted)]" role="status">
|
|
207
|
+
{backendCard.hint}
|
|
208
|
+
</p>
|
|
209
|
+
) : null}
|
|
210
|
+
{backend?.builtin ? (
|
|
211
|
+
<p className="mt-1 text-sm text-[var(--oke-muted)]">
|
|
212
|
+
Every read, write, seal and rotate is recorded in a hash-chained audit log. Read it
|
|
213
|
+
with <code className="font-mono">oke vault audit</code>; verify the chain with{" "}
|
|
214
|
+
<code className="font-mono">oke vault audit verify</code>.
|
|
215
|
+
</p>
|
|
216
|
+
) : null}
|
|
217
|
+
</section>
|
|
218
|
+
) : null}
|
|
219
|
+
|
|
167
220
|
<div className="flex min-h-0 flex-1">
|
|
168
221
|
<section
|
|
169
222
|
aria-label="Vault list"
|
|
@@ -289,7 +342,7 @@ export function VaultPanel() {
|
|
|
289
342
|
<section aria-label="Readers">
|
|
290
343
|
<h3 className="mb-2 text-sm font-medium">Readers</h3>
|
|
291
344
|
<p className="text-sm text-[var(--oke-muted)]">
|
|
292
|
-
Flows that declare <code className="font-mono">fx.vault({open.name})</code>
|
|
345
|
+
Flows that declare <code className="font-mono">fx.vault.get({open.name})</code>
|
|
293
346
|
</p>
|
|
294
347
|
<ul className="mt-1 list-disc pl-5 font-mono text-sm">
|
|
295
348
|
{open.readers.length === 0 ? (
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Static Vault markup for the axe gate — same landmarks as the live panel.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { formatVaultBackend } from "./backend.ts";
|
|
5
6
|
import { formatBlastRadius } from "./blast-radius.ts";
|
|
6
7
|
import { VAULT_LIST_FIXTURE } from "./fixture.ts";
|
|
7
8
|
import { groupByKind } from "./group.ts";
|
|
@@ -23,6 +24,8 @@ export function VaultA11yView(props: VaultA11yViewProps) {
|
|
|
23
24
|
const open = VAULT_LIST_FIXTURE.secrets.find((s) => s.name === openName);
|
|
24
25
|
const blast = open ? formatBlastRadius(open.blastRadius) : null;
|
|
25
26
|
const env = VAULT_LIST_FIXTURE.env;
|
|
27
|
+
const backend = VAULT_LIST_FIXTURE.backend;
|
|
28
|
+
const backendCard = formatVaultBackend(backend);
|
|
26
29
|
|
|
27
30
|
return (
|
|
28
31
|
<div className="vault-a11y">
|
|
@@ -37,6 +40,35 @@ export function VaultA11yView(props: VaultA11yViewProps) {
|
|
|
37
40
|
</label>
|
|
38
41
|
</header>
|
|
39
42
|
<main id="vault-main">
|
|
43
|
+
{backendCard ? (
|
|
44
|
+
<section aria-label="Vault backend">
|
|
45
|
+
<h2>{backendCard.title}</h2>
|
|
46
|
+
<p>{backendCard.description}</p>
|
|
47
|
+
<p>
|
|
48
|
+
{backendCard.badges.map((badge) => (
|
|
49
|
+
<span key={badge.id} role={badge.tone === "warn" ? "alert" : "status"}>
|
|
50
|
+
{badge.label}{" "}
|
|
51
|
+
</span>
|
|
52
|
+
))}
|
|
53
|
+
</p>
|
|
54
|
+
<dl>
|
|
55
|
+
{backendCard.facts.map((fact) => (
|
|
56
|
+
<div key={fact.label}>
|
|
57
|
+
<dt>{fact.label}</dt>
|
|
58
|
+
<dd>{fact.value}</dd>
|
|
59
|
+
</div>
|
|
60
|
+
))}
|
|
61
|
+
</dl>
|
|
62
|
+
{backendCard.hint ? <p role="status">{backendCard.hint}</p> : null}
|
|
63
|
+
{backend?.builtin ? (
|
|
64
|
+
<p>
|
|
65
|
+
Audit trail is hash-chained in the backend — read it with `oke vault audit`, verify
|
|
66
|
+
it with `oke vault audit verify`.
|
|
67
|
+
</p>
|
|
68
|
+
) : null}
|
|
69
|
+
</section>
|
|
70
|
+
) : null}
|
|
71
|
+
|
|
40
72
|
<section aria-label="Vault list">
|
|
41
73
|
<h2>Contracts</h2>
|
|
42
74
|
{groups.map((group) => (
|
|
@@ -111,7 +143,7 @@ export function VaultA11yView(props: VaultA11yViewProps) {
|
|
|
111
143
|
<section aria-label="Readers">
|
|
112
144
|
<h3>Readers</h3>
|
|
113
145
|
<p>
|
|
114
|
-
Flows that declare fx.vault({open.name}): {open.readers.join(", ") || "none"}
|
|
146
|
+
Flows that declare fx.vault.get({open.name}): {open.readers.join(", ") || "none"}
|
|
115
147
|
</p>
|
|
116
148
|
</section>
|
|
117
149
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault backend status card — badges, facts, operator hint.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import { formatVaultBackend } from "./backend.ts";
|
|
7
|
+
import { VAULT_BACKEND_FIXTURE } from "./fixture.ts";
|
|
8
|
+
import type { VaultBackend } from "./types.ts";
|
|
9
|
+
|
|
10
|
+
describe("formatVaultBackend", () => {
|
|
11
|
+
test("null backend renders no card", () => {
|
|
12
|
+
expect(formatVaultBackend(null)).toBeNull();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("non-builtin driver shows the id with no seal badges", () => {
|
|
16
|
+
const card = formatVaultBackend({
|
|
17
|
+
driverId: "managed",
|
|
18
|
+
builtin: false,
|
|
19
|
+
status: null,
|
|
20
|
+
unavailable: null,
|
|
21
|
+
});
|
|
22
|
+
expect(card?.title).toBe("Backend managed");
|
|
23
|
+
expect(card?.badges).toEqual([]);
|
|
24
|
+
expect(card?.facts).toEqual([]);
|
|
25
|
+
expect(card?.hint).toBeNull();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("sealed builtin backend warns and points at the master key", () => {
|
|
29
|
+
const card = formatVaultBackend(VAULT_BACKEND_FIXTURE);
|
|
30
|
+
expect(card?.badges.map((b) => b.id)).toEqual(["initialized", "sealed"]);
|
|
31
|
+
expect(card?.badges.find((b) => b.id === "sealed")?.tone).toBe("warn");
|
|
32
|
+
expect(card?.facts).toContainEqual({ label: "KEK generation", value: "v2" });
|
|
33
|
+
expect(card?.facts).toContainEqual({ label: "Secrets stored", value: "7" });
|
|
34
|
+
expect(card?.hint).toContain("OKE_VAULT_MASTER_KEY");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("unsealed builtin backend has no hint", () => {
|
|
38
|
+
const backend: VaultBackend = {
|
|
39
|
+
...VAULT_BACKEND_FIXTURE,
|
|
40
|
+
status: { ...VAULT_BACKEND_FIXTURE.status!, sealed: false },
|
|
41
|
+
};
|
|
42
|
+
const card = formatVaultBackend(backend);
|
|
43
|
+
expect(card?.badges.map((b) => b.id)).toEqual(["initialized", "unsealed"]);
|
|
44
|
+
expect(card?.hint).toBeNull();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("uninitialized backend points at `oke vault init`", () => {
|
|
48
|
+
const backend: VaultBackend = {
|
|
49
|
+
...VAULT_BACKEND_FIXTURE,
|
|
50
|
+
status: { ...VAULT_BACKEND_FIXTURE.status!, initialized: false },
|
|
51
|
+
};
|
|
52
|
+
const card = formatVaultBackend(backend);
|
|
53
|
+
expect(card?.badges.map((b) => b.id)).toEqual(["uninitialized"]);
|
|
54
|
+
expect(card?.hint).toContain("oke vault init");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("an in-flight master rotation surfaces the rewrap target", () => {
|
|
58
|
+
const backend: VaultBackend = {
|
|
59
|
+
...VAULT_BACKEND_FIXTURE,
|
|
60
|
+
status: { ...VAULT_BACKEND_FIXTURE.status!, rewrapTargetKekVersion: 3 },
|
|
61
|
+
};
|
|
62
|
+
expect(formatVaultBackend(backend)?.badges.map((b) => b.label)).toContain("rewrap → kek v3");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("unreachable builtin backend surfaces the reason", () => {
|
|
66
|
+
const card = formatVaultBackend({
|
|
67
|
+
driverId: "vault",
|
|
68
|
+
builtin: true,
|
|
69
|
+
status: null,
|
|
70
|
+
unavailable: "connection refused",
|
|
71
|
+
});
|
|
72
|
+
expect(card?.badges.map((b) => b.id)).toEqual(["unreachable"]);
|
|
73
|
+
expect(card?.hint).toBe("connection refused");
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format the Vault backend status card (console §9.8).
|
|
3
|
+
*
|
|
4
|
+
* Only the built-in `vault` driver has a seal lifecycle; every other driver
|
|
5
|
+
* shows its id alone so the operator still knows which layer terminates the
|
|
6
|
+
* resolution chain.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { VaultBackend } from "./types.ts";
|
|
10
|
+
|
|
11
|
+
/** One badge in the status card. */
|
|
12
|
+
export interface VaultBackendBadge {
|
|
13
|
+
/** Stable id for keys and tests. */
|
|
14
|
+
readonly id: string;
|
|
15
|
+
/** Short badge text. */
|
|
16
|
+
readonly label: string;
|
|
17
|
+
/** `warn` renders as an alert; `ok` and `neutral` are status text. */
|
|
18
|
+
readonly tone: "ok" | "warn" | "neutral";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Rendered status card. */
|
|
22
|
+
export interface VaultBackendCard {
|
|
23
|
+
/** Driver id headline (`Backend vault`). */
|
|
24
|
+
readonly title: string;
|
|
25
|
+
/** One-line explanation of what that backend is. */
|
|
26
|
+
readonly description: string;
|
|
27
|
+
/** Seal / initialization badges — empty for non-builtin drivers. */
|
|
28
|
+
readonly badges: readonly VaultBackendBadge[];
|
|
29
|
+
/** `label: value` facts (KEK generation, secret count, …). */
|
|
30
|
+
readonly facts: readonly { readonly label: string; readonly value: string }[];
|
|
31
|
+
/** Operator next step, when one applies. */
|
|
32
|
+
readonly hint: string | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** What each driver id means, in one line. */
|
|
36
|
+
const DRIVER_DESCRIPTION: Readonly<Record<string, string>> = {
|
|
37
|
+
vault: "okengine's own store — encrypted at rest, sealed until unsealed with the master key",
|
|
38
|
+
env: "Environment layers only — process.env, .env.local, docker/.env.docker",
|
|
39
|
+
managed: "Managed KMS / provider secret store",
|
|
40
|
+
memory: "In-memory bag — test only, nothing survives restart",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Build the status card for a backend.
|
|
45
|
+
*
|
|
46
|
+
* @param backend - Server-reported backend, or `null` when unresolved
|
|
47
|
+
*/
|
|
48
|
+
export function formatVaultBackend(backend: VaultBackend | null): VaultBackendCard | null {
|
|
49
|
+
if (!backend) return null;
|
|
50
|
+
|
|
51
|
+
const title = `Backend ${backend.driverId}`;
|
|
52
|
+
const description = DRIVER_DESCRIPTION[backend.driverId] ?? "Custom vault backend";
|
|
53
|
+
|
|
54
|
+
if (!backend.builtin) {
|
|
55
|
+
return { title, description, badges: [], facts: [], hint: null };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const status = backend.status;
|
|
59
|
+
if (!status) {
|
|
60
|
+
return {
|
|
61
|
+
title,
|
|
62
|
+
description,
|
|
63
|
+
badges: [{ id: "unreachable", label: "status unavailable", tone: "warn" }],
|
|
64
|
+
facts: [],
|
|
65
|
+
hint: backend.unavailable ?? "Run `oke vault status` to inspect the backend directly",
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!status.initialized) {
|
|
70
|
+
return {
|
|
71
|
+
title,
|
|
72
|
+
description,
|
|
73
|
+
badges: [{ id: "uninitialized", label: "not initialized", tone: "warn" }],
|
|
74
|
+
facts: [],
|
|
75
|
+
hint: "Run `oke vault init` to create the vault and print its master key once",
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const badges: VaultBackendBadge[] = [
|
|
80
|
+
{ id: "initialized", label: "initialized", tone: "ok" },
|
|
81
|
+
status.sealed
|
|
82
|
+
? { id: "sealed", label: "sealed", tone: "warn" }
|
|
83
|
+
: { id: "unsealed", label: "unsealed", tone: "ok" },
|
|
84
|
+
];
|
|
85
|
+
if (status.rewrapTargetKekVersion !== null) {
|
|
86
|
+
badges.push({
|
|
87
|
+
id: "rewrap",
|
|
88
|
+
label: `rewrap → kek v${status.rewrapTargetKekVersion}`,
|
|
89
|
+
tone: "warn",
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const facts: { label: string; value: string }[] = [
|
|
94
|
+
{ label: "KEK generation", value: `v${status.kekVersion}` },
|
|
95
|
+
{ label: "Secrets stored", value: String(status.secretCount) },
|
|
96
|
+
{ label: "Seal count", value: String(status.sealCount) },
|
|
97
|
+
];
|
|
98
|
+
if (status.lastUnsealedAt !== null) {
|
|
99
|
+
facts.push({
|
|
100
|
+
label: "Last unsealed",
|
|
101
|
+
value: new Date(status.lastUnsealedAt).toISOString(),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (status.lastSealedAt !== null) {
|
|
105
|
+
facts.push({ label: "Last sealed", value: new Date(status.lastSealedAt).toISOString() });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
title,
|
|
110
|
+
description,
|
|
111
|
+
badges,
|
|
112
|
+
facts,
|
|
113
|
+
hint: status.sealed
|
|
114
|
+
? "This process holds no master key — export OKE_VAULT_MASTER_KEY or run `oke vault unseal`"
|
|
115
|
+
: null,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Vault panel fixture — fingerprints only; never real secret values.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { VaultListResponse, VaultRecord } from "./types.ts";
|
|
5
|
+
import type { VaultBackend, VaultListResponse, VaultRecord } from "./types.ts";
|
|
6
6
|
|
|
7
7
|
/** Fixture secret used only for leak-detection tests (never in panel rows). */
|
|
8
8
|
export const FIXTURE_SECRET_VALUE = "sk_live_DO_NOT_LEAK_fixture";
|
|
@@ -68,8 +68,27 @@ export const VAULT_FIXTURE: readonly VaultRecord[] = [
|
|
|
68
68
|
},
|
|
69
69
|
];
|
|
70
70
|
|
|
71
|
+
/** Built-in backend, initialized and sealed in this process. */
|
|
72
|
+
export const VAULT_BACKEND_FIXTURE: VaultBackend = {
|
|
73
|
+
driverId: "vault",
|
|
74
|
+
builtin: true,
|
|
75
|
+
status: {
|
|
76
|
+
initialized: true,
|
|
77
|
+
sealed: true,
|
|
78
|
+
masterKeyPresent: true,
|
|
79
|
+
kekVersion: 2,
|
|
80
|
+
secretCount: 7,
|
|
81
|
+
sealCount: 1,
|
|
82
|
+
lastSealedAt: 1_700_000_100_000,
|
|
83
|
+
lastUnsealedAt: 1_700_000_000_000,
|
|
84
|
+
rewrapTargetKekVersion: null,
|
|
85
|
+
},
|
|
86
|
+
unavailable: null,
|
|
87
|
+
};
|
|
88
|
+
|
|
71
89
|
/** List response matching `console.vault.list`. */
|
|
72
90
|
export const VAULT_LIST_FIXTURE: VaultListResponse = {
|
|
73
91
|
secrets: VAULT_FIXTURE,
|
|
74
|
-
env: "
|
|
92
|
+
env: "dev",
|
|
93
|
+
backend: VAULT_BACKEND_FIXTURE,
|
|
75
94
|
};
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
export type {
|
|
6
|
+
VaultBackend,
|
|
6
7
|
VaultBlastRadius,
|
|
8
|
+
VaultBuiltinStatus,
|
|
9
|
+
VaultDriverId,
|
|
7
10
|
VaultKindGroup,
|
|
8
11
|
VaultListResponse,
|
|
9
12
|
VaultRecord,
|
|
@@ -11,7 +14,14 @@ export type {
|
|
|
11
14
|
VaultResolutionStep,
|
|
12
15
|
} from "./types.ts";
|
|
13
16
|
|
|
14
|
-
export {
|
|
17
|
+
export { formatVaultBackend, type VaultBackendBadge, type VaultBackendCard } from "./backend.ts";
|
|
18
|
+
|
|
19
|
+
export {
|
|
20
|
+
VAULT_BACKEND_FIXTURE,
|
|
21
|
+
VAULT_FIXTURE,
|
|
22
|
+
VAULT_LIST_FIXTURE,
|
|
23
|
+
FIXTURE_SECRET_VALUE,
|
|
24
|
+
} from "./fixture.ts";
|
|
15
25
|
|
|
16
26
|
export {
|
|
17
27
|
parseVaultSearch,
|
|
@@ -43,10 +43,36 @@ export interface VaultRecord {
|
|
|
43
43
|
readonly sharedFingerprintEnvs: readonly string[];
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/** Vault backend driver id — matches `drivers.vault`. */
|
|
47
|
+
export type VaultDriverId = "env" | "vault" | "managed" | "memory";
|
|
48
|
+
|
|
49
|
+
/** Built-in Vault backend state (epoch-ms timestamps). */
|
|
50
|
+
export interface VaultBuiltinStatus {
|
|
51
|
+
readonly initialized: boolean;
|
|
52
|
+
readonly sealed: boolean;
|
|
53
|
+
readonly masterKeyPresent: boolean;
|
|
54
|
+
readonly kekVersion: number;
|
|
55
|
+
readonly secretCount: number;
|
|
56
|
+
readonly sealCount: number;
|
|
57
|
+
readonly lastSealedAt: number | null;
|
|
58
|
+
readonly lastUnsealedAt: number | null;
|
|
59
|
+
readonly rewrapTargetKekVersion: number | null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Backend serving the terminal layer of the resolution chain. */
|
|
63
|
+
export interface VaultBackend {
|
|
64
|
+
readonly driverId: VaultDriverId;
|
|
65
|
+
readonly builtin: boolean;
|
|
66
|
+
readonly status: VaultBuiltinStatus | null;
|
|
67
|
+
readonly unavailable: string | null;
|
|
68
|
+
}
|
|
69
|
+
|
|
46
70
|
/** `console.vault.list` response. */
|
|
47
71
|
export interface VaultListResponse {
|
|
48
72
|
readonly secrets: readonly VaultRecord[];
|
|
49
73
|
readonly env: string;
|
|
74
|
+
/** `null` when the server could not resolve a backend. */
|
|
75
|
+
readonly backend: VaultBackend | null;
|
|
50
76
|
}
|
|
51
77
|
|
|
52
78
|
/** Grouped list section (secrets vs config). */
|