fix: preserve repository key for backend validation
This commit is contained in:
@@ -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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user