From f6fd7b632340861f045e7673f133e89e2421dd5a Mon Sep 17 00:00:00 2001 From: Hare Date: Fri, 26 Jun 2026 04:31:59 +0900 Subject: [PATCH] feat: add workspace runtime registry source boundary --- crates/workspace-server/src/hosts.rs | 83 +++++++++++++++++++++++++-- crates/workspace-server/src/server.rs | 27 +++++---- 2 files changed, 95 insertions(+), 15 deletions(-) diff --git a/crates/workspace-server/src/hosts.rs b/crates/workspace-server/src/hosts.rs index 52d9a2e6..f576cda2 100644 --- a/crates/workspace-server/src/hosts.rs +++ b/crates/workspace-server/src/hosts.rs @@ -44,6 +44,69 @@ pub enum DiagnosticSeverity { Error, } +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum RuntimeSourceKind { + /// Compatibility projection over the existing local Pod metadata store. + LocalCompatibility, + /// Reserved boundary for the future in-process worker-runtime Runtime adapter. + EmbeddedWorkerRuntime, + /// Reserved boundary for a future remote Workspace Runtime adapter. + RemoteHttp, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum RuntimeSourceStatus { + Active, + Reserved, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum RuntimeIdentityAuthority { + /// Public Runtime/Host/Worker ids are registry projections, never raw + /// compatibility-store names, socket addresses, session ids, or paths. + RuntimeRegistryProjection, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct RuntimeSourceSummary { + pub kind: RuntimeSourceKind, + pub status: RuntimeSourceStatus, + pub identity_authority: RuntimeIdentityAuthority, + pub note: String, +} + +impl RuntimeSourceSummary { + pub fn local_compatibility() -> Self { + Self { + kind: RuntimeSourceKind::LocalCompatibility, + status: RuntimeSourceStatus::Active, + identity_authority: RuntimeIdentityAuthority::RuntimeRegistryProjection, + note: "read-only compatibility projection over local Worker metadata; no socket, session, or path authority is exposed".to_string(), + } + } + + pub fn embedded_worker_runtime_reserved() -> Self { + Self { + kind: RuntimeSourceKind::EmbeddedWorkerRuntime, + status: RuntimeSourceStatus::Reserved, + identity_authority: RuntimeIdentityAuthority::RuntimeRegistryProjection, + note: "reserved boundary for a future embedded worker-runtime adapter; not connected in this registry foundation".to_string(), + } + } + + pub fn remote_http_reserved() -> Self { + Self { + kind: RuntimeSourceKind::RemoteHttp, + status: RuntimeSourceStatus::Reserved, + identity_authority: RuntimeIdentityAuthority::RuntimeRegistryProjection, + note: "reserved boundary for a future remote Runtime adapter; no HTTP client or REST server is implemented here".to_string(), + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct RuntimeCapabilitySummary { pub can_list_hosts: bool, @@ -74,6 +137,7 @@ pub struct RuntimeSummary { pub label: String, pub kind: String, pub status: String, + pub source: RuntimeSourceSummary, pub host_ids: Vec, pub capabilities: RuntimeCapabilitySummary, pub diagnostics: Vec, @@ -317,11 +381,11 @@ pub trait WorkspaceWorkerRuntime: Send + Sync { } #[derive(Clone)] -pub struct WorkerRuntimeRegistry { +pub struct RuntimeRegistry { runtimes: Vec>, } -impl WorkerRuntimeRegistry { +impl RuntimeRegistry { pub fn new(runtimes: Vec>) -> Self { Self { runtimes } } @@ -582,6 +646,7 @@ impl WorkspaceWorkerRuntime for LocalWorkerRuntime { label: "Local Worker runtime".to_string(), kind: "local_pod".to_string(), status: "available".to_string(), + source: RuntimeSourceSummary::local_compatibility(), host_ids: host_list .items .iter() @@ -1011,7 +1076,7 @@ mod tests { fn registry_lists_runtimes_hosts_and_workers() { let temp = TempDir::new().unwrap(); write_metadata(temp.path(), "coder", &metadata(Some("/workspace/project"))); - let registry = WorkerRuntimeRegistry::for_local_pods(LocalWorkerRuntime::new( + let registry = RuntimeRegistry::for_local_pods(LocalWorkerRuntime::new( "local:test", "/workspace/project", Some(temp.path().to_path_buf()), @@ -1019,6 +1084,14 @@ mod tests { let runtimes = registry.list_runtimes(10); assert_eq!(runtimes.items[0].runtime_id, LOCAL_RUNTIME_ID); + assert_eq!( + runtimes.items[0].source.kind, + RuntimeSourceKind::LocalCompatibility + ); + assert_eq!( + runtimes.items[0].source.identity_authority, + RuntimeIdentityAuthority::RuntimeRegistryProjection + ); assert_eq!(runtimes.items[0].host_ids, vec![host_id()]); let hosts = registry.list_hosts(10); @@ -1043,7 +1116,7 @@ mod tests { fn registry_resolves_backend_validated_host_ids() { let temp = TempDir::new().unwrap(); write_metadata(temp.path(), "coder", &metadata(Some("/workspace/project"))); - let registry = WorkerRuntimeRegistry::for_local_pods(LocalWorkerRuntime::new( + let registry = RuntimeRegistry::for_local_pods(LocalWorkerRuntime::new( "local:test", "/workspace/project", Some(temp.path().to_path_buf()), @@ -1133,7 +1206,7 @@ mod tests { "/workspace/project", Some(temp.path().to_path_buf()), ); - let registry = WorkerRuntimeRegistry::for_local_pods(bridge.clone()); + let registry = RuntimeRegistry::for_local_pods(bridge.clone()); let listed = registry.list_workers(100); assert_eq!(listed.items.len(), worker_names.len()); diff --git a/crates/workspace-server/src/server.rs b/crates/workspace-server/src/server.rs index 6f15a305..32e74bbf 100644 --- a/crates/workspace-server/src/server.rs +++ b/crates/workspace-server/src/server.rs @@ -11,8 +11,8 @@ use serde::{Deserialize, Serialize}; use tokio::net::TcpListener; use crate::hosts::{ - DiagnosticSeverity, HostSummary, LocalWorkerRuntime, RuntimeDiagnostic, RuntimeSummary, - WorkerRuntimeRegistry, WorkerSummary, + DiagnosticSeverity, HostSummary, LocalWorkerRuntime, RuntimeDiagnostic, RuntimeRegistry, + RuntimeSummary, WorkerSummary, }; use crate::identity::WorkspaceIdentity; use crate::records::{ @@ -64,7 +64,7 @@ pub struct WorkspaceApi { config: ServerConfig, store: Arc, records: LocalProjectRecordReader, - runtime: Arc, + runtime: Arc, } impl WorkspaceApi { @@ -78,13 +78,11 @@ impl WorkspaceApi { updated_at: config.workspace_created_at.clone(), }) .await?; - let runtime = Arc::new(WorkerRuntimeRegistry::for_local_pods( - LocalWorkerRuntime::new( - config.workspace_id.clone(), - config.workspace_root.clone(), - config.local_runtime_data_dir.clone(), - ), - )); + let runtime = Arc::new(RuntimeRegistry::for_local_pods(LocalWorkerRuntime::new( + config.workspace_id.clone(), + config.workspace_root.clone(), + config.local_runtime_data_dir.clone(), + ))); Ok(Self { records: LocalProjectRecordReader::new(config.workspace_root.clone()), config, @@ -746,6 +744,15 @@ mod tests { let runtimes = get_json(app.clone(), "/api/runtimes").await; assert_eq!(runtimes["source"], "worker_runtime_registry"); assert_eq!(runtimes["items"][0]["runtime_id"], "local-worker-runtime"); + assert_eq!( + runtimes["items"][0]["source"]["kind"], + "local_compatibility" + ); + assert_eq!( + runtimes["items"][0]["source"]["identity_authority"], + "runtime_registry_projection" + ); + assert!(!runtimes.to_string().contains("/workspace/demo")); assert_eq!(runtimes["items"][0]["host_ids"][0], host_id); let workers = get_json(app.clone(), "/api/workers").await;