From a46f05e2e3af66e2fb8d951c66aa53e20fe8c57d Mon Sep 17 00:00:00 2001 From: zm-oai Date: Fri, 13 Nov 2026 01:19:28 +0000 Subject: [PATCH] Include AppX event IDs in Windows runtime registration errors (#61224) ## What changed Augment managed runtime package registration failures with `appx_event_ids` from error-level events in `Microsoft-Windows-AppXDeploymentServer/Operational` that match the deployment activity ID. Report numeric event IDs in sorted, deduplicated order without including free-form event text. Skip the lookup when the activity ID is unavailable or zero, and leave the registration result unchanged when event diagnostics are unavailable. GitOrigin-RevId: 50167f3ffed1d07936594ef4b04f5adf2972be8e --- codex-rs/windows-sandbox-service/Cargo.toml | 2 + .../registered_runtime/registration_result.rs | 13 ++++- .../registration_result/appx_events.rs | 57 +++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 codex-rs/windows-sandbox-service/src/registered_runtime/registration_result/appx_events.rs diff --git a/codex-rs/windows-sandbox-service/Cargo.toml b/codex-rs/windows-sandbox-service/Cargo.toml index b4652f858f..c822b221b8 100644 --- a/codex-rs/windows-sandbox-service/Cargo.toml +++ b/codex-rs/windows-sandbox-service/Cargo.toml @@ -37,6 +37,8 @@ features = [ "Foundation_Collections", "Management_Deployment", "Storage", + "Win32_Security", + "Win32_System_EventLog", "Win32_System_WinRT", ] diff --git a/codex-rs/windows-sandbox-service/src/registered_runtime/registration_result.rs b/codex-rs/windows-sandbox-service/src/registered_runtime/registration_result.rs index 3f077f3244..b3756eb4e1 100644 --- a/codex-rs/windows-sandbox-service/src/registered_runtime/registration_result.rs +++ b/codex-rs/windows-sandbox-service/src/registered_runtime/registration_result.rs @@ -2,6 +2,8 @@ //! Diagnostic getters never replace the completion error or turn success into failure. //! Free-form Windows ErrorText stays in Windows deployment diagnostics, not this summary. +mod appx_events; + use anyhow::Context; use anyhow::Result; use windows::Foundation::AsyncStatus; @@ -57,7 +59,7 @@ impl RegistrationResult { let summary = format!("{context} phase=GetResults get_results={:?}", error.code()); anyhow::Error::new(error).context(summary) })?; - let activity_id = match details.activity_id { + let activity_id = match &details.activity_id { Ok(id) => format!("{id:?}"), Err(error) => format!("unavailable({:?})", error.code()), }; @@ -82,7 +84,14 @@ impl RegistrationResult { return Ok(()); } extended_error.ok().with_context(|| { - format!("{context} phase=deployment extended_error={extended_error:?}") + let mut summary = + format!("{context} phase=deployment extended_error={extended_error:?}"); + if let Ok(activity) = details.activity_id + && let Some(ids) = appx_events::failure_event_ids(activity) + { + summary.push_str(&format!(" appx_event_ids={ids}")); + } + summary }) } } diff --git a/codex-rs/windows-sandbox-service/src/registered_runtime/registration_result/appx_events.rs b/codex-rs/windows-sandbox-service/src/registered_runtime/registration_result/appx_events.rs new file mode 100644 index 0000000000..6c052d2751 --- /dev/null +++ b/codex-rs/windows-sandbox-service/src/registered_runtime/registration_result/appx_events.rs @@ -0,0 +1,57 @@ +//! Reads numeric error event IDs for one deployment activity. +use std::collections::BTreeSet; +use std::mem::size_of_val; +use windows::Win32::System::EventLog as evt; +use windows::core::GUID; +use windows::core::HSTRING; +use windows::core::Owned; +use windows::core::w; + +pub(super) fn failure_event_ids(activity: GUID) -> Option { + if activity == GUID::zeroed() { + return None; + } + let filter = HSTRING::from(format!( + "*[System[Correlation[@ActivityID='{{{activity:?}}}'] and Level=2]]" + )); + let channel = w!("Microsoft-Windows-AppXDeploymentServer/Operational"); + // Each successful call transfers a handle to us. Owned closes it on every exit. + unsafe { + let query = + Owned::new(evt::EvtQuery(None, channel, &filter, evt::EvtQueryChannelPath.0).ok()?); + let fields = [w!("Event/System/EventID")]; + let context = Owned::new( + evt::EvtCreateRenderContext(Some(&fields), evt::EvtRenderContextValues.0).ok()?, + ); + let mut ids = BTreeSet::new(); + let mut events = [0]; + let mut returned = 0; + while evt::EvtNext(*query, &mut events, 0, 0, &mut returned).is_ok() && returned == 1 { + let event = Owned::new(evt::EVT_HANDLE(events[0])); + let mut value = evt::EVT_VARIANT::default(); + let mut bytes_used = 0; + let mut properties = 0; + if evt::EvtRender( + *context, + *event, + evt::EvtRenderEventValues.0, + size_of_val(&value) as u32, + Some((&raw mut value).cast()), + &mut bytes_used, + &mut properties, + ) + .is_ok() + && properties == 1 + && value.Type == evt::EvtVarTypeUInt16.0 as u32 + { + ids.insert(value.Anonymous.UInt16Val); + } + } + (!ids.is_empty()).then(|| { + ids.into_iter() + .map(|id| id.to_string()) + .collect::>() + .join(",") + }) + } +}