Sync public tree to c852e65

This commit is contained in:
Michel Paulissen 2026-07-04 12:53:18 +02:00
parent 4e04601794
commit e2bc145f60
4 changed files with 223 additions and 7 deletions

View file

@ -1921,6 +1921,10 @@ fn artifact_download_report(args: ArtifactDownloadArgs) -> Result<Value> {
"status": "requires_coordinator",
"link_issued": false,
"explicit_user_action_required": true,
"machine_error": cli_error_summary_for_category(
"connectivity",
"artifact download requires a coordinator"
),
},
"grant_disclosures": [],
}))
@ -1949,6 +1953,11 @@ fn artifact_export_report(args: ArtifactExportArgs) -> Result<Value> {
"explicit_user_action": true,
"local_path": &args.to,
"local_bytes_written_by_cli": false,
"machine_error": artifact_response_machine_error(
&response,
"coordinator rejected artifact export",
"connectivity"
),
})
};
apply_local_export_summary(&mut export_plan, &local_export);
@ -1980,6 +1989,10 @@ fn artifact_export_report(args: ArtifactExportArgs) -> Result<Value> {
"explicit_user_action": true,
"local_bytes_written_by_cli": false,
"default_durable_store_assumed": false,
"machine_error": cli_error_summary_for_category(
"connectivity",
"artifact export requires a coordinator"
),
},
"grant_disclosures": [],
}))
@ -2014,6 +2027,11 @@ fn artifact_export_local_write_followup(
"content_bytes_available": false,
"download_session": artifact_download_session_summary(&link_response),
"grant_disclosures": [],
"machine_error": artifact_response_machine_error(
&link_response,
"coordinator rejected artifact download for local export",
"connectivity"
),
"link_response": link_response,
}));
}
@ -2045,6 +2063,11 @@ fn artifact_export_local_write_followup(
"content_bytes_available": false,
"download_session": download_session,
"grant_disclosures": grant_disclosures,
"machine_error": artifact_response_machine_error(
&stream_response,
"coordinator rejected artifact download stream",
"connectivity"
),
"stream": artifact_stream_summary(&stream_response),
}));
}
@ -2061,6 +2084,10 @@ fn artifact_export_local_write_followup(
"content_bytes_available": false,
"download_session": download_session,
"grant_disclosures": grant_disclosures,
"machine_error": cli_error_summary_for_category(
"program",
"artifact download stream opened without content"
),
"stream": artifact_stream_summary(&stream_response),
}));
};
@ -2089,7 +2116,11 @@ fn artifact_export_local_write_followup(
}
fn artifact_stream_summary(response: &Value) -> Value {
json!({
let status = response
.get("type")
.and_then(Value::as_str)
.unwrap_or("coordinator_response");
let mut summary = json!({
"status": response.get("type").and_then(Value::as_str).unwrap_or("coordinator_response"),
"streamed_bytes": response.get("streamed_bytes").cloned().unwrap_or_else(|| json!(0)),
"charged_download_bytes": response.get("charged_download_bytes").cloned().unwrap_or_else(|| json!(0)),
@ -2097,7 +2128,20 @@ fn artifact_stream_summary(response: &Value) -> Value {
"content_source": response.get("content_source").cloned().unwrap_or(Value::Null),
"content_material_returned_in_report": false,
"error": response.get("message").cloned().unwrap_or(Value::Null),
})
});
if status != "artifact_download_stream" {
if let Some(object) = summary.as_object_mut() {
object.insert(
"machine_error".to_owned(),
artifact_response_machine_error(
response,
"coordinator rejected artifact download stream",
"connectivity",
),
);
}
}
summary
}
fn apply_local_export_summary(export_plan: &mut Value, local_export: &Value) {
@ -2592,6 +2636,17 @@ fn human_report(value: &Value) -> String {
}
push_machine_error_line(&mut lines, value.get("machine_error"));
push_machine_error_line(&mut lines, value.pointer("/run_start/machine_error"));
push_machine_error_line(&mut lines, value.pointer("/download_session/machine_error"));
push_machine_error_line(&mut lines, value.pointer("/export_plan/machine_error"));
push_machine_error_line(&mut lines, value.pointer("/local_export/machine_error"));
push_machine_error_line(
&mut lines,
value.pointer("/local_export/download_session/machine_error"),
);
push_machine_error_line(
&mut lines,
value.pointer("/local_export/stream/machine_error"),
);
if let Some(flow) = value.get("human_flow") {
if let Some(device) = flow.get("Device") {
lines.push("flow: device".to_owned());
@ -2931,6 +2986,11 @@ fn apply_command_report_exit_code(value: &mut Value) -> Option<i32> {
"/restart_request/machine_error",
"/cancel_request/machine_error",
"/task_restart/machine_error",
"/download_session/machine_error",
"/export_plan/machine_error",
"/local_export/machine_error",
"/local_export/download_session/machine_error",
"/local_export/stream/machine_error",
] {
let Some(machine_error) = value.pointer_mut(pointer) else {
continue;
@ -4126,6 +4186,15 @@ fn response_error_message(response: &Value, fallback: &str) -> String {
.unwrap_or_else(|| fallback.to_owned())
}
fn artifact_response_machine_error(
response: &Value,
fallback: &str,
default_category: &'static str,
) -> Value {
let message = response_error_message(response, fallback);
cli_error_summary_with_default(&message, default_category)
}
fn process_restart_request_summary(response: &Value, requires_confirmation: bool) -> Value {
if response.get("type").and_then(Value::as_str) != Some("process_started") {
let message = response_error_message(response, "coordinator rejected process restart");
@ -4248,11 +4317,13 @@ fn task_restart_request_summary(response: &Value, requires_confirmation: bool) -
fn artifact_download_session_summary(response: &Value) -> Value {
if response.get("type").and_then(Value::as_str) != Some("artifact_download_link") {
let message = response_error_message(response, "coordinator rejected artifact download");
return json!({
"status": response.get("type").and_then(Value::as_str).unwrap_or("coordinator_response"),
"link_issued": false,
"explicit_user_action_required": true,
"error": response.get("message").cloned().unwrap_or(Value::Null),
"error": message.clone(),
"machine_error": cli_error_summary_with_default(&message, "connectivity"),
});
}
@ -4317,13 +4388,15 @@ fn artifact_download_grant_disclosures(response: &Value) -> Value {
fn artifact_export_plan_summary(response: &Value, to: &Path) -> Value {
if response.get("type").and_then(Value::as_str) != Some("artifact_export_plan") {
let message = response_error_message(response, "coordinator rejected artifact export");
return json!({
"status": response.get("type").and_then(Value::as_str).unwrap_or("coordinator_response"),
"explicit_user_action": true,
"local_path": to,
"local_bytes_written_by_cli": false,
"default_durable_store_assumed": false,
"error": response.get("message").cloned().unwrap_or(Value::Null),
"error": message.clone(),
"machine_error": cli_error_summary_with_default(&message, "connectivity"),
});
}
@ -8563,6 +8636,65 @@ mod tests {
assert_eq!(export["export_plan"]["authorization_digest_present"], true);
}
#[test]
fn artifact_failure_reports_apply_stable_exit_codes() {
let mut download = json!({
"command": "artifact download",
"download_session": artifact_download_session_summary(&json!({
"type": "error",
"message": "artifact download unauthorized for project",
})),
});
assert_eq!(apply_command_report_exit_code(&mut download), Some(21));
assert_eq!(
download["download_session"]["machine_error"]["category"],
"authorization"
);
assert_eq!(
download["download_session"]["machine_error"]["process_exit_code_applied"],
true
);
let mut export = json!({
"command": "artifact export",
"export_plan": artifact_export_plan_summary(
&json!({
"type": "error",
"message": "direct connectivity unavailable for artifact export",
}),
Path::new("dist/app.txt"),
),
});
assert_eq!(apply_command_report_exit_code(&mut export), Some(25));
assert_eq!(
export["export_plan"]["machine_error"]["category"],
"connectivity"
);
assert_eq!(
export["export_plan"]["machine_error"]["process_exit_code_applied"],
true
);
let mut stream = json!({
"command": "artifact export",
"local_export": {
"stream": artifact_stream_summary(&json!({
"type": "error",
"message": "quota unavailable: resource limit exceeded for artifact_download_bytes",
})),
},
});
assert_eq!(apply_command_report_exit_code(&mut stream), Some(22));
assert_eq!(
stream["local_export"]["stream"]["machine_error"]["category"],
"quota"
);
assert_eq!(
stream["local_export"]["stream"]["machine_error"]["process_exit_code_applied"],
true
);
}
#[test]
fn process_restart_and_cancel_reports_expose_control_boundaries() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();