Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support signing pkgs #1376

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions cargo-dist/src/backend/installer/macpkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ use axoprocess::Cmd;
use camino::Utf8PathBuf;
use serde::Serialize;
use temp_dir::TempDir;
use tracing::info;
use tracing::{info, warn};

use crate::{create_tmp, DistResult};
use crate::{
create_tmp,
sign::macos::{Codesign, Keychain},
DistResult, TargetTriple,
};

use super::ExecutableZipFragment;

Expand All @@ -30,13 +34,36 @@ pub struct PkgInstallerInfo {
pub version: String,
/// Executable aliases
pub bin_aliases: BTreeMap<String, Vec<String>>,
/// Whether to sign package artifacts
pub macos_sign: bool,
/// The target we're building from
pub host_target: TargetTriple,
}

struct SigningEnv {
pub keychain: Keychain,
pub identity: String,
}

impl PkgInstallerInfo {
/// Build the pkg installer
pub fn build(&self) -> DistResult<()> {
info!("building a pkg: {}", self.identifier);

let signing_env = if self.macos_sign {
if let Some(signer) = Codesign::new(&self.host_target)? {
Some(SigningEnv {
keychain: signer.create_keychain()?,
identity: signer.identity().to_owned(),
})
} else {
warn!("Signing was requested, but we weren't able to construct the signing environment - config may be missing");
None
}
} else {
None
};

// We can't build directly from dist_dir because the
// package installer wants the directory we feed it
// to have the final package layout, which in this case
Expand Down Expand Up @@ -81,6 +108,14 @@ impl PkgInstallerInfo {
pkgcmd.arg("--install-location").arg(&self.install_location);
pkgcmd.arg("--version").arg(&self.version);
pkgcmd.arg(&pkg_path);

// If we've been asked to sign, and we have the required
// environment, do that here.
if let Some(signing_env) = &signing_env {
pkgcmd.arg("--sign").arg(&signing_env.identity);
pkgcmd.arg("--keychain").arg(&signing_env.keychain.path);
}

// Ensures stdout from the build process doesn't taint the dist-manifest
pkgcmd.stdout_to_stderr();
pkgcmd.run()?;
Expand All @@ -89,6 +124,13 @@ impl PkgInstallerInfo {
let mut productcmd = Cmd::new("/usr/bin/productbuild", "create final product .pkg");
productcmd.arg("--package").arg(&pkg_path);
productcmd.arg(&product_path);

// We also need to sign the product .pkg.
if let Some(signing_env) = &signing_env {
productcmd.arg("--sign").arg(&signing_env.identity);
productcmd.arg("--keychain").arg(&signing_env.keychain.path);
}

productcmd.stdout_to_stderr();
productcmd.run()?;

Expand Down
21 changes: 19 additions & 2 deletions cargo-dist/src/sign/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ use tracing::warn;

use crate::{create_tmp, DistError, DistResult, TargetTriple};

struct Keychain {
/// Represents a temporary macOS keychain database. The database object will be created within `_root`, and deleted once this struct is dropped.
pub struct Keychain {
_root: TempDir,
root_path: Utf8PathBuf,
password: String,
/// The path to the keychain database.
pub path: Utf8PathBuf,
}

Expand Down Expand Up @@ -156,6 +158,7 @@ impl std::fmt::Debug for CodesignEnv {
}

impl Codesign {
/// Creates a new Codesign instance, if the host is darwin and the required information is in the environment
pub fn new(host_target: &TargetTriple) -> DistResult<Option<Self>> {
if !host_target.contains("darwin") {
return Ok(None);
Expand All @@ -182,11 +185,20 @@ impl Codesign {
val
}

pub fn sign(&self, file: &Utf8Path) -> DistResult<()> {
/// Creates a Keychain with this signer's certificate imported,
/// then returns it.
pub fn create_keychain(&self) -> DistResult<Keychain> {
let password = uuid::Uuid::new_v4().as_hyphenated().to_string();
let keychain = Keychain::create(password)?;
keychain.import_certificate(&self.env.certificate, &self.env.password)?;

Ok(keychain)
}

/// Signs a binary using `codesign`.
pub fn sign(&self, file: &Utf8Path) -> DistResult<()> {
let keychain = self.create_keychain()?;

let mut cmd = Cmd::new("/usr/bin/codesign", "sign macOS artifacts");
cmd.arg("--sign").arg(&self.env.identity);
cmd.arg("--keychain").arg(&keychain.path);
Expand All @@ -196,4 +208,9 @@ impl Codesign {

Ok(())
}

/// Returns the signing identity represented by this signer.
pub fn identity(&self) -> &str {
&self.env.identity
}
}
2 changes: 1 addition & 1 deletion cargo-dist/src/sign/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use camino::Utf8Path;

use crate::{config::ProductionMode, DistResult, TargetTriple};

mod macos;
pub mod macos;
mod ssldotcom;

/// Code/artifact signing providers
Expand Down
4 changes: 4 additions & 0 deletions cargo-dist/src/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2274,6 +2274,8 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
};

let bin_aliases = bin_aliases.for_target(&variant.target);
let macos_sign = self.inner.config.builds.macos_sign;
let host_target = self.inner.tools.cargo.host_target.clone();

// Gather up the bundles the installer supports
let installer_artifact = Artifact {
Expand All @@ -2297,6 +2299,8 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
install_location: config.install_location.clone(),
version: version.to_string(),
bin_aliases,
macos_sign,
host_target,
})),
is_global: false,
};
Expand Down
Loading