Skip to content

Commit

Permalink
fix: use notarytool instead of altool to codesign macos binaries (#1658)
Browse files Browse the repository at this point in the history
  • Loading branch information
EverlastingBugstopper authored Jun 28, 2023
1 parent 12d1a87 commit dee3597
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 86 deletions.
5 changes: 2 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

97 changes: 15 additions & 82 deletions xtask/src/commands/package/macos.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use anyhow::{bail, ensure, Context, Result};
use anyhow::{ensure, Context, Result};
use base64::Engine;
use clap::Parser;
use serde_json_traversal::serde_json_traversal;
use std::io::Write as _;
use std::path::Path;
use std::process::{Command, Stdio};

use crate::tools::XcrunRunner;
use crate::utils::{PKG_PROJECT_ROOT, PKG_VERSION};

const ENTITLEMENTS: &str = "macos-entitlements.plist";
Expand All @@ -24,10 +24,6 @@ pub struct PackageMacos {
#[arg(long, env = "MACOS_CERT_BUNDLE_PASSWORD", hide_env_values = true)]
cert_bundle_password: String,

/// Primary bundle ID.
#[arg(long, env = "MACOS_PRIMARY_BUNDLE_ID")]
primary_bundle_id: String,

/// Apple team ID.
#[arg(long, env = "APPLE_TEAM_ID")]
apple_team_id: String,
Expand Down Expand Up @@ -205,82 +201,19 @@ impl PackageMacos {
)?;
zip.finish()?;

crate::info!("Beginning notarization process...");
let output = Command::new("xcrun")
.args(["altool", "--notarize-app", "--primary-bundle-id"])
.arg(&self.primary_bundle_id)
.arg("--username")
.arg(&self.apple_username)
.arg("--password")
.arg(&self.notarization_password)
.arg("--asc-provider")
.arg(&self.apple_team_id)
.arg("--file")
.arg(&dist_zip)
.args(["--output-format", "json"])
.stderr(Stdio::inherit())
.output()
.context("could not start command xcrun")?;
let _ = std::io::stdout().write(&output.stdout);
ensure!(output.status.success(), "command exited with error",);
let json: serde_json::Value =
serde_json::from_slice(&output.stdout).context("could not parse json output")?;
let success_message = serde_json_traversal!(json => success-message)
.unwrap()
.as_str()
.unwrap();
let request_uuid = serde_json_traversal!(json => notarization-upload => RequestUUID)
.unwrap()
.as_str()
.unwrap();
crate::info!("Success message: {}", success_message);
crate::info!("Request UUID: {}", request_uuid);

let start_time = std::time::Instant::now();
let duration = std::time::Duration::from_secs(60 * 10);
let result = loop {
crate::info!("Checking notarization status...");
let output = Command::new("xcrun")
.args(["altool", "--notarization-info"])
.arg(request_uuid)
.arg("--username")
.arg(&self.apple_username)
.arg("--password")
.arg(&self.notarization_password)
.args(["--output-format", "json"])
.stderr(Stdio::inherit())
.output()
.context("could not start command xcrun")?;

let status = if !output.status.success() {
// NOTE: if the exit status is failure we need to keep trying otherwise the
// process becomes a bit flaky
crate::info!("command exited with error");
None
} else {
let json: serde_json::Value = serde_json::from_slice(&output.stdout)
.context("could not parse json output")?;
serde_json_traversal!(json => notarization-info => Status)
.ok()
.and_then(|x| x.as_str())
.map(|x| x.to_string())
};

if !matches!(
status.as_deref(),
Some("in progress") | None if start_time.elapsed() < duration
) {
break status;
}

std::thread::sleep(std::time::Duration::from_secs(5));
};
match result.as_deref() {
Some("success") => crate::info!("Notarization successful"),
Some("in progress") => bail!("Notarization timeout"),
Some(other) => bail!("Notarization failed: {}", other),
None => bail!("Notarization failed without status message"),
}
let dist_zip = dist_zip.to_str().unwrap_or_else(|| {
panic!(
"path to zipped directory '{}' is not valid utf-8",
dist_zip.display()
)
});

XcrunRunner::new().notarize(
dist_zip,
&self.apple_username,
&self.apple_team_id,
&self.notarization_password,
)?;

Ok(())
}
Expand Down
6 changes: 6 additions & 0 deletions xtask/src/tools/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ mod make;
mod npm;
mod runner;

#[cfg(target_os = "macos")]
mod xcrun;

pub(crate) use cargo::CargoRunner;
pub(crate) use git::GitRunner;
pub(crate) use make::MakeRunner;
pub(crate) use npm::NpmRunner;
pub(crate) use runner::Runner;

#[cfg(target_os = "macos")]
pub(crate) use xcrun::XcrunRunner;

#[cfg(not(windows))]
mod lychee;

Expand Down
15 changes: 14 additions & 1 deletion xtask/src/tools/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,28 @@ use crate::{utils::CommandOutput, Result};

pub struct Runner {
pub(crate) bin: String,
pub(crate) override_bash_descriptor: Option<String>,
}

impl Runner {
pub fn new(bin: &str) -> Self {
Self {
bin: bin.to_string(),
override_bash_descriptor: None,
}
}

#[cfg(target_os = "macos")]
pub(crate) fn set_bash_descriptor(&mut self, new_bash_descriptor: String) {
self.override_bash_descriptor = Some(new_bash_descriptor);
}

fn get_bash_descriptor(&self, task: &ShellTask) -> String {
self.override_bash_descriptor
.clone()
.unwrap_or_else(|| task.bash_descriptor())
}

pub(crate) fn exec(
&self,
args: &[&str],
Expand All @@ -34,7 +47,7 @@ impl Runner {
}
}
let bin = self.bin.to_string();
crate::info!("{}", task.bash_descriptor());
crate::info!("{}", &self.get_bash_descriptor(&task));
let task_result = task.run(move |line| {
match line {
ShellTaskLog::Stdout(line) | ShellTaskLog::Stderr(line) => {
Expand Down
48 changes: 48 additions & 0 deletions xtask/src/tools/xcrun.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use crate::tools::Runner;
use crate::utils::PKG_PROJECT_ROOT;

use anyhow::Result;

pub(crate) struct XcrunRunner {
runner: Runner,
}

impl XcrunRunner {
pub(crate) fn new() -> Self {
let runner = Runner::new("xcrun");

XcrunRunner { runner }
}

pub(crate) fn notarize(
&mut self,
dist_zip: &str,
apple_username: &str,
apple_team_id: &str,
notarization_password: &str,
) -> Result<()> {
crate::info!("Beginning notarization process...");
self.runner.set_bash_descriptor(format!("xcrun notarytool submit {dist_zip} --apple-id {apple_username} --apple-team-id {apple_team_id} --password xxxx-xxxx-xxxx-xxxx --wait --timeout 20m"));
let project_root = PKG_PROJECT_ROOT.clone();
self.runner.exec(
&[
"notarytool",
"submit",
dist_zip,
"--apple-id",
apple_username,
"--team-id",
apple_team_id,
"--password",
notarization_password,
"--wait",
"--timeout",
"20m",
],
&project_root,
None,
)?;
crate::info!("Notarization successful.");
Ok(())
}
}

0 comments on commit dee3597

Please sign in to comment.