mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-15 23:32:46 +00:00
Return 404 when a worker's originating run is missing
The worker folder-target guard opened a run reader and mapped every failure, including a run that no longer exists, to HTTP 500 with an error log. Load the projection through the store's lookup instead so a missing run is a 404 with its own error code, and run the check after environment selection so ordinary environment errors are reported first. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
b12eb8d84e
commit
da0b4c259a
3 changed files with 47 additions and 14 deletions
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue