Skip to content

feat(cloud-connection): runtime-identity bind v2 — environment-less self-hosted binding#1783

Merged
xuyushun441-sys merged 1 commit into
mainfrom
feat/runtime-identity-claim
Jun 12, 2026
Merged

feat(cloud-connection): runtime-identity bind v2 — environment-less self-hosted binding#1783
xuyushun441-sys merged 1 commit into
mainfrom
feat/runtime-identity-claim

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

Summary

Framework counterpart of cloud ADR runtime-identity-binding + cloud#264: a self-hosted runtime binds to the control plane like a device binding to an account.

  • No environment id anywhere in the self-hosted flow: bind/start/bind/poll work environment-less in singleEnvironment mode (the registration row is created cloud-side at approval). The Setup-page "create an environment in the cloud console and paste its id" dead-end is gone.
  • Registration claim: the bind call carries hostname + runtime_version (names the device on the approval surface / runtimes list) and the stored runtime_id on re-bind — identity survives token rotation; the claim is verified cloud-side (org match) against squatting.
  • Store: persists the cloud-minted runtime_id; environmentId optional (cloud-hosted binds only).
  • status: reports runtimeId; an env-less single-env runtime reads as unbound (200) instead of 404.
  • unbind: env-optional; revokes via the oscc_ bearer (it self-identifies) before clearing the local credential.
  • org-packages: bearer-only forward when no env — the cloud derives the org from the connection (existing behavior). installation/installed degrade gracefully for registration-only runtimes (local installs are tracked by LocalManifestSource).

Tests

  • +4 cases (claim contents + runtime_id persistence; env-less bind/start; bearer-only unbind; bearer-only org-packages); 2 status-shape assertions updated
  • @objectstack/cloud-connection 40/40, build + dts clean

Consumed by the cloud repo via SHA pin bump after merge.

🤖 Generated with Claude Code

…elf-hosted binding

Counterpart of cloud#264 (ADR runtime-identity-binding):
- bind/start + bind/poll no longer require an environment id in
  singleEnvironment mode — the registration is created cloud-side at
  approval; the old 'create an environment and paste its id' dead-end is gone
- bind carries a registration claim: hostname, runtime_version, and the
  stored runtime_id on re-bind (identity survives token rotation)
- the credential store persists the cloud-minted runtime_id;
  environmentId becomes optional (set only for cloud-hosted binds)
- status: reports runtimeId, env-less single-env runtimes read as
  unbound (200) instead of 404; queries cloud by runtime_id when no env
- unbind: env-optional, revokes via the oscc_ bearer (empty body)
- org-packages: bearer-only forward when no env (org from connection);
  installation/installed degrade gracefully for registration-only runtimes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@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 Building Building Preview, Comment Jun 12, 2026 11:46am

Request Review

@xuyushun441-sys
xuyushun441-sys merged commit 48051ff into main Jun 12, 2026
7 of 8 checks passed
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling and removed size/m labels Jun 12, 2026
@xuyushun441-sys
xuyushun441-sys deleted the feat/runtime-identity-claim branch June 12, 2026 11:47
const qs = environmentId
? `?environment_id=${encodeURIComponent(environmentId)}`
: runtimeId ? `?runtime_id=${encodeURIComponent(runtimeId)}` : '';
const resp = await fetch(`${cloudUrl}/api/v1/cloud-connection/status${qs}`, {
Comment on lines +333 to +340
body: JSON.stringify({
...(environmentId ? { environment_id: environmentId } : {}),
...(stored?.runtimeId ? { runtime_id: stored.runtimeId } : {}),
name: (() => { try { return hostname(); } catch { return undefined; } })(),
runtime_version: (process.env.OS_RUNTIME_VERSION ?? this.version) || undefined,
token: accessToken,
scope: deviceScope,
}),
method: 'POST',
headers: { 'Content-Type': 'application/json', ...authHeaders() },
body: JSON.stringify({ environment_id: environmentId }),
body: JSON.stringify(environmentId ? { environment_id: environmentId } : {}),
const qs = environmentId ? `?environment_id=${encodeURIComponent(environmentId)}` : '';
const resp = await fetch(
`${cloudUrl}/api/v1/cloud/org-packages?environment_id=${encodeURIComponent(environmentId)}`,
`${cloudUrl}/api/v1/cloud/org-packages${qs}`,
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 tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants