refactor(api): rename workspace-api authority to server-api

Absorb the Server HTTP DTO catalog and generators into server-api, remove the obsolete workspace-api package/path, preserve the separate runtime transport authority through explicit boundary DTO conversions, and rename the aggregate frontend projection as a bounded legacy artifact.
This commit is contained in:
2026-09-18 06:21:46 +09:00
parent 9566ad3482
commit c6cb038683
93 changed files with 6062 additions and 6562 deletions
+1 -1
View File
@@ -50,7 +50,7 @@ uuid = { workspace = true, features = ["v7"] }
zeroize.workspace = true
tower = { workspace = true, features = ["util"], optional = true }
worker.workspace = true
workspace-api = { path = "../workspace-api" }
server-api = { path = "../server-api" }
workdir.workspace = true
[dev-dependencies]
+2 -2
View File
@@ -74,7 +74,7 @@ impl std::ops::Deref for RepositorySelector {
pub struct WorkingDirectoryRepository {
pub id: String,
pub provider: String,
pub source: workspace_api::RepositorySource,
pub source: server_api::RepositorySource,
pub source_revision: u64,
pub source_fingerprint: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
@@ -131,7 +131,7 @@ pub struct RepositorySshMaterializationAccess {
pub credential_candidates: Vec<RepositorySshCredentialCandidate>,
pub host_trust_id: String,
pub host_trust_revision: u64,
pub access: workspace_api::RepositoryAccessMode,
pub access: server_api::RepositoryAccessMode,
pub expires_at_epoch_seconds: u64,
pub repository_id: String,
pub repository_source_fingerprint: String,
+1 -1
View File
@@ -2584,9 +2584,9 @@ mod tests {
use axum::body::to_bytes;
use axum::http::Method;
use manifest::{Scope, SharedScope};
use runtime_api::WorkerRestoreState;
use sha2::Digest as _;
use tower::ServiceExt;
use workspace_api::WorkerRestoreState;
#[derive(Clone)]
struct TestRuntimeAuthorizer(String);
@@ -377,7 +377,20 @@ impl runtime_api::RuntimeApi for RuntimeManagementApi {
.map_err(RuntimeHttpRestError::runtime)
.map_err(api_error)?;
Ok(runtime_api::WorkerRestoreResponse {
state: result.state,
state: match result.state {
server_api::WorkerRestoreState::Accepted => {
runtime_api::WorkerRestoreState::Accepted
}
server_api::WorkerRestoreState::Rejected => {
runtime_api::WorkerRestoreState::Rejected
}
server_api::WorkerRestoreState::RolledBack => {
runtime_api::WorkerRestoreState::RolledBack
}
server_api::WorkerRestoreState::ReconciliationRequired => {
runtime_api::WorkerRestoreState::ReconciliationRequired
}
},
worker: result.worker.map(response).transpose()?,
reason_code: result.reason_code,
message: result.message,
+1 -1
View File
@@ -1355,8 +1355,8 @@ mod tests {
#[test]
fn workspace_issuer_trust_cli_persists_across_reload_and_writes_private_mode() {
use server_api::WorkspacePublicIdentityBundle;
use sha2::{Digest as _, Sha256};
use workspace_api::WorkspacePublicIdentityBundle;
let temp = tempfile::tempdir().unwrap();
let identity = RuntimeIdentityMaterial::generate("WK-1").unwrap();
+8 -8
View File
@@ -46,6 +46,7 @@ use protocol::subscription::{
SubscriptionWorkerState,
};
use protocol::{Event, Method};
use server_api::WorkerRestoreState;
use std::collections::BTreeMap;
#[cfg(feature = "ws-server")]
use std::collections::VecDeque;
@@ -55,7 +56,6 @@ use std::sync::{Arc, Mutex, MutexGuard, Weak};
use tokio::sync::broadcast;
use tokio::sync::mpsc;
use uuid::Uuid;
use workspace_api::WorkerRestoreState;
/// Workspace-scoped Runtime authorization context supplied by a trusted backend.
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -4835,8 +4835,8 @@ mod tests {
repository: WorkingDirectoryRepository {
id: "repository-1".to_string(),
provider: "git".to_string(),
source: workspace_api::RepositorySource {
kind: workspace_api::RepositorySourceKind::Ssh,
source: server_api::RepositorySource {
kind: server_api::RepositorySourceKind::Ssh,
uri: "ssh://git@example.test/repo.git".to_string(),
},
source_revision: 1,
@@ -4859,7 +4859,7 @@ mod tests {
}],
host_trust_id: "host-trust-1".to_string(),
host_trust_revision: 1,
access: workspace_api::RepositoryAccessMode::ReadOnly,
access: server_api::RepositoryAccessMode::ReadOnly,
expires_at_epoch_seconds: u64::MAX,
repository_id: "repository-1".to_string(),
repository_source_fingerprint: "sha256:source".to_string(),
@@ -4977,7 +4977,7 @@ mod tests {
],
host_trust_id: "host-trust-1".to_string(),
host_trust_revision: 1,
access: workspace_api::RepositoryAccessMode::ReadOnly,
access: server_api::RepositoryAccessMode::ReadOnly,
expires_at_epoch_seconds: u64::MAX,
repository_id: "repository-1".to_string(),
repository_source_fingerprint: "sha256:source".to_string(),
@@ -5066,8 +5066,8 @@ mod tests {
repository: WorkingDirectoryRepository {
id: "repository-1".to_string(),
provider: "git".to_string(),
source: workspace_api::RepositorySource {
kind: workspace_api::RepositorySourceKind::Ssh,
source: server_api::RepositorySource {
kind: server_api::RepositorySourceKind::Ssh,
uri: "ssh://git@example.test/repo.git".to_string(),
},
source_revision: 1,
@@ -5097,7 +5097,7 @@ mod tests {
],
host_trust_id: "host-trust-1".to_string(),
host_trust_revision: 1,
access: workspace_api::RepositoryAccessMode::ReadOnly,
access: server_api::RepositoryAccessMode::ReadOnly,
expires_at_epoch_seconds: u64::MAX,
repository_id: "repository-1".to_string(),
repository_source_fingerprint: "sha256:source".to_string(),
+2 -2
View File
@@ -3583,8 +3583,8 @@ mod tests {
repository: WorkingDirectoryRepository {
id: "repo-main".to_string(),
provider: "git".to_string(),
source: workspace_api::RepositorySource {
kind: workspace_api::RepositorySourceKind::LocalPath,
source: server_api::RepositorySource {
kind: server_api::RepositorySourceKind::LocalPath,
uri: repo.display().to_string(),
},
source_revision: 1,
+1 -1
View File
@@ -455,7 +455,7 @@ impl WorkspaceClient for RuntimeOwnedWorkspaceClient {
fn list_workspace_workers(
&self,
request: worker::WorkspaceWorkerDiscoveryRequest,
) -> Result<workspace_api::WorkspaceWorkerDiscoveryPage, WorkspaceClientError> {
) -> Result<server_api::WorkspaceWorkerDiscoveryPage, WorkspaceClientError> {
let mut path = format!(
"/api/w/{}/worker-discovery/workers?limit={}",
self.workspace_id, request.limit
+44 -46
View File
@@ -842,8 +842,8 @@ impl RuntimeGitMaterializer {
binding.command_environment.insert(
"YOI_REPOSITORY_ACCESS".to_string(),
match access.access {
workspace_api::RepositoryAccessMode::ReadOnly => "read_only",
workspace_api::RepositoryAccessMode::ReadWrite => "read_write",
server_api::RepositoryAccessMode::ReadOnly => "read_only",
server_api::RepositoryAccessMode::ReadWrite => "read_write",
}
.to_string(),
);
@@ -884,7 +884,7 @@ impl RuntimeGitMaterializer {
Self::validate_plain_http_source(request)?;
if matches!(
request.repository.source.kind,
workspace_api::RepositorySourceKind::Https | workspace_api::RepositorySourceKind::Ssh
server_api::RepositorySourceKind::Https | server_api::RepositorySourceKind::Ssh
) {
validate_remote_source_uri(request)?;
let materialization = request.materialization.as_ref().ok_or_else(|| {
@@ -906,10 +906,10 @@ impl RuntimeGitMaterializer {
}
}
match request.repository.source.kind {
workspace_api::RepositorySourceKind::LocalPath
| workspace_api::RepositorySourceKind::File
| workspace_api::RepositorySourceKind::Https => {}
workspace_api::RepositorySourceKind::Ssh => {
server_api::RepositorySourceKind::LocalPath
| server_api::RepositorySourceKind::File
| server_api::RepositorySourceKind::Https => {}
server_api::RepositorySourceKind::Ssh => {
let ssh = request
.materialization
.as_ref()
@@ -922,7 +922,7 @@ impl RuntimeGitMaterializer {
})?;
validate_ssh_materialization_access(ssh)?;
}
workspace_api::RepositorySourceKind::Invalid => {
server_api::RepositorySourceKind::Invalid => {
return Err(WorkingDirectoryDiagnostic::new(
"working_directory_repository_source_invalid",
"configured Repository source is invalid and cannot be materialized",
@@ -939,7 +939,7 @@ impl RuntimeGitMaterializer {
) -> Result<WorkingDirectoryRequest, WorkingDirectoryDiagnostic> {
let mut request = request.clone();
if request.repository.provider != "git"
|| request.repository.source.kind != workspace_api::RepositorySourceKind::Ssh
|| request.repository.source.kind != server_api::RepositorySourceKind::Ssh
{
return Ok(request);
}
@@ -1911,7 +1911,7 @@ struct RepositorySshCommandPolicy {
username: Option<String>,
port: Option<u16>,
repository_path: String,
access: workspace_api::RepositoryAccessMode,
access: server_api::RepositoryAccessMode,
}
impl RepositorySshCommandPolicy {
@@ -2053,9 +2053,7 @@ fn repository_command_matches(command: &str, policy: &RepositorySshCommandPolicy
} else {
return false;
};
if operation == "receive-pack"
&& policy.access != workspace_api::RepositoryAccessMode::ReadWrite
{
if operation == "receive-pack" && policy.access != server_api::RepositoryAccessMode::ReadWrite {
return false;
}
let argument = argument
@@ -2218,7 +2216,7 @@ impl RepositoryCommandAccess {
runtime_root: &Path,
request: &WorkingDirectoryRequest,
) -> Result<Option<Self>, WorkingDirectoryDiagnostic> {
if request.repository.source.kind != workspace_api::RepositorySourceKind::Ssh {
if request.repository.source.kind != server_api::RepositorySourceKind::Ssh {
return Ok(None);
}
let Some(ssh) = request
@@ -2403,7 +2401,7 @@ fn validate_ssh_materialization_access(
fn validate_remote_source_uri(
request: &WorkingDirectoryRequest,
) -> Result<(), WorkingDirectoryDiagnostic> {
if request.repository.source.kind == workspace_api::RepositorySourceKind::Ssh {
if request.repository.source.kind == server_api::RepositorySourceKind::Ssh {
let source =
parse_repository_ssh_source(&request.repository.source.uri).ok_or_else(|| {
WorkingDirectoryDiagnostic::new(
@@ -2441,7 +2439,7 @@ fn validate_remote_source_uri(
"remote Repository source URI is invalid",
)
})?;
if request.repository.source.kind != workspace_api::RepositorySourceKind::Https {
if request.repository.source.kind != server_api::RepositorySourceKind::Https {
return Ok(());
}
if url.scheme() != "https"
@@ -2512,7 +2510,7 @@ fn repository_git_command(
let mut command = isolated_git_command();
let file_policy = if matches!(
request.repository.source.kind,
workspace_api::RepositorySourceKind::LocalPath | workspace_api::RepositorySourceKind::File
server_api::RepositorySourceKind::LocalPath | server_api::RepositorySourceKind::File
) {
"always"
} else {
@@ -2589,7 +2587,7 @@ fn test_repository_git_invocation_count() -> usize {
fn run_repository_git_stdout(
mut command: Command,
source_kind: workspace_api::RepositorySourceKind,
source_kind: server_api::RepositorySourceKind,
) -> Result<String, WorkingDirectoryDiagnostic> {
#[cfg(test)]
TEST_REPOSITORY_GIT_INVOCATIONS.with(|count| count.set(count.get().saturating_add(1)));
@@ -2837,10 +2835,10 @@ fn resolve_cloned_commit(
fn apply_repository_access_policy(
repository_root: &Path,
access: workspace_api::RepositoryAccessMode,
access: server_api::RepositoryAccessMode,
) -> Result<(), WorkingDirectoryDiagnostic> {
match access {
workspace_api::RepositoryAccessMode::ReadOnly => {
server_api::RepositoryAccessMode::ReadOnly => {
let mut disable_push = isolated_git_command();
disable_push.arg("-C").arg(repository_root).args([
"remote",
@@ -2851,7 +2849,7 @@ fn apply_repository_access_policy(
]);
run_repository_git(disable_push, "working_directory_repository_policy_failed")
}
workspace_api::RepositoryAccessMode::ReadWrite => {
server_api::RepositoryAccessMode::ReadWrite => {
if git_stdout(
repository_root,
["config", "--get-all", "remote.origin.pushurl"],
@@ -3122,7 +3120,7 @@ mod tests {
}],
host_trust_id: "trust-1".to_string(),
host_trust_revision: 4,
access: workspace_api::RepositoryAccessMode::ReadOnly,
access: server_api::RepositoryAccessMode::ReadOnly,
expires_at_epoch_seconds: u64::MAX,
repository_id: "repo-main".to_string(),
repository_source_fingerprint: "sha256:test".to_string(),
@@ -3310,8 +3308,8 @@ mod tests {
repository: WorkingDirectoryRepository {
id: "repo-main".to_string(),
provider: "git".to_string(),
source: workspace_api::RepositorySource {
kind: workspace_api::RepositorySourceKind::LocalPath,
source: server_api::RepositorySource {
kind: server_api::RepositorySourceKind::LocalPath,
uri: repo.display().to_string(),
},
source_revision: 1,
@@ -3594,7 +3592,7 @@ mod tests {
assert!(!runtime_root.path().join(".repository-cache").exists());
let mut file_request = request(repo.path());
file_request.repository.source.kind = workspace_api::RepositorySourceKind::File;
file_request.repository.source.kind = server_api::RepositorySourceKind::File;
file_request.repository.source.uri = format!("file://{}", repo.path().display());
file_request.repository.source_revision = 2;
file_request.repository.source_fingerprint = "sha256:file-source".to_string();
@@ -3723,7 +3721,7 @@ mod tests {
],
host_trust_id: "trust-1".to_string(),
host_trust_revision: 1,
access: workspace_api::RepositoryAccessMode::ReadWrite,
access: server_api::RepositoryAccessMode::ReadWrite,
expires_at_epoch_seconds: u64::MAX,
repository_id: "repo-main".to_string(),
repository_source_fingerprint: "sha256:test".to_string(),
@@ -3735,8 +3733,8 @@ mod tests {
}),
});
let mut ssh_operation = request.clone();
ssh_operation.repository.source = workspace_api::RepositorySource {
kind: workspace_api::RepositorySourceKind::Ssh,
ssh_operation.repository.source = server_api::RepositorySource {
kind: server_api::RepositorySourceKind::Ssh,
uri: "ssh://git@example.test/repo.git".to_string(),
};
let command_access = RepositoryCommandAccess::prepare(runtime_root.path(), &ssh_operation)
@@ -3810,8 +3808,8 @@ mod tests {
request.backend_workdir_id = Some(working_directory_id.clone());
request.materialization.as_mut().unwrap().ssh = None;
let mut authorized_ssh_request = request.clone();
authorized_ssh_request.repository.source = workspace_api::RepositorySource {
kind: workspace_api::RepositorySourceKind::Ssh,
authorized_ssh_request.repository.source = server_api::RepositorySource {
kind: server_api::RepositorySourceKind::Ssh,
uri: "ssh://git@example.test/repo.git".to_string(),
};
assert!(
@@ -3910,7 +3908,7 @@ mod tests {
let mut rotated = initial_materialization.clone();
rotated.operation_id = "operation-agent-rotated".to_string();
rotated.ssh.as_mut().unwrap().credential_candidates[0].credential_revision = 2;
rotated.ssh.as_mut().unwrap().access = workspace_api::RepositoryAccessMode::ReadOnly;
rotated.ssh.as_mut().unwrap().access = server_api::RepositoryAccessMode::ReadOnly;
materializer
.authorize_repository_access(&WorkingDirectoryRepositoryAccessRequest {
working_directory_id: id.clone(),
@@ -4028,7 +4026,7 @@ mod tests {
let mut read_write = rotated;
read_write.operation_id = "operation-agent-read-write".to_string();
read_write.ssh.as_mut().unwrap().credential_candidates[0].credential_revision = 3;
read_write.ssh.as_mut().unwrap().access = workspace_api::RepositoryAccessMode::ReadWrite;
read_write.ssh.as_mut().unwrap().access = server_api::RepositoryAccessMode::ReadWrite;
let read_write_command_policy =
RepositorySshCommandPolicy::from_access(read_write.ssh.as_ref().unwrap()).unwrap();
materializer
@@ -4099,7 +4097,7 @@ mod tests {
}],
host_trust_id: "trust-1".to_string(),
host_trust_revision: 1,
access: workspace_api::RepositoryAccessMode::ReadOnly,
access: server_api::RepositoryAccessMode::ReadOnly,
expires_at_epoch_seconds: u64::MAX,
repository_id: "repo-main".to_string(),
repository_source_fingerprint: "sha256:test".to_string(),
@@ -4251,8 +4249,8 @@ mod tests {
assert_eq!(policy.repository_path, "team/repo.git");
let mut request = request(Path::new("."));
request.repository.source = workspace_api::RepositorySource {
kind: workspace_api::RepositorySourceKind::Ssh,
request.repository.source = server_api::RepositorySource {
kind: server_api::RepositorySourceKind::Ssh,
uri: uri.to_string(),
};
request.materialization = Some(crate::catalog::RepositoryMaterializationContext {
@@ -4294,8 +4292,8 @@ mod tests {
};
let mut https = request(repo.path());
https.repository.source = workspace_api::RepositorySource {
kind: workspace_api::RepositorySourceKind::Https,
https.repository.source = server_api::RepositorySource {
kind: server_api::RepositorySourceKind::Https,
uri: "https://token@example.test/repo.git".to_string(),
};
https.materialization = Some(context(None));
@@ -4330,15 +4328,15 @@ mod tests {
);
for (offset, kind) in [
workspace_api::RepositorySourceKind::LocalPath,
workspace_api::RepositorySourceKind::File,
workspace_api::RepositorySourceKind::Https,
server_api::RepositorySourceKind::LocalPath,
server_api::RepositorySourceKind::File,
server_api::RepositorySourceKind::Https,
]
.into_iter()
.enumerate()
{
let mut mismatched_http = request(repo.path());
mismatched_http.repository.source = workspace_api::RepositorySource {
mismatched_http.repository.source = server_api::RepositorySource {
kind,
uri: "http://example.test/repo.git".to_string(),
};
@@ -4358,8 +4356,8 @@ mod tests {
}
let mut ssh = request(repo.path());
ssh.repository.source = workspace_api::RepositorySource {
kind: workspace_api::RepositorySourceKind::Ssh,
ssh.repository.source = server_api::RepositorySource {
kind: server_api::RepositorySourceKind::Ssh,
uri: "ssh://git@example.test/repo.git".to_string(),
};
ssh.materialization = Some(context(Some(
@@ -4371,7 +4369,7 @@ mod tests {
}],
host_trust_id: "trust-1".to_string(),
host_trust_revision: 1,
access: workspace_api::RepositoryAccessMode::ReadOnly,
access: server_api::RepositoryAccessMode::ReadOnly,
expires_at_epoch_seconds: u64::MAX,
repository_id: "repo-main".to_string(),
repository_source_fingerprint: "sha256:test".to_string(),
@@ -4396,8 +4394,8 @@ mod tests {
let runtime_root = tempfile::tempdir().unwrap();
let materializer = RuntimeGitMaterializer::new(runtime_root.path());
let mut remote = request(Path::new("."));
remote.repository.source = workspace_api::RepositorySource {
kind: workspace_api::RepositorySourceKind::Ssh,
remote.repository.source = server_api::RepositorySource {
kind: server_api::RepositorySourceKind::Ssh,
uri: "ssh://git@example.invalid/repo.git".to_string(),
};
remote.materialization = Some(crate::catalog::RepositoryMaterializationContext {
@@ -8,8 +8,8 @@ use base64::Engine as _;
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
use ring::signature::Ed25519KeyPair;
use serde::{Deserialize, Serialize};
use server_api::WorkspacePublicIdentityBundle;
use sha2::{Digest, Sha256};
use workspace_api::WorkspacePublicIdentityBundle;
use crate::auth::RuntimeAuthError;