From 46dfdba75c9e06adf7e107be552b3c34f5ad6ba7 Mon Sep 17 00:00:00 2001 From: Vasili Gulevich Date: Sun, 8 Dec 2024 10:05:58 +0000 Subject: [PATCH] apple-codesign: survive network brownout Notarization performs a lot of polling requests. Some may fail due to network problems. Only the last request result is required for succefull notarization. Therefore we can safely ignore non-fatal errors until timeout is exceded. Fixes #169 --- .devcontainer/devcontainer.json | 6 +++ apple-codesign/src/notarization.rs | 64 +++++++++++++++++++++++------- 2 files changed, 55 insertions(+), 15 deletions(-) create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..f5767728 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,6 @@ +{ + "image": "mcr.microsoft.com/devcontainers/universal:2", + "features": { + "ghcr.io/devcontainers/features/rust:1": {} + } +} \ No newline at end of file diff --git a/apple-codesign/src/notarization.rs b/apple-codesign/src/notarization.rs index 9116beef..88e296ec 100644 --- a/apple-codesign/src/notarization.rs +++ b/apple-codesign/src/notarization.rs @@ -22,6 +22,7 @@ use { log::warn, sha2::Digest, std::{ + error::Error, fs::File, io::{Read, Seek, SeekFrom, Write}, path::{Path, PathBuf}, @@ -381,27 +382,34 @@ impl Notarizer { let start_time = std::time::Instant::now(); loop { - let status = self.get_submission(submission_id)?; - - let elapsed = start_time.elapsed(); - - warn!( - "poll state after {}s: {:?}", - elapsed.as_secs(), - status.data.attributes.status - ); - - if status.data.attributes.status != notary_api::SubmissionResponseStatus::InProgress { - warn!("Notary API Server has finished processing the uploaded asset"); - - return Ok(status); + match self.get_submission(submission_id) { + Ok(status) => { + let elapsed = start_time.elapsed(); + + warn!( + "poll state after {}s: {:?}", + elapsed.as_secs(), + status.data.attributes.status + ); + + if status.data.attributes.status != notary_api::SubmissionResponseStatus::InProgress { + warn!("Notary API Server has finished processing the uploaded asset"); + + return Ok(status); + } + }, + Err(e) => { + if !is_transient_error(&e) { + return Err(e) + } + } } + let elapsed = start_time.elapsed(); if elapsed >= wait_limit { warn!("reached wait limit after {}s", elapsed.as_secs()); return Err(AppleCodesignError::NotarizeWaitLimitReached); } - std::thread::sleep(self.wait_poll_interval); } } @@ -441,3 +449,29 @@ impl Notarizer { Ok(self.client()?.list_submissions()?) } } + +fn is_transient_error(root: &(dyn Error + 'static)) -> bool { + if let Some::<&reqwest::Error>(reqwest_error) = root.downcast_ref::() { + if reqwest_error.is_timeout() { + warn(reqwest_error, 0); + return true; + } + if reqwest_error.is_connect() { + warn(reqwest_error, 0); + return true; + } + } + + if let Some(source) = root.source() { + return is_transient_error(source) + } + + return false +} + +fn warn(error: &(dyn Error + 'static), indent: usize) { + warn!("{}{}", " ".repeat(indent), error); + if let Some(source) = error.source() { + warn(source, indent + 1); + } +} \ No newline at end of file