diff --git a/lib/apps/fabro-server/src/run_intent.rs b/lib/apps/fabro-server/src/run_intent.rs index 0a04fc7cf..32c6f4eea 100644 --- a/lib/apps/fabro-server/src/run_intent.rs +++ b/lib/apps/fabro-server/src/run_intent.rs @@ -46,6 +46,8 @@ pub(crate) enum RunIntentAdmissionError { #[source] source: fabro_store::Error, }, + #[error("originating worker run `{run_id}` was not found")] + WorkerRunNotFound { run_id: RunId }, } #[derive(Debug, Error)] diff --git a/lib/apps/fabro-server/src/server/handler/runs.rs b/lib/apps/fabro-server/src/server/handler/runs.rs index 07170f769..b2de8d3c6 100644 --- a/lib/apps/fabro-server/src/server/handler/runs.rs +++ b/lib/apps/fabro-server/src/server/handler/runs.rs @@ -631,9 +631,6 @@ pub(crate) async fn create_run_from_intent( Ok(validated) => validated, Err(error) => return run_intent_admission_error(error.into()), }; - if let Err(error) = validate_intent_actor_target(&state, &actor, &target).await { - return run_intent_admission_error(error); - } let environment_id = match select_intent_environment_id( &state, intent @@ -644,6 +641,9 @@ pub(crate) async fn create_run_from_intent( Ok(id) => id, Err(error) => return run_intent_admission_error(error.into()), }; + if let Err(error) = validate_intent_actor_target(&state, &actor, &target).await { + return run_intent_admission_error(error); + } let blobs = state.store_ref().blobs(); let version_store = fabro_workflow_version::WorkflowVersionStore::new(blobs); let closure = match version_store.get_closure(&intent.workflow_version_id).await { @@ -1007,6 +1007,7 @@ fn run_intent_admission_error(error: RunIntentAdmissionError) -> Response { } RunIntentAdmissionError::Target(_) | RunIntentAdmissionError::FolderTarget(_) + | RunIntentAdmissionError::WorkerRunNotFound { .. } | RunIntentAdmissionError::Environment(_) => {} } @@ -1085,6 +1086,11 @@ fn run_intent_admission_error(error: RunIntentAdmissionError) -> Response { "failed to inspect originating worker run", "worker_run_store_error", ), + RunIntentAdmissionError::WorkerRunNotFound { .. } => intent_error( + StatusCode::NOT_FOUND, + "originating worker run not found", + "worker_run_not_found", + ), } } @@ -1096,23 +1102,16 @@ async fn validate_intent_actor_target( let (Principal::Worker { run_id }, RunTarget::Folder { .. }) = (actor, target) else { return Ok(()); }; - let run_store = state + let projection = state .stores .runs - .open_run_reader(run_id) + .load_run_projection(run_id) .await .map_err(|source| RunIntentAdmissionError::WorkerRun { run_id: *run_id, source, - })?; - let projection = - run_store - .state() - .await - .map_err(|source| RunIntentAdmissionError::WorkerRun { - run_id: *run_id, - source, - })?; + })? + .ok_or(RunIntentAdmissionError::WorkerRunNotFound { run_id: *run_id })?; if !projection.spec.settings.run.environment.provider.is_local() { return Err(EnvironmentSelectionError::TargetUnsupported { detail: "folder targets created by a worker require a Local parent environment", diff --git a/lib/apps/fabro-server/src/server/tests.rs b/lib/apps/fabro-server/src/server/tests.rs index d34398253..3dfadcf15 100644 --- a/lib/apps/fabro-server/src/server/tests.rs +++ b/lib/apps/fabro-server/src/server/tests.rs @@ -4536,6 +4536,38 @@ async fn run_tools_worker_cannot_select_server_folder_from_clone_based_parent() ); } +#[tokio::test] +async fn run_tools_worker_folder_target_from_missing_parent_run_is_not_found() { + let dir = tempfile::tempdir().unwrap(); + let (state, app) = jwt_auth_app(); + let worker_token = issue_test_run_tools_worker_token(&RunId::new()); + let workflow_version_id = store_workflow_version(&state, MINIMAL_DOT, None).await; + let mut intent = folder_intent(workflow_version_id, dir.path().to_string_lossy()); + intent["environment_id"] = json!("local"); + + let response = app + .oneshot(json_bearer_request( + Method::POST, + "/runs", + &worker_token, + &intent, + )) + .await + .unwrap(); + let body = response_json!(response, StatusCode::NOT_FOUND).await; + + assert_eq!(body["errors"][0]["code"], "worker_run_not_found"); + assert!( + state + .stores + .run_summaries + .list_identities() + .await + .unwrap() + .is_empty() + ); +} + #[tokio::test] async fn run_tools_worker_can_select_server_folder_from_local_parent() { let dir = tempfile::tempdir().unwrap();