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

@ -1,7 +1,7 @@
{
"kind": "disasmer-filtered-public-tree",
"source_commit": "8a8f27c7bdaed2573256af31204dd4142be3319d",
"release_name": "dryrun-8a8f27c7bdae",
"source_commit": "c852e659435428b69cf3991a3fad015f60d121ff",
"release_name": "dryrun-c852e6594354",
"filtered_out": [
"private/**",
"experiments/**",

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();

View file

@ -34,6 +34,27 @@ function runDisasmer(args) {
});
}
async function runWithOneCoordinatorResponse(buildArgs, response) {
let request = "";
const server = net.createServer((socket) => {
socket.setEncoding("utf8");
socket.on("data", (chunk) => {
request += chunk;
if (!request.includes("\n")) return;
socket.write(JSON.stringify(response) + "\n");
socket.end();
server.close();
});
});
const address = await new Promise((resolve) => {
server.listen(0, "127.0.0.1", () => resolve(server.address()));
});
const coordinator = `http://${address.address}:${address.port}`;
const result = await runDisasmer(buildArgs(coordinator));
return { request, result };
}
async function main() {
const nonInteractive = await runDisasmer([
"run",
@ -120,6 +141,62 @@ async function main() {
report.run_start.machine_error.next_actions.includes("disasmer quota status")
);
const artifactDownload = await runWithOneCoordinatorResponse(
(coordinator) => [
"artifact",
"download",
"app.txt",
"--coordinator",
coordinator,
"--json",
],
{
type: "artifact_download_denied",
message: "artifact download unauthorized for project",
}
);
assert.strictEqual(artifactDownload.result.signal, null, artifactDownload.result.stderr);
assert.strictEqual(artifactDownload.result.code, 21, artifactDownload.result.stderr);
assert.match(artifactDownload.request, /"type":"create_artifact_download_link"/);
const artifactDownloadReport = JSON.parse(artifactDownload.result.stdout);
assert.strictEqual(
artifactDownloadReport.download_session.machine_error.category,
"authorization"
);
assert.strictEqual(
artifactDownloadReport.download_session.machine_error.process_exit_code_applied,
true
);
const artifactExport = await runWithOneCoordinatorResponse(
(coordinator) => [
"artifact",
"export",
"app.txt",
"--to",
path.join(project, "target", "blocked-artifact.txt"),
"--coordinator",
coordinator,
"--json",
],
{
type: "artifact_export_unavailable",
message: "direct connectivity unavailable for artifact export",
}
);
assert.strictEqual(artifactExport.result.signal, null, artifactExport.result.stderr);
assert.strictEqual(artifactExport.result.code, 25, artifactExport.result.stderr);
assert.match(artifactExport.request, /"type":"export_artifact_to_node"/);
const artifactExportReport = JSON.parse(artifactExport.result.stdout);
assert.strictEqual(
artifactExportReport.export_plan.machine_error.category,
"connectivity"
);
assert.strictEqual(
artifactExportReport.export_plan.machine_error.process_exit_code_applied,
true
);
const confirmation = await runDisasmer([
"process",
"cancel",

View file

@ -430,7 +430,12 @@ expect(
expect(
cli,
"CLI applies process exit code after printing command failure report",
/fn emit_report<T: Serialize>[\s\S]*apply_command_report_exit_code[\s\S]*std::process::exit\(exit_code\)/
/fn emit_report<T: Serialize>[\s\S]*apply_command_report_exit_code[\s\S]*std::process::exit\(exit_code\)[\s\S]*fn human_report/
);
expect(
cli,
"CLI applies artifact nested failure exit codes",
/fn apply_command_report_exit_code[\s\S]*"\/download_session\/machine_error"[\s\S]*"\/export_plan\/machine_error"[\s\S]*"\/local_export\/machine_error"[\s\S]*"\/local_export\/download_session\/machine_error"[\s\S]*"\/local_export\/stream\/machine_error"/
);
expect(
cli,
@ -541,6 +546,8 @@ for (const [name, pattern] of [
["actual quota resource-category assertion", /machine_error\.resource_category, "api_calls"/],
["actual quota community-tier label assertion", /machine_error\.community_tier_label,[\s\S]*"community tier"/],
["actual quota abuse-heuristics assertion", /machine_error\.private_abuse_heuristics_exposed,[\s\S]*false/],
["artifact download rejection exit code", /artifactDownload[\s\S]*assert\.strictEqual\(artifactDownload\.result\.code, 21/],
["artifact export rejection exit code", /artifactExport[\s\S]*assert\.strictEqual\(artifactExport\.result\.code, 25/],
["exit-code application in JSON", /process_exit_code_applied[\s\S]*true/],
]) {
expect(errorExitSmoke, name, pattern);