fix: preserve repository key for backend validation

This commit is contained in:
2026-10-02 14:34:51 +09:00
parent 013f909b9b
commit 7b13303724
2 changed files with 45 additions and 18 deletions
+22 -2
View File
@@ -195,12 +195,14 @@ fn prompt_create_request_with_io(
let Some(display_name) = prompt_line(input, output, "Workspace display name: ")? else { let Some(display_name) = prompt_line(input, output, "Workspace display name: ")? else {
return Ok(None); return Ok(None);
}; };
let display_name = display_name.trim().to_string();
if display_name.is_empty() { if display_name.is_empty() {
return Ok(None); return Ok(None);
} }
let Some(uri) = prompt_line(input, output, "Initial repository absolute path/URI: ")? else { let Some(uri) = prompt_line(input, output, "Initial repository absolute path/URI: ")? else {
return Ok(None); return Ok(None);
}; };
let uri = uri.trim().to_string();
if uri.is_empty() { if uri.is_empty() {
writeln!(output, "Repository path/URI is required.")?; writeln!(output, "Repository path/URI is required.")?;
return Ok(None); return Ok(None);
@@ -210,7 +212,7 @@ fn prompt_create_request_with_io(
else { else {
return Ok(None); return Ok(None);
}; };
if repository_key.is_empty() { if repository_key.trim().is_empty() {
writeln!(output, "Repository key is required.")?; writeln!(output, "Repository key is required.")?;
continue; continue;
} }
@@ -220,6 +222,7 @@ fn prompt_create_request_with_io(
else { else {
return Ok(None); return Ok(None);
}; };
let default_ref = default_ref.trim().to_string();
let operation_key = format!( let operation_key = format!(
"tui-workspace-create-{}-{}", "tui-workspace-create-{}-{}",
std::process::id(), std::process::id(),
@@ -250,7 +253,13 @@ fn prompt_line(
if input.read_line(&mut value)? == 0 { if input.read_line(&mut value)? == 0 {
return Ok(None); return Ok(None);
} }
Ok(Some(value.trim().to_string())) if value.ends_with('\n') {
value.pop();
if value.ends_with('\r') {
value.pop();
}
}
Ok(Some(value))
} }
#[cfg(test)] #[cfg(test)]
@@ -300,6 +309,17 @@ mod tests {
assert_eq!(output.matches("Repository key (required): ").count(), 3); assert_eq!(output.matches("Repository key (required): ").count(), 3);
} }
#[test]
fn workspace_creation_does_not_normalize_a_nonblank_repository_key() {
let (request, _) = prompt_create("Workspace\n/srv/repository\n platform \n\n");
assert_eq!(
request.unwrap().repository.repository_key,
" platform ",
"the Backend must validate the creator's exact Repository key"
);
}
#[test] #[test]
fn workspace_creation_accepts_explicit_main_repository_key() { fn workspace_creation_accepts_explicit_main_repository_key() {
let (request, _) = prompt_create("Workspace\n/srv/repository\nmain\n\n"); let (request, _) = prompt_create("Workspace\n/srv/repository\nmain\n\n");
@@ -336,7 +336,7 @@ mod tests {
} }
#[test] #[test]
fn create_rejects_blank_repository_key_without_persisting_a_workspace() { fn create_rejects_noncanonical_repository_keys_without_persisting_a_workspace() {
let store = Arc::new(SqliteWorkspaceStore::in_memory().unwrap()); let store = Arc::new(SqliteWorkspaceStore::in_memory().unwrap());
let service = WorkspaceCatalogService::new( let service = WorkspaceCatalogService::new(
store.clone(), store.clone(),
@@ -345,24 +345,31 @@ mod tests {
), ),
); );
let repository = git_repository(); let repository = git_repository();
let owner_account_id = owner_account(store.as_ref());
for (operation_key, repository_key) in [
("blank-repository-key", " "),
("spaced-repository-key", " platform "),
] {
let request = WorkspaceCreateRequest { let request = WorkspaceCreateRequest {
operation_key: "blank-repository-key".to_string(), operation_key: operation_key.to_string(),
display_name: "Workspace A".to_string(), display_name: "Workspace A".to_string(),
repository: InitialRepositoryIntent { repository: InitialRepositoryIntent {
uri: repository.path().display().to_string(), uri: repository.path().display().to_string(),
repository_key: " ".to_string(), repository_key: repository_key.to_string(),
default_ref: None, default_ref: None,
}, },
}; };
let error = service let error = service
.create(request, owner_account(store.as_ref())) .create(request, owner_account_id.clone())
.unwrap_err() .unwrap_err()
.to_string(); .to_string();
assert!(error.contains("invalid Repository key"), "{error}"); assert!(error.contains("invalid Repository key"), "{error}");
assert!(store.list_workspaces().unwrap().is_empty()); assert!(store.list_workspaces().unwrap().is_empty());
} }
}
#[tokio::test] #[tokio::test]
async fn create_recovers_same_reserved_identity_after_material_write_failure() { async fn create_recovers_same_reserved_identity_after_material_write_failure() {