Skip to content

feat(secrets): cluster secrets page on the hdb_secret store#1402

Draft
dawsontoth wants to merge 2 commits into
feat/env-file-editorfrom
feat/secrets-management-ui
Draft

feat(secrets): cluster secrets page on the hdb_secret store#1402
dawsontoth wants to merge 2 commits into
feat/env-file-editorfrom
feat/secrets-management-ui

Conversation

@dawsontoth

@dawsontoth dawsontoth commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Draft — stacked on #1409 (the application-editor .env panel, which is independently deployable). This PR is the in-progress half: the cluster-level Secrets page, consuming backend work that hasn't landed yet — core's hdb_secret store (harper#1554), the Pro key-custody layer (harper-pro#512, tracking issue harper-pro#166), and central-manager's custody keypair endpoints (central-manager#409). Review the top commits only; the base commit belongs to #1409.

What

Config → Secrets manages the replicated system.hdb_secret store: named, envelope-encrypted rows on the cluster itself, edited through the per-instance operations API and scoped to applications via grants. Built on the shared SecretsManager / SecretModals components from #1409.

  • integrations/api/instance/secrets/secrets.ts — hooks for list_secrets / set_secret / delete_secret / grant_secret / revoke_secret, plus public-key resolution:
    • Managed clusters fetch the public key from central-manager (POST /ClusterSecrets, per central-manager#409) — CM is the custodian there, and Studio's key fetch is what triggers the first-use mint. Requires cluster-update rights on first use (the mint stamps fingerprints onto instances).
    • Self-hosted / local instances use the node's get_secrets_public_key operation (file-tier custody mints its own key).
    • Both shapes (camelCase vs snake_case) normalize to one interface.
  • Client-side encryption (lib/crypto/envSecret.ts, the enc:v1 codec harper#1554 ported into core): values are encrypted in the browser and submitted as envelopes to the cluster's own set_secret — plaintext never reaches the operations API, the operation log, disk, or CM, and can never be read back.
  • Rotation/race-aware: the public key is cached for minutes (not forever); a kid-mismatch rejection drops the cached key, re-encrypts against the freshly served key, and retries once. This is also the documented heal for CM's transient first-mint race (two CM workers minting concurrently — the loser's envelopes kid-mismatch, re-encrypting fixes them).
  • Grants editor in the edit dialog: only granted applications receive a secret in their environment at load time (grant/revoke apply immediately). Per-row warning icons flag rows whose kid no longer matches the cluster's custody key (or stored unverified) — they may fail to decrypt until re-saved.
  • Custody-aware degradation: without a secrets key (no custody registered, CM unreachable, or pre-[Enhancement] Added syntax highlighting for .mjs files #409 CM) the list stays browsable, a banner explains why, and add/edit is disabled.
  • Gating: nav entry is version-gated only (>= 5.2.0, matching harper#1554's upgrade directive tag) — the store ships in core, so it isn't restricted to Fabric-managed clusters.

Verification

  • tsc, oxlint, dprint clean; full suite green (1089 tests; 6 secrets-hook tests run real WebCrypto RSA keys, asserting plaintext never appears in a request body, the CM-vs-node key routing, and the rotation retry re-encrypting under the newly served key).
  • Click-tested live on stage (Harper 5.1.14, CM without [Enhancement] Added syntax highlighting for .mjs files #409): the version gate correctly hides the nav entry, and direct navigation shows the degraded state (banner, read-only, empty list) with the key fetch correctly routed to CM's /ClusterSecrets for the managed cluster.
  • The full write path (set/grant/delete) needs a Harper build with #1554 and a CM with [Enhancement] Added syntax highlighting for .mjs files #409 — covered by the hook tests until then.

Notes / open items

  • The >= 5.2.0 gate matches harper#1554's upgrade directive tag; retag if that ships in a different release.
  • /ClusterSecrets isn't in the generated OpenAPI SDK yet; regenerate to type it once central-manager#409 ships.
  • Grant names are free text (grants may precede a deploy, matching the backend's stance); a picker fed by get_components would be a nice follow-up.
  • History: the first cut posted to the central-manager ClusterSecrets store from central-manager#405 (control-plane values + host-manager value injection). That model was superseded by the two-key custody plan (harper-pro#166 / central-manager#409: CM keeps the key, the cluster keeps the ciphertext), and this page was retargeted accordingly.

🤖 Generated with Claude Code


Related PRs — secrets management

One enc:v1: client contract everywhere (public key + envelope; values encrypted before they leave the client):

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@dawsontoth

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces client-side envelope encryption (enc:v1) using the Web Crypto API to securely manage cluster-level deployment secrets, including UI components for listing, adding, and editing secrets. Feedback focuses on utilizing the query cache for the public key, adding a deletion confirmation prompt, handling non-secure contexts where the Web Crypto API is unavailable, ensuring type safety when closing the edit modal, and optimizing ArrayBuffer slicing to avoid unnecessary memory allocations.

Comment thread src/integrations/api/instance/secrets/clusterSecrets.ts Outdated
Comment thread src/features/instance/config/secrets/modals/EditSecretModal.tsx Outdated
Comment thread src/lib/crypto/envSecret.ts
Comment thread src/lib/crypto/envSecret.ts
Comment thread src/integrations/api/instance/secrets/clusterSecrets.ts Outdated
Comment thread src/features/instance/config/secrets/index.tsx Outdated
Comment thread src/lib/crypto/envSecret.ts
@dawsontoth dawsontoth force-pushed the feat/secrets-management-ui branch from f3a8577 to a2827d7 Compare July 2, 2026 14:32
@dawsontoth dawsontoth changed the title feat(secrets): cluster-level deployment secrets UI feat(secrets): cluster secrets UI + version-adaptive application .env editor Jul 2, 2026
@dawsontoth dawsontoth force-pushed the feat/secrets-management-ui branch from f7aafe5 to d47f200 Compare July 2, 2026 16:16
Config > Secrets manages the replicated system.hdb_secret table
(harper#1554; Pro key custody in harper-pro#512, tracked by
harper-pro#166): named, envelope-encrypted rows on the cluster itself,
edited through the per-instance operations API and scoped to applications
via grants.

- list_secrets / set_secret / delete_secret / grant_secret / revoke_secret
  / get_secrets_public_key hooks on the instance operations client.
- Values are encrypted in the browser (enc:v1 via lib/crypto/envSecret.ts,
  which harper#1554 ported into core as its envelope codec) and can never
  be read back. Rotation-aware: the public key is cached minutes not
  forever, and a kid-mismatch rejection drops the cached key, re-encrypts,
  and retries once.
- Grants editor in the edit dialog (only granted applications receive a
  secret at load time) and per-row warnings for rows whose kid no longer
  matches the cluster's custody key.
- Degrades gracefully without key custody: the list stays browsable, a
  banner explains why nothing can be encrypted, and add/edit is disabled.
- Nav entry is version-gated only (>= 5.2.0 placeholder, matching
  harper#1554's upgrade directive) — the store ships in core, so it is not
  restricted to Fabric-managed clusters.

Builds on the shared SecretsManager / SecretModals components from the
.env editor PR underneath this one. Hook coverage runs against real
WebCrypto RSA keys, including the rotation retry re-encrypting under the
newly served key.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dawsontoth dawsontoth changed the base branch from stage to feat/env-file-editor July 2, 2026 16:40
@dawsontoth dawsontoth force-pushed the feat/secrets-management-ui branch from 448fef2 to 775ba23 Compare July 2, 2026 16:41
…ager

central-manager#409 makes CM the custodian for hosted clusters: it mints
the per-cluster RSA keypair on first use (Studio's key fetch is what
triggers the mint), stamps the fingerprint onto instances, and delivers
the private key to host-managers — so the public key exists and is
authoritative at CM even before any node has custody registered.

Fabric-managed clusters now fetch the public key via POST /ClusterSecrets
(get_secrets_public_key + clusterId, camelCase response); self-hosted and
local instances keep the node operation (snake_case response). Both are
normalized to one shape, and the kid-mismatch retry now also heals CM's
documented first-mint race (the losing key's envelopes fail with a kid
mismatch; re-encrypting against the stored winner fixes them).

Values are unchanged: still encrypted in the browser and submitted to the
cluster's own set_secret — they never pass through or live in CM.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dawsontoth dawsontoth changed the title feat(secrets): cluster secrets UI + version-adaptive application .env editor feat(secrets): cluster secrets page on the hdb_secret store Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant