Fabric Connect: seal proxied operations end-to-end with the cluster secrets key (`encrypted_operation`), starting with the token mint (blocked on harper#3288)

未关闭
#1,982 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 2 天内回复

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
25/100
Issue 类型
功能
描述清晰度
基本清楚
活跃度
活跃
技术栈
typescript

调研方向

Start with src/config/getInstanceClient.ts and trace the proxy client setup, then read src/lib/crypto/envSecret.ts, src/integrations/api/instance/secrets/secrets.ts, and authStore.establishFabricConnectAuth. The issue depends on Harper's encrypted_operation support and the control-plane relay, so confirm those interfaces before implementation. Done means the listed acceptance criteria pass, including interceptor tests, retry and fallback behavior, badge state, and logging redaction.

由索引模型根据 Issue 内容生成。

描述

Studio leg of end-to-end encrypted Fabric Connect operations. Blocked on HarperFast/harper#3288 (encrypted_operation in core) and on the control-plane leg that relays it opaquely (linked as a dependency on this issue).

Context

When a cluster or instance is reached through Fabric Connect, getInstanceClient points the axios client at the proxy URL (src/config/getInstanceClient.ts:58-77) and every operation, request and response, crosses the proxy in plaintext. The first one in every session is createInstanceAuthenticationTokens (src/integrations/api/instance/auth/createInstanceAuthenticationTokens.ts, called from authStore.establishFabricConnectAuth), whose response is the operation token and refresh token the rest of the session uses; sessions whose direct connection fails (studio#1635 measured network-level direct failures across 11 organizations in a day) keep using the proxy for everything.

Studio already seals values to a cluster's secrets public key for set_secret: src/lib/crypto/envSecret.ts (encryptEnvelope, WebCrypto RSA-OAEP + AES-GCM, enc:v1 output) and secretsPublicKeyQueryOptions({ managedClusterId }) in src/integrations/api/instance/secrets/secrets.ts, which fetches the key from the control plane for managed clusters. harper#3288 lets the same envelope carry a whole operation and answers with a response sealed under a per-request key.

Changes

  1. Transparent sealing on the proxy client. In getInstanceClient, when fabricConnect is true and the target supports it, install a request interceptor that replaces the body with { operation: 'encrypted_operation', envelope } where envelope = encryptEnvelope(JSON.stringify({ v: 1, op: body, rk, nonce, ts: Date.now(), actor }), publicKey, fingerprint) with fresh random rk (32 bytes) and nonce (16 bytes); and a response interceptor that decrypts encrypted_response with WebCrypto AES-GCM under rk, AAD "harper.encrypted_operation.response:" + nonce, then resolves with the inner body or rejects with an AxiosError whose response.status / data are the inner ones. Existing callers and react-query hooks see the same shapes as today. connectsThroughProxy(id) stays the single switch.
  2. Self-heal paths. On a plaintext 409 with custody_fingerprint, invalidate the public-key query and retry once (same pattern as the KID_MISMATCH_ERROR_PHRASE handling in secrets.ts). On a staleness error carrying server_time, retry once with the clock offset applied.
  3. Capability gate. MIN_ENCRYPTED_OPERATION_VERSION checked with wasAReleasedBeforeB against getRegistrationInfoQueryOptions' version, the pattern in useSupportsDeploymentSSE.ts; the constant is set when the core release is cut.
  4. No custody key. Self-hosted clusters (the control plane answers 400 for the key), clusters below the minimum version, or a node answering 503 "custody is not initialized": fall back to plaintext proxying and show a persistent indicator on the Fabric Connect badge ("not end-to-end encrypted; operations are visible to the control plane"). A "require encrypted proxying" preference is a follow-up, not this issue.
  5. Mode policy. harper#3288 has two modes: whole-body sealed, and fields (keys in the clear, values sealed, inner status visible) so the control plane can audit what was attempted. Proposed default: fields, sealing every leaf except operation and the structural keys database, schema, table, with whole-body sealed as a per-call override for operations whose structure is sensitive. In fields mode the interceptor serializes op to JSON text, puts its SHA-256 in the sealed header as oph, and binds each sealed leaf to its JSON Pointer; the helper lives beside envSecret.ts. Both modes must be selectable per call; the default is left open until the core issue has had feedback (Devin, 2026-10-19).
  6. First consumer is the token mint over the proxy; the proxy-fallback mode in resolveFabricConnectAuth is covered by the same interceptor.
  7. Never log the sealed request, rk, or the unsealed response; the existing rule of logging only error.message (axios configs carry bearer tokens) applies.

Acceptance criteria

  1. With a capable managed cluster, every operation sent through the proxy leaves the browser as encrypted_operation with an enc:v1 envelope sealed to the cluster key the secrets page uses, and the caller receives the inner response or error with unchanged shape (unit tests on the interceptors with a mocked proxy; one test proves the plaintext operation name never appears in the request body).

  2. The token mint over the proxy is sealed; the minted token is unsealed in the browser only.

  3. Key-mismatch and clock-skew answers self-heal with one retry; a second failure surfaces as the inner error.

  4. Without a key or below the minimum version, operations still work in plaintext and the badge shows the plaintext state; the secrets page's "no custody" copy mentions that proxied operations are affected too.

  5. No sealed material or key bytes reach console, Datadog RUM actions, or error tracking (assert on the RUM wrapper's redaction as existing tests do).

  6. In fields mode the request body shows operation and the structural keys in plaintext and every other leaf as { $sealed }; a test proves oph matches the sent op bytes and that a sealed leaf moved to another path is rejected by the node.

Links

  • Core: HarperFast/harper#3288 (mechanism, threat model). Related: studio#1635 (direct-connect reachability), studio#1974 (sign-out through the proxy).

🤖 Generated by Anthropic Claude (Mythos 5.1) as devain; posted via @Devin-Holland.

主要语言
TypeScript
星标
5
派生
4
平均合并
1 天 19 小时
30 天内合并 PR
144

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

HarperFast/studio 的其他 Issue

查看 HarperFast/studio 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。