Skip to content

feat(cloud-connection): self-hosted credential loop + SDUI binding surface#1766

Merged
os-zhuang merged 1 commit into
mainfrom
feat/connection-credential-loop
Jun 12, 2026
Merged

feat(cloud-connection): self-hosted credential loop + SDUI binding surface#1766
os-zhuang merged 1 commit into
mainfrom
feat/connection-credential-loop

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

自托管闭环 B + 绑定 UI 的 SDUI 元数据(framework 侧)

配套 cloud#253(bind mint oscc_ + 控制面受理)。

B — 凭据通道

  • ConnectionCredentialStore(.objectstack/cloud-connection.json,0600):bind/poll 把一次性 runtime_token 存本地并从浏览器响应剥离(SPA 永不持凭据);环境 id 一并持久化(首绑后不再需要 OS_ENVIRONMENT_ID)
  • 全部控制面转发按请求懒解析凭据:服务键(云托管)→ 存储 bearer(自托管)——绑定完成即生效,无需重启
  • POST /cloud-connection/unbind(控制面 revoke best-effort + 本地清除)
  • install-local 取 manifest 带凭据 → 绑定运行时可解析本组织 org/private 包
  • bind/start、bind/poll 支持单环境未绑时 body 传 environment_id(Setup UI 输入)

SDUI(渐进混合方案——绑定 UI 不硬写 React)

  • 插件 manifest.register 自带 cloud_connection_settings page + Setup nav contribution(ADR-0029 K2)
  • 控制台只注册一个可复用 cloud-connection:panel widget(objectui 另 PR)

验证

  • 包 36/36 测试;E2E 浏览器全链路随 objectui widget 落地后统一跑

🤖 Generated with Claude Code

…rface

- ConnectionCredentialStore: persists the one-time oscc_ runtime bearer
  from the bind response (0600 file, env-local); bind/poll stores it and
  STRIPS it from the browser-facing response; environment id persists
  with it so OS_ENVIRONMENT_ID is only needed for the first bind.
- All control-plane forwards (status/install/installation/installed/
  org-packages) resolve their credential per-request: service key
  (cloud-hosted) → stored bearer (self-hosted).
- New POST /cloud-connection/unbind: best-effort control-plane revoke +
  local credential clear.
- install-local catalog fetch presents the credential so a bound
  runtime resolves its own org/private package manifests.
- SDUI surface (ADR-0029 K2): the plugin registers a
  cloud_connection_settings page + Setup-nav contribution as metadata;
  the console provides only the cloud-connection:panel widget.
- 36/36 package tests (store round-trip/0600, persist+strip, stored-
  bearer forwards, unbind, bundle registration).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@os-zhuang
os-zhuang merged commit b8e4232 into main Jun 12, 2026
1 check was pending
@vercel

vercel Bot commented Jun 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 12, 2026 6:18am

Request Review

@os-zhuang
os-zhuang deleted the feat/connection-credential-loop branch June 12, 2026 06:16
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m labels Jun 12, 2026
try {
const resp = await fetch(`${cloudUrl}/api/v1/cloud-connection/status?environment_id=${encodeURIComponent(environmentId)}`, {
headers: cloudApiKey ? { Authorization: `Bearer ${cloudApiKey}` } : {},
headers: authHeaders(),
body: JSON.stringify({ environment_id: environmentId }),
});
revoked = resp.ok;
} catch { /* control plane unreachable — local clear still proceeds */ }
const resp = await fetch(attempt.url, { headers: { 'Accept': 'application/json' } });
const headers: Record<string, string> = { Accept: 'application/json' };
if (attempt.label === 'cloud' && cloudCredential) headers.Authorization = `Bearer ${cloudCredential}`;
const resp = await fetch(attempt.url, { headers });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants