-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add Bun TypeScript SDK as a workspace package #18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -143,20 +143,47 @@ async fn list_services( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _auth: RequireAuth, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| State(state): State<Arc<ServerState>>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) -> impl IntoResponse { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // A misconfigured `--services` path must not look like an empty directory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Swallowing the error here returns `{"services": []}` with HTTP 200, which | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // is indistinguishable from "no services installed". | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let entries = match fs::read_dir(&state.services_path) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(entries) => entries, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Err(e) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tracing::error!( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path = %state.services_path.display(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error = %e, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "cannot read the configured services directory" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| StatusCode::INTERNAL_SERVER_ERROR, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Json(serde_json::json!({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "error": format!( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Cannot read services directory {}: {}", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| state.services_path.display(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| })), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut services = Vec::new(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if let Ok(entries) = fs::read_dir(&state.services_path) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for entry in entries.flatten() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let path = entry.path(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if let Some(name) = path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .file_name() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .and_then(|n| n.to_str()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .filter(|_| path.is_dir()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| services.push(name.to_string()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for entry in entries.flatten() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let path = entry.path(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if let Some(name) = path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .file_name() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .and_then(|n| n.to_str()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .filter(|_| path.is_dir()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| services.push(name.to_string()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Json(serde_json::json!({ "services": services })) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Directory order is filesystem-dependent; sort so the API is deterministic. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| services.sort(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| StatusCode::OK, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Json(serde_json::json!({ "services": services })), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[derive(Deserialize)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -229,7 +256,34 @@ async fn execute_service_handler( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ..ExecuteOptions::default() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| match execute_service(&service_dir, options, None, None) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // `execute_service` is synchronous and runs for the entire lifetime of the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // microVM. Calling it directly from an async handler parks a Tokio worker | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // thread for that whole duration, so enough concurrent executions starve | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // the runtime and stall every other route, including `/health`. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let result = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tokio::task::spawn_blocking(move || execute_service(&service_dir, options, None, None)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .await; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let result = match result { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(result) => result, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Err(join_err) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // The blocking task panicked or was cancelled. Surface it rather | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // than reporting success with no metrics. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tracing::error!(error = %join_err, "service execution task failed to complete"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| StatusCode::INTERNAL_SERVER_ERROR, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Json(ExecuteResponse { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| success: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| service_name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| metrics: None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| preflight: None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error: Some(format!("Execution task failed to complete: {join_err}")), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| match result { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+259
to
+286
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the declared Tokio version and all execution-admission controls.
rg -n -C 4 \
-g 'Cargo.toml' -g 'Cargo.lock' -g '*.rs' \
'tokio|spawn_blocking|Semaphore|execute_service_handler|struct ServerState' .Repository: dev-dami/ignite Length of output: 12060 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== Cargo workspace Tokio dependency =="
sed -n '1,30p' Cargo.toml
echo
echo "== ServerState definition and execute handler outline =="
sed -n '1,45p' ignite-http/src/server.rs
echo
sed -n '200,295p' ignite-http/src/server.rs
echo
echo "== Existing Semaphore/Concurrency controls =="
rg -n '\bSemaphore\b|semaphore|try_acquire|acquire_owned|tokio::sync' ignite-http/src/server.rs ignition-http ignite-shared ignite-core ignite-cli || true
echo
echo "== Runtime/blocking-task settings around Tokio main and serve =="
sed -n '1,90p' ignite-http/src/main.rs
echo
echo "== Static probe: count spawn_blocking under execute_service_handler and ServerState fields =="
python3 - <<'PY'
from pathlib import Path
p=Path('ignite-http/src/server.rs')
text=p.read_text()
start=text.find(' async fn execute_service_handler')
end=text.find('\n pub fn create_router', start)
body=text[start:end] if start!=-1 and end!=-1 else ''
print("spawn_blocking_count=", body.count('spawn_blocking'))
print("ServerState fields in file:")
for i,line in enumerate(Path('ignite-http/src/server.rs').read_text().splitlines(),1):
if 'pub struct ServerState' in line or 'Semaphore' in line or 'RateLimiter' in line:
print(f"{i}: {line}")
PYRepository: dev-dami/ignite Length of output: 8973 Bound concurrent service executions before
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok((preflight, metrics)) => ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| StatusCode::OK, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Json(ExecuteResponse { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -344,4 +398,94 @@ mod tests { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Previously hardcoded to 0.1.0 while the crate was 0.9.0. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_eq!(env!("CARGO_PKG_VERSION"), "0.9.0"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn test_state(services_path: PathBuf) -> Arc<ServerState> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Arc::new(ServerState { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| services_path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| api_key: None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rate_limiter: RateLimiter::new(1000, 60), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| kernel_path: None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rootfs_path: None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| runtimes_root: None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| allowed_origins: Vec::new(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async fn get(state: Arc<ServerState>, uri: &str) -> (StatusCode, serde_json::Value) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use tower::ServiceExt; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let response = create_router(state) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .oneshot( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| axum::http::Request::builder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .uri(uri) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .body(axum::body::Body::empty()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .unwrap(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .await | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let status = response.status(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let bytes = axum::body::to_bytes(response.into_body(), usize::MAX) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .await | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let json = serde_json::from_slice(&bytes).unwrap_or(serde_json::Value::Null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (status, json) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[tokio::test] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async fn list_services_returns_directory_names_sorted() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let dir = tempfile::tempdir().unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for name in ["zebra", "alpha", "middle"] { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs::create_dir(dir.path().join(name)).unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // A stray file is not a service and must not be listed. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs::write(dir.path().join("notes.txt"), b"x").unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let (status, body) = get(test_state(dir.path().to_path_buf()), "/services").await; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_eq!(status, StatusCode::OK); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_eq!( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body["services"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| serde_json::json!(["alpha", "middle", "zebra"]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[tokio::test] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async fn list_services_reports_an_unreadable_directory_instead_of_an_empty_list() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Previously this swallowed the error and returned `{"services": []}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // with HTTP 200, making a misconfigured path look like an empty one. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let missing = PathBuf::from("/nonexistent/ignite-services-should-not-exist"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let (status, body) = get(test_state(missing), "/services").await; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_eq!(status, StatusCode::INTERNAL_SERVER_ERROR); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert!( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body["error"].as_str().unwrap_or("").contains("Cannot read"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "expected a read failure message, got {body}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert!( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body.get("services").is_none(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "a failed listing must not report a services array" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+453
to
+470
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Use a temporary path for the missing-directory test. Line 457 embeds an absolute host path. The path can exist on a test host and makes the test depend on host filesystem layout. Create a missing child under As per coding guidelines: “Never introduce secrets, tokens, or host-specific paths into committed Rust code.” Proposed fix- let missing = PathBuf::from("/nonexistent/ignite-services-should-not-exist");
+ let dir = tempfile::tempdir().unwrap();
+ let missing = dir.path().join("missing");📝 Committable suggestion
Suggested change
🤖 Prompt for AI AgentsSource: Coding guidelines |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[tokio::test] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async fn execute_rejects_invalid_service_names_before_touching_the_filesystem() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use tower::ServiceExt; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let dir = tempfile::tempdir().unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let response = create_router(test_state(dir.path().to_path_buf())) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .oneshot( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| axum::http::Request::builder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .method("POST") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .uri("/services/..%2f..%2fetc/execute") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .header("content-type", "application/json") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .body(axum::body::Body::from("{}")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .unwrap(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .await | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_eq!(response.status(), StatusCode::BAD_REQUEST); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Return an error for directory iteration failures.
Line 171 discards
ReadDirerrors withflatten(). If iteration fails after the directory opens, this endpoint returns a partial service list with HTTP 200. Handle eachResult<DirEntry, io::Error>and return the same HTTP 500 response used for the initialread_dirfailure.🤖 Prompt for AI Agents