Skip to content

Commit

Permalink
Merge pull request #1528 from axodotdev/auditable-builds
Browse files Browse the repository at this point in the history
 Add cargo-auditable config option
  • Loading branch information
duckinator authored Nov 6, 2024
2 parents 576e266 + 1028bf2 commit f1b4789
Show file tree
Hide file tree
Showing 65 changed files with 693 additions and 238 deletions.
3 changes: 3 additions & 0 deletions cargo-dist-schema/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,9 @@ pub struct GithubMatrixEntry {
/// what cache provider to use
#[serde(skip_serializing_if = "Option::is_none")]
pub cache_provider: Option<String>,
/// Expression to execute to install cargo-auditable
#[serde(skip_serializing_if = "Option::is_none")]
pub install_cargo_auditable: Option<String>,
}

/// Type of job to run on pull request
Expand Down
8 changes: 8 additions & 0 deletions cargo-dist-schema/src/snapshots/cargo_dist_schema__emit.snap

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

26 changes: 23 additions & 3 deletions cargo-dist/src/backend/ci/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ pub struct GithubCiInfo {
pub install_dist_sh: String,
/// expression to use for installing dist via powershell script
pub install_dist_ps1: String,
/// expression to use for installing cargo-auditable via shell script
pub install_cargo_auditable_sh: String,
/// expression to use for installing cargo-auditable via powershell script
pub install_cargo_auditable_ps1: String,
/// Whether to fail-fast
pub fail_fast: bool,
/// Whether to cache builds
Expand Down Expand Up @@ -89,6 +93,8 @@ pub struct GithubCiInfo {
/// Info about making a GitHub Release (if we're making one)
#[serde(flatten)]
pub github_release: Option<GithubReleaseInfo>,
/// Whether to install cargo-auditable
pub need_cargo_auditable: bool,
}

/// Details for github releases
Expand Down Expand Up @@ -206,6 +212,8 @@ impl GithubCiInfo {
release_branch.is_some() || pr_run_mode == cargo_dist_schema::PrRunMode::Upload;
let cache_builds = cache_builds.unwrap_or(caching_could_be_profitable);

let need_cargo_auditable = dist.config.builds.cargo.cargo_auditable;

// Figure out what builds we need to do
let mut local_targets: SortedSet<&TargetTripleRef> = SortedSet::new();
for release in &dist.releases {
Expand All @@ -218,6 +226,8 @@ impl GithubCiInfo {
// Get the platform-specific installation methods
let install_dist_sh = super::install_dist_sh_for_version(dist_version);
let install_dist_ps1 = super::install_dist_ps1_for_version(dist_version);
let install_cargo_auditable_sh = super::install_cargo_auditable_sh_latest();
let install_cargo_auditable_ps1 = super::install_cargo_auditable_ps1_latest();
let hosting_providers = dist
.hosting
.as_ref()
Expand Down Expand Up @@ -246,6 +256,7 @@ impl GithubCiInfo {
runner: Some(global_runner.to_owned()),
dist_args: Some("--artifacts=global".into()),
install_dist: Some(install_dist_sh.clone()),
install_cargo_auditable: Some(install_cargo_auditable_sh.clone()),
packages_install: None,
};

Expand Down Expand Up @@ -301,7 +312,12 @@ impl GithubCiInfo {
for (runner, targets) in local_runs {
use std::fmt::Write;
let install_dist =
install_dist_for_targets(&targets, &install_dist_sh, &install_dist_ps1);
install_package_for_targets(&targets, &install_dist_sh, &install_dist_ps1);
let install_cargo_auditable = install_package_for_targets(
&targets,
&install_cargo_auditable_sh,
&install_cargo_auditable_ps1,
);
let mut dist_args = String::from("--artifacts=local");
for target in &targets {
write!(dist_args, " --target={target}").unwrap();
Expand All @@ -312,6 +328,7 @@ impl GithubCiInfo {
runner: Some(runner),
dist_args: Some(dist_args),
install_dist: Some(install_dist.to_owned()),
install_cargo_auditable: Some(install_cargo_auditable.to_owned()),
packages_install: package_install_for_targets(&targets, &dependencies),
});
}
Expand All @@ -336,6 +353,8 @@ impl GithubCiInfo {
rust_version,
install_dist_sh,
install_dist_ps1,
install_cargo_auditable_sh,
install_cargo_auditable_ps1,
fail_fast,
cache_builds,
build_local_artifacts,
Expand All @@ -358,6 +377,7 @@ impl GithubCiInfo {
root_permissions,
github_build_setup,
github_release,
need_cargo_auditable,
})
}

Expand Down Expand Up @@ -618,8 +638,8 @@ fn github_runner_for_target(
}
}

/// Select the dist installer approach for a given Github Runner
fn install_dist_for_targets<'a>(
/// Select the (dist-produced) installer approach for a given Github Runner
fn install_package_for_targets<'a>(
targets: &'a [&'a TargetTripleRef],
install_sh: &'a str,
install_ps1: &'a str,
Expand Down
18 changes: 18 additions & 0 deletions cargo-dist/src/backend/ci/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ pub mod github;
const SELF_DIST_VERSION: &str = env!("CARGO_PKG_VERSION");
const BASE_DIST_FETCH_URL: &str = "https://github.com/axodotdev/cargo-dist/releases/download";

// NOTE: This is hard-coded to download latest.
const BASE_CARGO_AUDITABLE_FETCH_LATEST_URL: &str =
"https://github.com/rust-secure-code/cargo-auditable/releases/latest/download";

/// Info about all the enabled CI backends
#[derive(Debug, Default)]
pub struct CiInfo {
Expand Down Expand Up @@ -66,3 +70,17 @@ fn install_dist_git(version: &Version) -> Option<String> {
format!("cargo install --git https://github.com/axodotdev/cargo-dist/ --branch={branch} cargo-dist")
})
}

/// Get the command to invoke to install cargo-auditable via sh script
fn install_cargo_auditable_sh_latest() -> String {
let installer_url =
format!("{BASE_CARGO_AUDITABLE_FETCH_LATEST_URL}/cargo-auditable-installer.sh");
format!("curl --proto '=https' --tlsv1.2 -LsSf {installer_url} | sh")
}

/// Get the command to invoke to install cargo-auditable via ps1 script
fn install_cargo_auditable_ps1_latest() -> String {
let installer_url =
format!("{BASE_CARGO_AUDITABLE_FETCH_LATEST_URL}/cargo-auditable-installer.ps1");
format!(r#"powershell -c "irm {installer_url} | iex""#)
}
130 changes: 108 additions & 22 deletions cargo-dist/src/build/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,39 +156,28 @@ impl<'a> DistGraphBuilder<'a> {
}
}

/// Build a cargo target
pub fn build_cargo_target(
dist_graph: &DistGraph,
manifest: &mut DistManifest,
// This function was split out of build_cargo_target() so it can have unit
// tests on its own.
fn make_build_cargo_target_command(
cargo_cmd: &String,
rustflags: &String,
target: &CargoBuildStep,
) -> DistResult<()> {
let cargo = dist_graph.tools.cargo()?;
auditable: bool,
) -> Cmd {
let mut command = Cmd::new(cargo_cmd, "build your app with Cargo");

eprint!(
"building cargo target ({}/{}",
target.target_triple, target.profile
);

let mut rustflags = target.rustflags.clone();
let mut desired_extra_env = vec![];
let skip_brewfile = env::var("DO_NOT_USE_BREWFILE").is_ok();
if !skip_brewfile {
if let Some(env_output) = fetch_brew_env(dist_graph, &target.working_dir)? {
let brew_env = parse_env(&env_output)?;
desired_extra_env = select_brew_env(&brew_env);
rustflags = determine_brew_rustflags(&rustflags, &brew_env);
}
if auditable {
command.arg("auditable");
}

let mut command = Cmd::new(&cargo.cmd, "build your app with Cargo");
command
.arg("build")
.arg("--profile")
.arg(&target.profile)
.arg("--message-format=json-render-diagnostics")
.arg("--target")
.arg(target.target_triple.as_str())
.env("RUSTFLAGS", &rustflags)
.env("RUSTFLAGS", rustflags)
.current_dir(&target.working_dir)
.stdout(std::process::Stdio::piped());
if !target.features.default_features {
Expand Down Expand Up @@ -219,6 +208,37 @@ pub fn build_cargo_target(
eprintln!(" --package={})", package);
}
}

command
}

/// Build a cargo target
pub fn build_cargo_target(
dist_graph: &DistGraph,
manifest: &mut DistManifest,
target: &CargoBuildStep,
) -> DistResult<()> {
let cargo = dist_graph.tools.cargo()?;

eprint!(
"building cargo target ({}/{}",
target.target_triple, target.profile
);

let mut rustflags = target.rustflags.clone();
let mut desired_extra_env = vec![];
let skip_brewfile = env::var("DO_NOT_USE_BREWFILE").is_ok();
if !skip_brewfile {
if let Some(env_output) = fetch_brew_env(dist_graph, &target.working_dir)? {
let brew_env = parse_env(&env_output)?;
desired_extra_env = select_brew_env(&brew_env);
rustflags = determine_brew_rustflags(&rustflags, &brew_env);
}
}

let auditable = dist_graph.config.builds.cargo.cargo_auditable;
let mut command = make_build_cargo_target_command(&cargo.cmd, &rustflags, target, auditable);

// If we generated any extra environment variables to
// inject into the environment, apply them now.
command.envs(desired_extra_env);
Expand Down Expand Up @@ -274,3 +294,69 @@ pub fn rustup_toolchain(dist_graph: &DistGraph, cmd: &RustupStep) -> DistResult<
fn determine_brew_rustflags(base_rustflags: &str, environment: &SortedMap<&str, &str>) -> String {
format!("{base_rustflags} {}", calculate_ldflags(environment))
}

#[cfg(test)]
mod tests {
use super::make_build_cargo_target_command;
use crate::tasks::{CargoTargetFeatureList, CargoTargetFeatures, CargoTargetPackages};
use crate::{CargoBuildStep, TargetTriple};

#[test]
fn build_command_not_auditable() {
let cargo_cmd = "cargo".to_string();
let rustflags = "--some-rust-flag".to_string();
let auditable = false;

let features = CargoTargetFeatures {
default_features: true,
features: CargoTargetFeatureList::default(),
};
let target = CargoBuildStep {
expected_binaries: vec![],
features,
package: CargoTargetPackages::Workspace,
profile: "release".to_string(),
rustflags: "--this-rust-flag-gets-ignored".to_string(),
target_triple: TargetTriple::new("x86_64-unknown-linux-gnu".to_string()),
working_dir: ".".to_string().into(), // this feels mildly cursed -duckinator.
};

let cmd = make_build_cargo_target_command(&cargo_cmd, &rustflags, &target, auditable);

let mut args = cmd.inner.get_args();

let arg1 = args.next().unwrap().to_str().unwrap();
assert_eq!(arg1, "build");
}

#[test]
fn build_command_auditable() {
let cargo_cmd = "cargo".to_string();
let rustflags = "--some-rust-flag".to_string();
let auditable = true;

let features = CargoTargetFeatures {
default_features: true,
features: CargoTargetFeatureList::default(),
};
let target = CargoBuildStep {
expected_binaries: vec![],
features,
package: CargoTargetPackages::Workspace,
profile: "release".to_string(),
rustflags: "--this-rust-flag-gets-ignored".to_string(),
target_triple: TargetTriple::new("x86_64-unknown-linux-gnu".to_string()),
working_dir: ".".to_string().into(), // this feels mildly cursed -duckinator.
};

let cmd = make_build_cargo_target_command(&cargo_cmd, &rustflags, &target, auditable);

let mut args = cmd.inner.get_args();

let arg1 = args.next().unwrap().to_str().unwrap();
assert_eq!(arg1, "auditable");

let arg2 = args.next().unwrap().to_str().unwrap();
assert_eq!(arg2, "build");
}
}
10 changes: 10 additions & 0 deletions cargo-dist/src/config/v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,11 @@ pub struct DistMetadata {
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub minimum_glibc_version: Option<LibcVersion>,

/// Whether to embed dependency information in the executable.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub cargo_auditable: Option<bool>,
}

impl DistMetadata {
Expand Down Expand Up @@ -511,6 +516,7 @@ impl DistMetadata {
github_build_setup: _,
mac_pkg_config: _,
minimum_glibc_version: _,
cargo_auditable: _,
} = self;
if let Some(include) = include {
for include in include {
Expand Down Expand Up @@ -608,6 +614,7 @@ impl DistMetadata {
github_build_setup,
mac_pkg_config,
minimum_glibc_version,
cargo_auditable,
} = self;

// Check for global settings on local packages
Expand Down Expand Up @@ -795,6 +802,9 @@ impl DistMetadata {
if minimum_glibc_version.is_none() {
minimum_glibc_version.clone_from(&workspace_config.minimum_glibc_version);
}
if cargo_auditable.is_none() {
cargo_auditable.clone_from(&workspace_config.cargo_auditable);
}

// This was historically implemented as extend, but I'm not convinced the
// inconsistency is worth the inconvenience...
Expand Down
5 changes: 4 additions & 1 deletion cargo-dist/src/config/v0_to_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ impl DistMetadata {
install_libraries,
github_build_setup,
minimum_glibc_version,
cargo_auditable,
} = self.clone();

// Archives
Expand Down Expand Up @@ -114,7 +115,8 @@ impl DistMetadata {
|| precise_builds.is_some()
|| features.is_some()
|| default_features.is_some()
|| all_features.is_some();
|| all_features.is_some()
|| cargo_auditable.is_some();
let cargo_layer = needs_cargo_build_layer.then_some(BoolOr::Val(CargoBuildLayer {
common: CommonBuildLayer::default(),
rust_toolchain_version,
Expand All @@ -123,6 +125,7 @@ impl DistMetadata {
default_features,
all_features,
msvc_crt_static,
cargo_auditable,
}));
let needs_build_layer = cargo_layer.is_some()
|| system_dependencies.is_some()
Expand Down
Loading

0 comments on commit f1b4789

Please sign in to comment.