use super::formatting::detect_target_label;
use super::*;
use std::collections::HashMap;
fn env_allowlist_contains(env_allowlist: &[String], key: &str) -> bool {
env_allowlist
.iter()
.map(|item| item.trim())
.any(|item| item == key)
}
fn cargo_kind_uses_target_dir(kind: Option<CompilationKind>) -> bool {
matches!(
kind,
Some(
CompilationKind::CargoBuild
| CompilationKind::CargoCheck
| CompilationKind::CargoClippy
| CompilationKind::CargoDoc
| CompilationKind::CargoTest
| CompilationKind::CargoNextest
| CompilationKind::CargoBench
| CompilationKind::CargoZigbuild,
)
)
}
pub(super) fn resolve_forwarded_cargo_target_dir_with_lookup<F>(
kind: Option<CompilationKind>,
invocation_cwd: &Path,
reporter: &HookReporter,
mut lookup_env: F,
command_tokens: Option<&[String]>,
) -> Option<PathBuf>
where
F: FnMut(&str) -> Option<String>,
{
if !cargo_kind_uses_target_dir(kind) {
return None;
}
let raw = command_tokens
.and_then(|tokens| {
extract_cargo_target_dir_from_command_tokens(tokens).inspect(|_| {
reporter.verbose(
"[RCH] CARGO_TARGET_DIR forwarding detected from delegated command tokens",
);
})
})
.or_else(|| {
lookup_env("CARGO_TARGET_DIR").inspect(|_| {
reporter.verbose("[RCH] CARGO_TARGET_DIR forwarding detected from environment");
})
});
let resolved = raw.and_then(|value| {
let trimmed = value.trim();
if trimmed.is_empty() {
reporter.verbose("[RCH] CARGO_TARGET_DIR is empty; using default Cargo target dir");
return None;
}
let requested = PathBuf::from(trimmed);
Some(if requested.is_absolute() {
requested
} else {
invocation_cwd.join(requested)
})
});
let resolved = resolved.unwrap_or_else(|| invocation_cwd.join("target"));
reporter.verbose(&format!(
"[RCH] Cargo target sync active; forcing worker CARGO_TARGET_DIR to an isolated remote target and syncing back to {}",
resolved.display()
));
Some(resolved)
}
pub(super) fn resolve_forwarded_cargo_target_dir(
kind: Option<CompilationKind>,
invocation_cwd: &Path,
reporter: &HookReporter,
command_tokens: Option<&[String]>,
) -> Option<PathBuf> {
resolve_forwarded_cargo_target_dir_with_lookup(
kind,
invocation_cwd,
reporter,
|key| std::env::var(key).ok(),
command_tokens,
)
}
pub(super) fn cargo_target_env_allowlist(
env_allowlist: &[String],
cargo_target_sync: bool,
) -> Vec<String> {
let mut effective = env_allowlist.to_vec();
if cargo_target_sync && !env_allowlist_contains(&effective, "CARGO_TARGET_DIR") {
effective.push("CARGO_TARGET_DIR".to_string());
}
effective
}
pub(super) fn cargo_target_env_overrides(
local_target_dir: Option<&Path>,
) -> Option<HashMap<String, String>> {
let local_target_dir = local_target_dir?;
let mut overrides = HashMap::new();
overrides.insert(
"CARGO_TARGET_DIR".to_string(),
local_target_dir.to_string_lossy().to_string(),
);
Some(overrides)
}
pub(super) fn sanitize_cargo_home_token(token: &str) -> String {
let safe = token
.chars()
.map(|ch| {
if ch.is_ascii_alphanumeric() || ch == '-' || ch == '_' {
ch
} else {
'-'
}
})
.collect::<String>();
let safe = safe.trim_matches('-');
if safe.is_empty() {
"worker".to_string()
} else {
safe.to_string()
}
}
pub(super) fn remote_cargo_target_dir_name(build_id: Option<u64>, worker_id: &WorkerId) -> String {
static REMOTE_CARGO_TARGET_DIR_SEQUENCE: std::sync::atomic::AtomicU64 =
std::sync::atomic::AtomicU64::new(0);
let safe_worker_id = sanitize_cargo_home_token(worker_id.as_str());
let job_id = build_id
.map(|id| format!("job-{id}"))
.unwrap_or_else(|| format!("pid-{}", std::process::id()));
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_nanos();
let sequence =
REMOTE_CARGO_TARGET_DIR_SEQUENCE.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
format!(".rch-target-{safe_worker_id}-{job_id}-{timestamp}-{sequence}")
}
pub(super) fn target_reuse_disabled() -> bool {
target_reuse_disabled_from_value(std::env::var(RCH_DISABLE_TARGET_REUSE_ENV).ok())
}
pub(super) fn target_reuse_disabled_from_value(value: Option<String>) -> bool {
value
.map(|v| {
let v = v.trim().to_ascii_lowercase();
!v.is_empty() && v != "0" && v != "false" && v != "no" && v != "off"
})
.unwrap_or(false)
}
pub(super) fn target_triple_for_command(command: &str) -> String {
explicit_target_triple_for_command(command).unwrap_or_else(default_host_target_triple)
}
pub(super) fn explicit_target_triple_for_command(command: &str) -> Option<String> {
let (tokens, cargo_index) = cargo_command_tokens(command).ok()?;
let mut iter = tokens[cargo_index + 1..].iter();
let mut configured_target = None;
while let Some(token) = iter.next() {
if token == "--" {
break;
}
if let Some(value) = token.strip_prefix("--target=") {
if !value.is_empty() {
return Some(value.to_string());
}
} else if token == "--target" {
if let Some(value) = iter.next().filter(|value| !value.is_empty()) {
return Some(value.to_string());
}
} else {
let config = if token == "--config" {
iter.next().map(String::as_str)
} else {
token.strip_prefix("--config=")
};
if let Some(config) = config
&& let Ok(config) = toml::from_str::<toml::Value>(config)
&& let Some(target) = config.get("build").and_then(|build| build.get("target"))
{
configured_target = target
.as_str()
.filter(|value| !value.is_empty())
.map(str::to_string);
}
}
}
configured_target
}
pub(super) fn default_host_target_triple() -> String {
let arch = std::env::consts::ARCH; match std::env::consts::OS {
"linux" => format!("{arch}-unknown-linux-gnu"),
"macos" => format!("{arch}-apple-darwin"),
"windows" => format!("{arch}-pc-windows-msvc"),
other => format!("{arch}-unknown-{other}"),
}
}
pub(super) fn feature_set_for_command(command: &str) -> Vec<String> {
let mut features: Vec<String> = Vec::new();
let push_list = |list: &str, features: &mut Vec<String>| {
for f in list
.split([',', ' '])
.map(str::trim)
.filter(|s| !s.is_empty())
{
features.push(f.to_string());
}
};
let tokens: Vec<&str> = command.split_whitespace().collect();
let mut iter = tokens.iter().peekable();
while let Some(token) = iter.next() {
if let Some(value) = token.strip_prefix("--features=") {
push_list(value, &mut features);
} else if let Some(value) = token.strip_prefix("-F=") {
push_list(value, &mut features);
} else if *token == "--features" || *token == "-F" {
if let Some(value) = iter.next() {
push_list(value, &mut features);
}
} else if *token == "--all-features" {
features.push("__rch_all_features".to_string());
} else if *token == "--no-default-features" {
features.push("__rch_no_default_features".to_string());
}
}
features
}
pub(super) fn remote_cargo_pooled_target_dir_name(
worker_id: &WorkerId,
normalized_project_root: &Path,
toolchain: Option<&ToolchainInfo>,
command: &str,
) -> String {
let toolchain_id = toolchain
.map(ToolchainInfo::rustup_toolchain)
.unwrap_or_else(|| "unknown".to_string());
let profile = detect_target_label(command, "").unwrap_or_else(|| "dev".to_string());
let triple = target_triple_for_command(command);
let dims = rch_common::pooled_target_key::PooledTargetDimensions::new(
normalized_project_root.to_string_lossy().to_string(),
toolchain_id,
triple,
profile,
)
.with_features(feature_set_for_command(command));
let key = rch_common::pooled_target_key::PooledTargetKey::derive(&dims);
let safe_worker_id = sanitize_cargo_home_token(worker_id.as_str());
format!(".rch-target-{safe_worker_id}-pool-{}", key.as_str())
}
pub(super) fn stale_target_reap_idle_hours() -> u32 {
parse_stale_target_reap_idle_hours(std::env::var("RCH_STALE_TARGET_REAP_HOURS").ok())
}
pub(super) fn parse_stale_target_reap_idle_hours(raw: Option<String>) -> u32 {
const DEFAULT_IDLE_HOURS: u32 = 12;
raw.and_then(|v| v.trim().parse::<u32>().ok())
.map(|hours| hours.max(1))
.unwrap_or(DEFAULT_IDLE_HOURS)
}
pub(super) fn rewrite_cargo_target_dir_command_for_remote(
command: &str,
command_tokens: Option<&[String]>,
forwarded_cargo_target_dir: Option<&PathBuf>,
reporter: &HookReporter,
) -> String {
if forwarded_cargo_target_dir.is_none() {
return command.to_string();
}
let parsed_tokens;
let tokens = if let Some(tokens) = command_tokens {
tokens
} else {
parsed_tokens = parse_command_tokens(command, reporter);
let Some(tokens) = parsed_tokens.as_deref() else {
return command.to_string();
};
tokens
};
let mut stripped = tokens.to_vec();
let mut removed_target_dir = false;
if let Some(without_assignments) =
strip_cargo_target_dir_assignments_from_command_tokens(&stripped)
{
stripped = without_assignments;
removed_target_dir = true;
}
if let Some(without_flags) = strip_cargo_target_dir_flags_from_command_tokens(&stripped) {
stripped = without_flags;
removed_target_dir = true;
}
if removed_target_dir {
reporter.verbose(
"[RCH] removed local Cargo target-dir setting before remote execution; worker-scoped target dir will be injected",
);
return join_exec_command(&stripped);
}
command.to_string()
}
pub(super) fn managed_clean_overlay_cargo_tokens(
command: &str,
) -> anyhow::Result<(Vec<String>, usize)> {
literal_cargo_tokens(command, false)
}
fn literal_cargo_tokens(
command: &str,
allow_classified_wrappers: bool,
) -> anyhow::Result<(Vec<String>, usize)> {
let mut quote = None;
let mut escaped = false;
for ch in command.chars() {
if escaped {
escaped = false;
} else if ch == '\\' && quote != Some('\'') {
escaped = true;
} else if quote == Some(ch) {
quote = None;
} else if quote.is_none() && matches!(ch, '\'' | '"') {
quote = Some(ch);
} else if quote != Some('\'') && matches!(ch, '$' | '`')
|| quote.is_none()
&& matches!(
ch,
';' | '|' | '&' | '<' | '>' | '\n' | '*' | '?' | '[' | '~' | '(' | ')'
)
{
anyhow::bail!("cannot safely bind Cargo build directory across shell evaluation");
}
}
if escaped || quote.is_some() {
anyhow::bail!("cannot safely bind Cargo build directory across shell evaluation");
}
cargo_command_tokens_with_wrappers(command, allow_classified_wrappers)
}
fn cargo_command_tokens(command: &str) -> anyhow::Result<(Vec<String>, usize)> {
cargo_command_tokens_with_wrappers(command, false)
}
fn cargo_command_tokens_with_wrappers(
command: &str,
allow_classified_wrappers: bool,
) -> anyhow::Result<(Vec<String>, usize)> {
let mut tokens = shell_words::split(command)?;
let assignment = super::is_shell_assignment;
if tokens.first().is_some_and(|token| assignment(token)) {
tokens.insert(0, "env".to_string());
}
let mut index = 0;
loop {
let token = tokens
.get(index)
.ok_or_else(|| anyhow::anyhow!("missing Cargo command"))?;
let executable = Path::new(token).file_name().and_then(|name| name.to_str());
let wrapper_start = index;
match executable {
Some(
"cargo" | "cargo.exe" | "cargo-zigbuild" | "cargo-zigbuild.exe" | "cargo-xwin"
| "cargo-xwin.exe",
) => break,
Some("env") => {
index += 1;
while let Some(token) = tokens.get(index) {
match token.as_str() {
"--" => {
index += 1;
break;
}
"-i" | "--ignore-environment" => index += 1,
"--debug" if allow_classified_wrappers => index += 1,
"-u" | "--unset" | "-C" | "--chdir" => {
anyhow::ensure!(
tokens.get(index + 1).is_some(),
"missing env option value"
);
index += 2;
}
value
if value.starts_with("--unset=")
|| value.starts_with("--chdir=")
|| assignment(value) =>
{
index += 1
}
value if value.starts_with('-') && allow_classified_wrappers => {
let cargo_index = classified_cargo_suffix(&tokens, wrapper_start)?;
return Ok((tokens, cargo_index));
}
value if value.starts_with('-') => anyhow::bail!(
"unsupported env option in managed Cargo command: {value}"
),
_ => break,
}
}
while tokens.get(index).is_some_and(|token| assignment(token)) {
index += 1;
}
}
Some("time") => {
index += 1;
while let Some(token) = tokens.get(index) {
match token.as_str() {
"--" => {
index += 1;
break;
}
"-p" | "--portability" | "-v" | "--verbose" | "-a" | "--append" | "-q"
| "--quiet" => index += 1,
"-f" | "--format" | "-o" | "--output" => {
anyhow::ensure!(
tokens.get(index + 1).is_some(),
"missing time option value"
);
index += 2;
}
value
if value.starts_with("--format=") || value.starts_with("--output=") =>
{
index += 1
}
value if value.starts_with('-') && allow_classified_wrappers => {
let cargo_index = classified_cargo_suffix(&tokens, wrapper_start)?;
return Ok((tokens, cargo_index));
}
value if value.starts_with('-') => anyhow::bail!(
"unsupported time option in managed Cargo command: {value}"
),
_ => break,
}
}
}
Some("rustup") => {
anyhow::ensure!(
tokens.get(index + 1).is_some_and(|token| token == "run"),
"expected rustup run before Cargo"
);
index += 2;
if tokens.get(index).is_some_and(|token| token == "--install") {
index += 1;
}
anyhow::ensure!(
tokens
.get(index)
.is_some_and(|token| !token.is_empty() && !token.starts_with('-')),
"missing rustup toolchain"
);
index += 1;
}
_ if allow_classified_wrappers => {
let cargo_index = classified_cargo_suffix(&tokens, wrapper_start)?;
return Ok((tokens, cargo_index));
}
_ => anyhow::bail!("unsupported executable prefix in managed Cargo command: {token}"),
}
}
Ok((tokens, index))
}
fn classified_cargo_suffix(tokens: &[String], wrapper_start: usize) -> anyhow::Result<usize> {
let remaining = join_exec_command(&tokens[wrapper_start..]);
let normalized = rch_common::patterns::normalize_command(&remaining);
let suffix = shell_words::split(&normalized)?;
let start = tokens.len().checked_sub(suffix.len());
if let Some(start) = start.filter(|&start| start >= wrapper_start)
&& !suffix.is_empty()
&& matches!(
Path::new(&tokens[start])
.file_name()
.and_then(|name| name.to_str()),
Some(
"cargo"
| "cargo.exe"
| "cargo-zigbuild"
| "cargo-zigbuild.exe"
| "cargo-xwin"
| "cargo-xwin.exe"
)
)
&& tokens[start + 1..] == suffix[1..]
{
return Ok(start);
}
anyhow::bail!("cannot locate an unchanged Cargo argv suffix: {remaining}");
}
pub(super) fn managed_clean_overlay_cargo_build_dir(
command: &str,
managed_target: &str,
) -> anyhow::Result<String> {
anyhow::ensure!(
!managed_target.is_empty() && !managed_target.chars().any(char::is_control),
"managed Cargo build directory must be a nonempty path without control characters"
);
let (mut tokens, cargo_index) = managed_clean_overlay_cargo_tokens(command)?;
let executable = Path::new(&tokens[cargo_index])
.file_name()
.and_then(|name| name.to_str());
let standalone_xwin = matches!(executable, Some("cargo-xwin" | "cargo-xwin.exe"));
anyhow::ensure!(
standalone_xwin || matches!(executable, Some("cargo" | "cargo.exe")),
"managed clean-overlay build directory requires Cargo or an exact xwin build"
);
let mut index = cargo_index + 1;
if !standalone_xwin
&& tokens
.get(index)
.is_some_and(|token| token.starts_with('+'))
{
index += 1;
}
while let Some(token) = tokens.get(index) {
match token.as_str() {
"--config" | "--color" | "-Z" | "-C" => {
anyhow::ensure!(
tokens.get(index + 1).is_some_and(|value| value != "--"),
"missing Cargo global option value"
);
index += 2;
}
"-v" | "-vv" | "-q" | "--verbose" | "--quiet" | "--locked" | "--offline"
| "--frozen" => index += 1,
value
if value.starts_with("--config=")
|| value.starts_with("--color=")
|| value.starts_with("-Z") && value.len() > 2 =>
{
index += 1
}
value if value.starts_with('-') => {
anyhow::bail!("unsupported Cargo global option: {value}")
}
_ => break,
}
}
let subcommand = tokens
.get(index)
.ok_or_else(|| anyhow::anyhow!("missing Cargo subcommand"))?;
let xwin = standalone_xwin || subcommand == "xwin";
if xwin {
anyhow::ensure!(
rch_common::patterns::is_cargo_xwin_build(command),
"managed xwin requires an exact classified xwin build"
);
if subcommand == "xwin" {
index += 1;
}
}
let subcommand = tokens
.get(index)
.ok_or_else(|| anyhow::anyhow!("missing Cargo build subcommand"))?;
if !xwin && subcommand == "fmt" {
return Ok(command.to_string());
}
let packaging = !xwin && matches!(subcommand.as_str(), "package" | "publish");
if packaging {
anyhow::ensure!(
rch_common::patterns::is_cargo_package_verification(command),
"managed packaging requires verified cargo package or explicit cargo publish --dry-run"
);
}
anyhow::ensure!(
packaging
|| matches!(
subcommand.as_str(),
"build"
| "b"
| "check"
| "c"
| "test"
| "t"
| "clippy"
| "doc"
| "d"
| "bench"
| "run"
| "r"
| "rustc"
| "rustdoc"
| "fix"
),
"unsupported Cargo subcommand for managed build directory: {subcommand}"
);
let end = tokens[index + 1..]
.iter()
.position(|token| token == "--")
.map_or(tokens.len(), |offset| index + 1 + offset);
anyhow::ensure!(
!tokens[index + 1..end]
.iter()
.any(|token| token == "--build-dir" || token.starts_with("--build-dir=")),
"explicit --build-dir is unsupported for clean-overlay execution"
);
let value = format!(
"build.build-dir={}",
toml::Value::String(managed_target.to_string())
);
tokens.splice(end..end, ["--config".to_string(), value]);
Ok(join_exec_command(&tokens))
}
pub(super) fn bind_owned_cargo_target_dir(
command: &str,
managed_target: &str,
) -> anyhow::Result<String> {
anyhow::ensure!(
Path::new(managed_target).is_absolute()
&& Path::new(managed_target).file_name().is_some()
&& !managed_target.chars().any(char::is_control)
&& !managed_target.contains('\\')
&& !managed_target
.split('/')
.any(|part| part == "." || part == ".."),
"owned Cargo target must be an absolute literal pool path"
);
let (mut tokens, cargo_index) = managed_clean_overlay_cargo_tokens(command)?;
anyhow::ensure!(
Path::new(&tokens[cargo_index])
.file_name()
.is_some_and(|name| name == "cargo" || name == "cargo.exe"),
"owned target binding requires the Cargo executable"
);
let mut index = cargo_index + 1;
if tokens
.get(index)
.is_some_and(|token| token.starts_with('+'))
{
index += 1;
}
while let Some(token) = tokens.get(index) {
match token.as_str() {
"--config" | "--color" | "-Z" => {
anyhow::ensure!(
tokens.get(index + 1).is_some_and(|value| value != "--"),
"missing Cargo global option value"
);
index += 2;
}
"-v" | "-vv" | "-q" | "--verbose" | "--quiet" | "--locked" | "--offline"
| "--frozen" => index += 1,
value
if value.starts_with("--config=")
|| value.starts_with("--color=")
|| value.starts_with("-Z") && value.len() > 2 =>
{
index += 1
}
value if value.starts_with('-') => {
anyhow::bail!("unsupported owned Cargo global option: {value}")
}
_ => break,
}
}
let subcommand = tokens
.get(index)
.ok_or_else(|| anyhow::anyhow!("missing Cargo subcommand"))?;
anyhow::ensure!(
matches!(
subcommand.as_str(),
"build"
| "b"
| "check"
| "c"
| "test"
| "t"
| "clippy"
| "doc"
| "d"
| "bench"
| "run"
| "r"
| "rustc"
| "rustdoc"
| "fix"
| "package"
| "publish"
),
"unsupported Cargo subcommand for owned target binding: {subcommand}"
);
let end = tokens[index + 1..]
.iter()
.position(|token| token == "--")
.map_or(tokens.len(), |offset| index + 1 + offset);
anyhow::ensure!(
!tokens[index + 1..end]
.iter()
.any(|token| token == "--target-dir" || token.starts_with("--target-dir=")),
"owned Cargo target binding requires the caller's target selector to be absent"
);
tokens.splice(
end..end,
["--target-dir".to_owned(), managed_target.to_owned()],
);
Ok(join_exec_command(&tokens))
}
pub(super) struct ManagedCargoCommand<'a> {
original: &'a str,
rewritten: Option<String>,
}
impl<'a> ManagedCargoCommand<'a> {
pub(super) fn new(command: &'a str, managed_target: Option<&str>) -> anyhow::Result<Self> {
let rewritten = managed_target
.map(|target| managed_clean_overlay_cargo_build_dir(command, target))
.transpose()?;
Ok(Self {
original: command,
rewritten,
})
}
pub(super) fn policy_command(&self) -> &str {
self.original
}
pub(super) fn execution_command(&self) -> &str {
self.rewritten.as_deref().unwrap_or(self.original)
}
}
pub(super) fn bind_build_source_stamp(command: &str, stamp: &str) -> anyhow::Result<String> {
anyhow::ensure!(
!stamp.is_empty() && !stamp.chars().any(char::is_control),
"invalid build-source stamp"
);
let (mut tokens, cargo_index) = literal_cargo_tokens(command, true)?;
let end = tokens
.iter()
.enumerate()
.skip(cargo_index + 1)
.find_map(|(index, token)| (token == "--").then_some(index))
.unwrap_or(tokens.len());
let value = format!(
"env.RCH_BUILD_SOURCE.value={}",
toml::Value::String(stamp.to_owned())
);
if cargo_subcommand_is_nextest(&tokens, cargo_index) {
tokens.splice(end..end, ["--config".to_owned(), value]);
tokens.splice(
cargo_index..cargo_index,
["env".to_owned(), format!("RCH_BUILD_SOURCE={stamp}")],
);
return Ok(join_exec_command(&tokens));
}
tokens.splice(
end..end,
[
"--config".to_owned(),
value,
"--config".to_owned(),
"env.RCH_BUILD_SOURCE.force=true".to_owned(),
],
);
Ok(join_exec_command(&tokens))
}
fn cargo_subcommand_is_nextest(tokens: &[String], cargo_index: usize) -> bool {
const CARGO_VALUE_FLAGS: &[&str] = &["--color", "-Z", "-C", "--config"];
let mut rest = tokens.iter().skip(cargo_index + 1);
while let Some(token) = rest.next() {
if token.starts_with('+') {
continue;
}
if token.starts_with('-') {
if !token.contains('=') && CARGO_VALUE_FLAGS.contains(&token.as_str()) {
rest.next();
}
continue;
}
return token == "nextest";
}
false
}
pub(super) fn guard_clean_overlay_cargo_config(command: &str) -> anyhow::Result<String> {
let (mut tokens, cargo_index) = managed_clean_overlay_cargo_tokens(command)?;
let guard = r#"rch_config_refuse() {
printf '%s\n' 'RCH-E413 clean-overlay unselected Cargo configuration' >&2
exit 113
}
rch_config_directory() {
[ -d "$1" ] && [ -r "$1" ] && [ -x "$1" ] || rch_config_refuse
/bin/ls -a "$1" >/dev/null 2>&1 || rch_config_refuse
}
rch_config_absent() {
for rch_config_name in config config.toml; do
if [ -e "$1/$rch_config_name" ] || [ -L "$1/$rch_config_name" ]; then
rch_config_refuse
fi
done
}
case "${CARGO_HOME-}" in
/*) ;;
*) rch_config_refuse ;;
esac
rch_config_directory "$CARGO_HOME"
rch_config_absent "$CARGO_HOME"
rch_config_parent=$(pwd -P) || rch_config_refuse
case "$rch_config_parent" in
/*) ;;
*) rch_config_refuse ;;
esac
while [ "$rch_config_parent" != / ]; do # ubs:ignore — compares a directory path with filesystem root, not a secret.
rch_config_parent=${rch_config_parent%/*}
[ -n "$rch_config_parent" ] || rch_config_parent=/
rch_config_directory "$rch_config_parent"
if [ -e "$rch_config_parent/.cargo" ] || [ -L "$rch_config_parent/.cargo" ]; then
rch_config_directory "$rch_config_parent/.cargo"
rch_config_absent "$rch_config_parent/.cargo"
fi
done
exec "$@""#;
tokens.splice(
cargo_index..cargo_index,
[
"/bin/sh".to_string(),
"-c".to_string(),
guard.to_string(),
"rch-clean-overlay-config".to_string(),
],
);
Ok(join_exec_command(&tokens))
}
pub(super) fn strip_cargo_target_dir_assignments_from_command_tokens(
tokens: &[String],
) -> Option<Vec<String>> {
fn strip_assignment_prefix(tokens: &mut Vec<String>, mut index: usize) -> bool {
let mut changed = false;
while let Some(token) = tokens.get(index) {
let Some((key, _)) = token.split_once('=') else {
break;
};
if key == "CARGO_TARGET_DIR" {
tokens.remove(index);
changed = true;
} else {
index += 1;
}
}
changed
}
let mut stripped = tokens.to_vec();
let mut index = 0usize;
while let Some(token) = stripped.get(index) {
match token.as_str() {
"sudo" | "time" => {
index += 1;
while let Some(flag) = stripped.get(index) {
if flag.starts_with('-') {
index += 1;
} else {
break;
}
}
}
"env" => {
index = skip_env_option_prefix(&stripped, index + 1);
return strip_assignment_prefix(&mut stripped, index).then_some(stripped);
}
_ => {
return strip_assignment_prefix(&mut stripped, index).then_some(stripped);
}
}
}
None
}
fn skip_env_option_prefix(tokens: &[String], mut index: usize) -> usize {
while let Some(flag) = tokens.get(index).map(String::as_str) {
if flag == "--" {
return index + 1;
}
match flag {
"-u" | "--unset" => {
index += 1;
if tokens.get(index).is_some() {
index += 1;
}
}
_ if flag.starts_with("--unset=") => {
index += 1;
}
_ if flag.starts_with('-') && !flag.contains('=') => {
index += 1;
}
_ => break,
}
}
index
}
fn cargo_target_dir_flag_span(tokens: &[String]) -> Option<(std::ops::Range<usize>, String)> {
let command = shell_words::join(tokens);
let (normalized, cargo_index) = cargo_command_tokens_with_wrappers(&command, true).ok()?;
let added = normalized.len().checked_sub(tokens.len())?;
if added > 1 || normalized.get(added..)? != tokens {
return None;
}
let mut index = cargo_index.checked_sub(added)? + 1;
let mut selected = None;
while let Some(token) = tokens.get(index) {
if token == "--" {
break;
}
let (end, value) = if token == "--target-dir" {
let value = tokens.get(index + 1)?;
if value.starts_with('-') {
return None;
}
(index + 2, Some(value.as_str()))
} else if let Some(value) = token.strip_prefix("--target-dir=") {
(index + 1, Some(value))
} else {
let takes_value = matches!(
token.as_str(),
"--config"
| "--target"
| "--manifest-path"
| "--lockfile-path"
| "--profile"
| "--package"
| "-p"
| "--exclude"
| "--features"
| "-F"
| "--bin"
| "--example"
| "--test"
| "--bench"
| "--color"
| "--message-format"
| "--jobs"
| "-j"
| "-Z"
| "-C"
| "--artifact-dir"
| "--out-dir"
| "--build-dir"
);
if takes_value {
tokens.get(index + 1)?;
}
(index + if takes_value { 2 } else { 1 }, None)
};
if let Some(value) = value {
if selected.is_some() || value.is_empty() || value.chars().any(char::is_control) {
return None;
}
selected = Some((index..end, value.to_string()));
}
index = end;
}
selected
}
pub(super) fn strip_cargo_target_dir_flags_from_command_tokens(
tokens: &[String],
) -> Option<Vec<String>> {
let (span, _) = cargo_target_dir_flag_span(tokens)?;
let mut stripped = tokens.to_vec();
stripped.drain(span);
Some(stripped)
}
pub(super) fn extract_cargo_target_dir_from_command_tokens(tokens: &[String]) -> Option<String> {
if let Some((_, value)) = cargo_target_dir_flag_span(tokens) {
return Some(value);
}
fn scan_assignment_prefix(tokens: &[String], start: usize) -> Option<String> {
let mut index = start;
while let Some(token) = tokens.get(index) {
if let Some((key, value)) = token.split_once('=') {
if key == "CARGO_TARGET_DIR" {
return Some(value.to_string());
}
index += 1;
continue;
}
break;
}
None
}
let mut index = 0usize;
while let Some(token) = tokens.get(index) {
match token.as_str() {
"sudo" | "time" => {
index += 1;
while let Some(flag) = tokens.get(index) {
if flag.starts_with('-') {
index += 1;
} else {
break;
}
}
}
"env" => {
index = skip_env_option_prefix(tokens, index + 1);
return scan_assignment_prefix(tokens, index);
}
_ => return scan_assignment_prefix(tokens, index),
}
}
None
}
#[cfg(test)]
mod managed_build_dir_tests {
use super::{
bind_owned_cargo_target_dir, managed_clean_overlay_cargo_build_dir,
managed_clean_overlay_cargo_tokens,
};
#[test]
fn owned_target_binding_preserves_wrappers_and_passthrough() {
let target = "/worker/pools/target with ' quotes";
for argv in [
vec![
"cargo",
"build",
"--config",
"build.target-dir=\"/unselected\"",
],
vec![
"env",
"--",
"CARGO_TARGET_DIR=/unselected",
"cargo",
"+nightly",
"test",
"--",
"--target-dir=/test-payload",
],
vec![
"time",
"-f",
"literal --target-dir",
"cargo",
"--color",
"never",
"clippy",
"--",
"-D",
"warnings",
],
vec![
"rustup",
"run",
"nightly",
"cargo",
"check",
"--all-targets",
],
] {
let command = shell_words::join(&argv);
let managed = managed_clean_overlay_cargo_build_dir(&command, target).unwrap();
let mut expected = shell_words::split(&managed).unwrap();
let (_, cargo_index) = managed_clean_overlay_cargo_tokens(&managed).unwrap();
let separator = expected[cargo_index + 1..]
.iter()
.position(|token| token == "--")
.map_or(expected.len(), |offset| cargo_index + 1 + offset);
expected.splice(
separator..separator,
["--target-dir".to_owned(), target.to_owned()],
);
let bound = bind_owned_cargo_target_dir(&managed, target).unwrap();
assert_eq!(shell_words::split(&bound).unwrap(), expected, "{command}");
}
}
#[test]
fn owned_target_binding_refuses_unsupported_or_duplicate_output_authority() {
for command in [
"cargo fmt",
"cargo clean",
"cargo build --target-dir /unselected",
"cargo build --target-dir=/unselected",
"cargo -C /elsewhere build",
"cargo-xwin build",
"cargo build; echo changed",
] {
assert!(
bind_owned_cargo_target_dir(command, "/worker/pool").is_err(),
"{command}"
);
}
for target in ["relative", "/", "/worker/../pool", "/worker/pool\nother"] {
assert!(
bind_owned_cargo_target_dir("cargo build", target).is_err(),
"{target:?}"
);
}
}
#[cfg(target_os = "linux")]
#[test]
fn managed_packaging_real_cargo_verifies_archive_and_returns_identical_bytes() {
use super::super::artifact_patterns::get_custom_target_artifact_patterns;
use std::fs;
use std::io::{Read as _, Write as _};
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
fn files(root: &Path, directory: &Path, paths: &mut Vec<PathBuf>) {
for entry in fs::read_dir(directory).unwrap() {
let entry = entry.unwrap();
let kind = entry.file_type().unwrap();
assert!(
!kind.is_symlink(),
"unexpected fixture symlink: {:?}",
entry.path()
);
if kind.is_dir() {
files(root, &entry.path(), paths);
} else if kind.is_file() {
paths.push(entry.path().strip_prefix(root).unwrap().to_path_buf());
}
}
}
let root = tempfile::Builder::new()
.prefix("rch-managed-package-")
.tempdir()
.unwrap()
.keep();
eprintln!(
"managed packaging fixture and logs retained at {}",
root.display()
);
for directory in ["src", ".cargo", "bin", "cargo-home", "logs", "returned"] {
fs::create_dir(root.join(directory)).unwrap();
}
fs::write(
root.join("Cargo.toml"),
"[package]\nname='managed_package_fixture'\nversion='0.1.0'\nedition='2021'\n\
include=['Cargo.toml', 'build.rs', 'src/**', 'packaged.txt']\n[workspace]\n",
)
.unwrap();
fs::write(root.join("packaged.txt"), "archive-owned input\n").unwrap();
fs::write(root.join("worktree-only.txt"), "excluded input\n").unwrap();
let source = b"pub const MESSAGE: &str = include_str!(\"../packaged.txt\");\n";
fs::write(root.join("src/lib.rs"), source).unwrap();
fs::write(
root.join("build.rs"),
r#"fn main() {
let origin = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let out = std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
std::fs::write(out.join("rch-package-origin"), origin).unwrap();
}
"#,
)
.unwrap();
let outside_file = root.join("outside-file-config");
let outside_env = root.join("outside-environment");
fs::write(
root.join(".cargo/config.toml"),
format!(
"[build]\nbuild-dir={}\n",
toml::Value::String(outside_file.to_str().unwrap().to_owned())
),
)
.unwrap();
let mut cargo = PathBuf::from(env!("CARGO"));
if fs::metadata(&cargo).unwrap().len() <= 8 * 1024
&& fs::read_to_string(&cargo)
.unwrap()
.lines()
.any(|line| line.starts_with("# rch-toolchain-wrap-version:"))
{
cargo.set_file_name("cargo-rch-real");
}
let mut magic = [0; 4];
fs::File::open(&cargo)
.unwrap()
.read_exact(&mut magic)
.unwrap();
assert_eq!(&magic, b"\x7fELF", "fixture requires real Cargo");
let cargo_bin = cargo.parent().unwrap();
std::os::unix::fs::symlink(&cargo, root.join("bin/cargo")).unwrap();
let path = std::env::join_paths([
root.join("bin"),
cargo_bin.to_path_buf(),
PathBuf::from("/usr/bin"),
PathBuf::from("/bin"),
])
.unwrap();
let run = |name: &str, command: &str, pool: &Path| {
let plan =
super::ManagedCargoCommand::new(command, Some(pool.to_str().unwrap())).unwrap();
let stamped =
super::bind_build_source_stamp(plan.execution_command(), &"a".repeat(40)).unwrap();
let guarded = super::guard_clean_overlay_cargo_config(&stamped).unwrap();
let output = Command::new("/usr/bin/timeout") .args(["--kill-after=5", "120", "sh", "-c", &guarded])
.current_dir(&root)
.env_clear()
.env("PATH", &path)
.env("HOME", &root)
.env("CARGO_HOME", root.join("cargo-home"))
.env("CARGO_TARGET_DIR", pool)
.env("CARGO_BUILD_BUILD_DIR", &outside_env)
.env("RUSTC", cargo_bin.join("rustc"))
.env("RUSTUP_AUTO_INSTALL", "0")
.env("RCH_CARGO_WRAPPER_BYPASS", "1")
.env("LC_ALL", "C")
.output()
.expect("GNU timeout and the fixture's native Cargo must be available");
fs::write(root.join(format!("logs/{name}.stdout")), &output.stdout).unwrap();
fs::write(root.join(format!("logs/{name}.stderr")), &output.stderr).unwrap();
output
};
let command = "cargo package --offline --allow-dirty --no-metadata -j1";
let pool = root.join("managed pool");
let packaged = run("package", command, &pool);
assert!(packaged.status.success(), "{packaged:?}");
let mut inventory = Vec::new();
files(&pool, &pool, &mut inventory);
let extracted = pool.join("package/managed_package_fixture-0.1.0");
assert!(
inventory.iter().any(|relative| {
relative
.file_name()
.is_some_and(|name| name == "rch-package-origin")
&& fs::read_to_string(pool.join(relative)).unwrap()
== extracted.to_str().unwrap()
}),
"verification must execute the build script from the extracted archive"
);
let plan = super::ManagedCargoCommand::new(command, Some(pool.to_str().unwrap())).unwrap();
let patterns = get_custom_target_artifact_patterns(
Some(rch_common::CompilationKind::CargoBuild),
Some(plan.policy_command()),
);
let pipeline = crate::transfer::TransferPipeline::new(
root.join("returned"),
"native-package".into(),
"fixture".into(),
rch_common::TransferConfig::default(),
);
let (selected, _) = pipeline
.partition_staged_artifact_paths(&inventory, &patterns)
.unwrap();
let archive = PathBuf::from("package/managed_package_fixture-0.1.0.crate");
let temporary_archive =
PathBuf::from("package/tmp-crate/managed_package_fixture-0.1.0.crate");
let mut expected = vec![archive.clone()];
if pool.join(&temporary_archive).is_file() {
assert_eq!(
fs::read(pool.join(&temporary_archive)).unwrap(),
fs::read(pool.join(&archive)).unwrap(),
"Cargo's staging archive must be byte-identical to its final archive"
);
expected.push(temporary_archive.clone());
}
expected.sort();
let mut selected_set = selected.clone();
selected_set.sort();
assert_eq!(selected_set, expected);
let mut rsync = Command::new("/usr/bin/timeout") .args([
"--kill-after=5",
"60",
"rsync",
"-a",
"--from0",
"--files-from=-",
"--",
])
.arg(format!("{}/", pool.display()))
.arg(format!("{}/", root.join("returned").display()))
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("rsync must be available for the native retrieval fixture");
{
let mut input = rsync.stdin.take().unwrap();
for relative in &selected {
input
.write_all(relative.as_os_str().as_encoded_bytes())
.unwrap();
input.write_all(&[0]).unwrap();
}
}
let transferred = rsync.wait_with_output().unwrap();
assert!(transferred.status.success(), "{transferred:?}");
for relative in &selected {
let original = fs::read(pool.join(relative)).unwrap();
let returned = fs::read(root.join("returned").join(relative)).unwrap();
assert_eq!(
blake3::hash(&returned),
blake3::hash(&original),
"returned archive bytes differ for {relative:?}"
);
}
let original = fs::read(pool.join(&archive)).unwrap();
let returned = fs::read(root.join("returned").join(&archive)).unwrap();
assert_eq!(blake3::hash(&returned), blake3::hash(&original));
let mut members = tar::Archive::new(flate2::read::GzDecoder::new(returned.as_slice()));
let mut saw_source = false;
for entry in members.entries().unwrap() {
let mut entry = entry.unwrap();
let path = entry.path().unwrap().into_owned();
assert!(!path.ends_with("worktree-only.txt"));
if path.ends_with("src/lib.rs") {
let mut bytes = Vec::new();
entry.read_to_end(&mut bytes).unwrap();
assert_eq!(bytes.as_slice(), &source[..]);
saw_source = true;
}
}
assert!(saw_source);
assert!(!outside_file.exists() && !outside_env.exists());
let failing_source = b"pub const MESSAGE: &str = include_str!(\"../worktree-only.txt\");\n";
fs::write(root.join("src/lib.rs"), failing_source).unwrap();
let check = run(
"worktree",
"cargo check --offline -j1",
&root.join("check pool"),
);
assert!(check.status.success(), "{check:?}");
let failed_pool = root.join("failed package pool");
let failed = run("package-missing-input", command, &failed_pool);
assert_eq!(failed.status.code(), Some(101), "{failed:?}");
assert!(String::from_utf8_lossy(&failed.stderr).contains("worktree-only.txt"));
assert!(
failed_pool.join(&temporary_archive).is_file(),
"verification failure must occur after staging the archive"
);
assert!(
!failed_pool.join(&archive).exists(),
"failed verification must not promote a final archive"
);
let failed_archive = fs::read(failed_pool.join(&temporary_archive)).unwrap();
assert_ne!(
failed_archive, original,
"failed package must use the new source"
);
let mut members =
tar::Archive::new(flate2::read::GzDecoder::new(failed_archive.as_slice()));
let mut saw_failing_source = false;
let mut saw_packaged_input = false;
for entry in members.entries().unwrap() {
let mut entry = entry.unwrap();
let path = entry.path().unwrap().into_owned();
assert!(!path.ends_with("worktree-only.txt"));
if path == Path::new("managed_package_fixture-0.1.0/src/lib.rs") {
let mut bytes = Vec::new();
entry.read_to_end(&mut bytes).unwrap();
assert_eq!(bytes.as_slice(), &failing_source[..]);
saw_failing_source = true;
} else if path == Path::new("managed_package_fixture-0.1.0/packaged.txt") {
let mut bytes = Vec::new();
entry.read_to_end(&mut bytes).unwrap();
assert_eq!(bytes, b"archive-owned input\n");
saw_packaged_input = true;
}
}
assert!(saw_failing_source && saw_packaged_input);
let mut failed_inventory = Vec::new();
files(&failed_pool, &failed_pool, &mut failed_inventory);
let failed_extracted = failed_pool.join("package/managed_package_fixture-0.1.0");
assert!(
failed_inventory.iter().any(|relative| {
relative
.file_name()
.is_some_and(|name| name == "rch-package-origin")
&& fs::read_to_string(failed_pool.join(relative)).unwrap()
== failed_extracted.to_str().unwrap()
}),
"failed verification must execute the build script from the extracted archive"
);
assert_eq!(
fs::read(root.join("worktree-only.txt")).unwrap(),
b"excluded input\n"
);
assert!(!outside_file.exists() && !outside_env.exists());
}
#[test]
fn managed_packaging_preserves_the_classified_command_and_binds_the_cache() {
use rch_common::patterns::{classify_command, is_cargo_package_verification};
let target = "/worker/cache with 'single' and \"double\" quotes";
for command in [
"cargo package --offline -j1",
"cargo publish --dry-run --locked -j1",
"cargo publish -n --workspace -p demo",
"cargo +nightly package --locked",
"cargo --offline publish --dry-run",
"env CARGO_HOME=/tmp/cargo cargo publish --dry-run",
] {
assert!(is_cargo_package_verification(command), "{command}");
assert_eq!(
classify_command(command).kind,
Some(rch_common::CompilationKind::CargoBuild),
"{command}"
);
let plan = super::ManagedCargoCommand::new(command, Some(target)).unwrap();
assert_eq!(plan.policy_command(), command);
let original = shell_words::split(command).unwrap();
let rewritten = shell_words::split(plan.execution_command()).unwrap();
assert_eq!(&rewritten[..original.len()], original.as_slice());
assert_eq!(rewritten.len(), original.len() + 2);
assert_eq!(rewritten[original.len()], "--config");
let config: toml::Value = toml::from_str(&rewritten[original.len() + 1]).unwrap();
assert_eq!(config["build"]["build-dir"].as_str(), Some(target));
}
}
#[test]
fn managed_packaging_never_promotes_publication_or_a_dry_run_option_value() {
for command in [
"cargo publish",
"cargo publish --no-verify --dry-run",
"cargo package --no-verify",
"cargo package --list",
"cargo publish --help --dry-run",
"cargo publish --token --dry-run",
"cargo publish --token=--dry-run",
"cargo publish --registry=-n",
"cargo publish --config=--dry-run",
"cargo publish --manifest-path --dry-run",
"cargo publish --unknown --dry-run",
"cargo publish -- --dry-run",
"cargo publish --dry-run=false",
"cargo publish --dry-run --build-dir /unmanaged",
"cargo publish --dry-run; cargo publish",
"cargo publish '$MODE'",
"cargo package --config 'build.jobs=1'",
] {
assert!(
super::ManagedCargoCommand::new(command, Some("/worker/target")).is_err(),
"{command}"
);
}
}
#[test]
fn managed_packaging_keeps_archive_only_delivery_through_all_execution_rewrites() {
use super::super::artifact_patterns::{
expected_output_glob_list, get_custom_target_artifact_patterns,
get_project_artifact_patterns, sync_back_verified_zero_package_archives,
};
use std::collections::BTreeSet;
use std::path::PathBuf;
let kind = Some(rch_common::CompilationKind::CargoBuild);
let archives: Vec<PathBuf> = [
"package/demo-0.1.0.crate",
"package/tmp-registry/dependency-0.1.0.crate",
"package/tmp-crate/demo-0.1.0.crate",
]
.into_iter()
.map(PathBuf::from)
.collect();
let mut inventory = archives.clone();
inventory.extend(
[
"package/demo-0.1.0/src/lib.rs",
"package/tmp-registry/index/config.json",
".rustc_info.json",
"debug/stale-executable",
"debug/incremental/stale.o",
]
.into_iter()
.map(PathBuf::from),
);
for command in [
"cargo package --offline",
"cargo publish --dry-run --locked",
] {
for target in [None, Some("/worker/managed pool")] {
let plan = super::ManagedCargoCommand::new(command, target).unwrap();
let stamped =
super::bind_build_source_stamp(plan.execution_command(), &"a".repeat(40))
.unwrap();
assert!(stamped.contains("RCH_BUILD_SOURCE"));
assert_eq!(plan.policy_command(), command);
let patterns =
get_custom_target_artifact_patterns(kind, Some(plan.policy_command()));
assert_eq!(
expected_output_glob_list(&patterns),
[
"package/*.crate",
"package/tmp-registry/*.crate",
"package/tmp-crate/*.crate",
]
);
assert!(
get_project_artifact_patterns(kind, Some(plan.policy_command()), true)
.is_empty()
);
assert_eq!(
get_project_artifact_patterns(kind, Some(plan.policy_command()), false),
[
"target/package/*.crate",
"target/package/tmp-registry/*.crate",
"target/package/tmp-crate/*.crate",
]
);
let pipeline = crate::transfer::TransferPipeline::new(
PathBuf::from("/unused/local"),
"package-policy".into(),
"fixture".into(),
rch_common::TransferConfig::default(),
);
let (selected, excluded) = pipeline
.partition_staged_artifact_paths(&inventory, &patterns)
.unwrap();
assert_eq!(
selected.into_iter().collect::<BTreeSet<_>>(),
archives.iter().cloned().collect::<BTreeSet<_>>()
);
assert_eq!(excluded.len(), 5);
assert!(sync_back_verified_zero_package_archives(
Some(0),
plan.policy_command()
));
assert!(!sync_back_verified_zero_package_archives(
Some(1),
plan.policy_command()
));
assert!(!sync_back_verified_zero_package_archives(
None,
plan.policy_command()
));
}
}
}
#[test]
fn unmanaged_command_plan_does_not_reclassify_or_rewrite_non_cargo_jobs() {
let command = "python3 -I collect.py --config 'literal $value'";
let plan = super::ManagedCargoCommand::new(command, None).unwrap();
assert_eq!(plan.policy_command(), command);
assert_eq!(plan.execution_command(), command);
}
#[test]
fn explicit_target_honors_inline_config_and_shell_quoting() {
let target = "aarch64-apple-darwin";
for command in [
r#"cargo build --config 'build.target="aarch64-apple-darwin"'"#,
r#"cargo build --config='build.target="aarch64-apple-darwin"'"#,
r#"cargo --config "build.target = 'aarch64-apple-darwin'" build"#,
r#"cargo build --target 'aarch64-apple-darwin'"#,
r#"cargo build '--target=aarch64-apple-darwin'"#,
r#"env -- CARGO_TARGET_DIR='/custom target' /opt/bin/cargo +nightly build --config 'build.target="aarch64-apple-darwin"'"#,
r#"/usr/bin/time -f cargo env -u cargo -- rustup run nightly cargo build --config 'build.target="aarch64-apple-darwin"'"#,
] {
assert_eq!(
super::explicit_target_triple_for_command(command).as_deref(),
Some(target),
"{command}"
);
assert_eq!(super::target_triple_for_command(command), target);
}
}
#[test]
fn explicit_target_obeys_precedence_and_ignores_passthrough() {
for command in [
r#"cargo build --config 'build.target="x86_64-unknown-linux-gnu"' --target aarch64-apple-darwin"#,
r#"cargo build --target=aarch64-apple-darwin --config 'build.target="x86_64-unknown-linux-gnu"'"#,
r#"cargo build --config 'build.target="x86_64-unknown-linux-gnu"' --config 'build.target="aarch64-apple-darwin"' --config 'build.jobs=2'"#,
r#"cargo rustc --config 'build.target="aarch64-apple-darwin"' -- --target x86_64-unknown-linux-gnu"#,
] {
assert_eq!(
super::explicit_target_triple_for_command(command).as_deref(),
Some("aarch64-apple-darwin"),
"{command}"
);
}
for command in [
"cargo build --release",
"cargo build --target-dir /tmp/target",
"cargo test -- --target aarch64-apple-darwin",
r#"cargo test -- --config 'build.target="aarch64-apple-darwin"'"#,
"cargo build --config .cargo/extra.toml",
r#"cargo build --config 'build.target-dir="aarch64-apple-darwin"'"#,
r#"cargo build --config 'build.target=["aarch64-apple-darwin", "x86_64-unknown-linux-gnu"]'"#,
"cargo build --config 'unterminated",
] {
assert_eq!(
super::explicit_target_triple_for_command(command),
None,
"{command}"
);
}
}
#[test]
fn configured_cross_target_artifacts_exclude_host_tools_but_keep_target_guard() {
use super::super::artifact_triple::foreign_target_artifacts;
let command = r#"cargo build --release --config 'build.target="aarch64-apple-darwin"' --config 'target.aarch64-apple-darwin.linker="/usr/local/bin/zigcc-aarch64-darwin"'"#;
let pinned = super::explicit_target_triple_for_command(command).unwrap();
for custom in [false, true] {
let dir = tempfile::tempdir().unwrap();
let prefix = if custom { "" } else { "target/" };
let host = format!("{prefix}release/deps/libclap_derive-fixture.so");
let target = format!("{prefix}{pinned}/release/app");
for path in [&host, &target] {
std::fs::create_dir_all(dir.path().join(path).parent().unwrap()).unwrap();
}
std::fs::write(dir.path().join(&host), b"\x7fELF\0\0\0\0").unwrap();
std::fs::write(dir.path().join(&target), b"\xcf\xfa\xed\xfe\0\0\0\0").unwrap();
let manifest = vec![host.clone(), target.clone()];
assert!(
foreign_target_artifacts(dir.path(), &manifest, custom, &pinned, Some(&pinned))
.is_empty()
);
std::fs::write(dir.path().join(&target), b"\x7fELF\0\0\0\0").unwrap();
let foreign =
foreign_target_artifacts(dir.path(), &manifest, custom, &pinned, Some(&pinned));
assert_eq!(foreign.len(), 1);
assert_eq!(foreign[0].path, target);
let native = foreign_target_artifacts(dir.path(), &manifest, custom, &pinned, None);
assert_eq!(native.len(), 1);
assert_eq!(native[0].path, host);
}
}
#[cfg(unix)]
struct ConfigGuardFixture {
root: std::path::PathBuf,
project: std::path::PathBuf,
home: std::path::PathBuf,
cargo: std::path::PathBuf,
sentinel: std::path::PathBuf,
}
#[cfg(unix)]
impl ConfigGuardFixture {
fn new() -> Self {
use std::os::unix::fs::PermissionsExt as _;
let root = tempfile::Builder::new()
.prefix("rch-cfg-")
.tempdir_in("/tmp")
.unwrap()
.keep();
let project = root.join("project");
let home = root.join("cargo home");
let cargo = root.join("cargo");
let sentinel = root.join("child-started");
std::fs::create_dir(&project).unwrap();
std::fs::create_dir(&home).unwrap();
std::fs::write(
&cargo,
"#!/bin/sh\nprintf '%s\\n' \"$@\" > \"$RCH_CONFIG_GUARD_SENTINEL\"\n",
)
.unwrap();
std::fs::set_permissions(&cargo, std::fs::Permissions::from_mode(0o700)).unwrap();
Self {
root,
project,
home,
cargo,
sentinel,
}
}
fn run(&self, prefix: &str) -> std::process::Output {
let command = format!(
"{prefix} {} test -- 'literal $value; with spaces'",
shell_words::quote(self.cargo.to_str().unwrap())
);
let guarded = super::guard_clean_overlay_cargo_config(&command).unwrap();
std::process::Command::new("/bin/sh") .args(["-c", &guarded])
.current_dir(&self.project)
.env_clear()
.env("PATH", "/usr/bin:/bin")
.env("CARGO_HOME", &self.home)
.env("RCH_CONFIG_GUARD_SENTINEL", &self.sentinel)
.output()
.unwrap()
}
fn assert_refused(&self, output: &std::process::Output) {
assert_eq!(output.status.code(), Some(113), "{output:?}");
assert_eq!(
output.stderr,
b"RCH-E413 clean-overlay unselected Cargo configuration\n"
);
assert!(output.stdout.is_empty());
assert!(!self.sentinel.exists(), "Cargo child must not start");
}
}
#[cfg(unix)]
#[test]
fn source_pair_config_guard_allows_clean_home_and_selected_project_config() {
let fixture = ConfigGuardFixture::new();
std::fs::create_dir(fixture.project.join(".cargo")).unwrap();
std::fs::write(
fixture.project.join(".cargo/config.toml"),
"[build]\njobs=1\n",
)
.unwrap();
let output = fixture.run("");
assert!(output.status.success(), "{output:?}");
assert!(output.stderr.is_empty());
assert_eq!(
std::fs::read_to_string(&fixture.sentinel).unwrap(),
"test\n--\nliteral $value; with spaces\n"
);
}
#[cfg(unix)]
#[test]
fn source_pair_config_guard_refuses_home_config_and_broken_symlink() {
for name in ["config", "config.toml"] {
for symlink in [false, true] {
let fixture = ConfigGuardFixture::new();
let path = fixture.home.join(name);
if symlink {
std::os::unix::fs::symlink(fixture.root.join("absent"), &path).unwrap();
} else {
std::fs::write(&path, "secret-looking-config-value").unwrap();
}
fixture.assert_refused(&fixture.run(""));
}
}
}
#[cfg(unix)]
#[test]
fn source_pair_config_guard_checks_inline_home_after_env_prefix() {
let fixture = ConfigGuardFixture::new();
let inline_home = fixture.root.join("inline 'cargo' home");
std::fs::create_dir(&inline_home).unwrap();
std::fs::write(inline_home.join("config.toml"), "must-not-be-printed").unwrap();
let prefix = format!(
"env -- CARGO_HOME={}",
shell_words::quote(inline_home.to_str().unwrap())
);
fixture.assert_refused(&fixture.run(&prefix));
}
#[cfg(unix)]
#[test]
fn source_pair_config_guard_refuses_ancestor_config() {
for name in ["config", "config.toml"] {
let fixture = ConfigGuardFixture::new();
std::fs::create_dir(fixture.root.join(".cargo")).unwrap();
std::fs::write(fixture.root.join(".cargo").join(name), "unselected").unwrap();
fixture.assert_refused(&fixture.run(""));
}
}
#[cfg(unix)]
#[test]
fn source_pair_config_guard_refuses_unknown_home_and_non_directory() {
for prefix in ["CARGO_HOME=relative", "CARGO_HOME=", "env -u CARGO_HOME"] {
let fixture = ConfigGuardFixture::new();
fixture.assert_refused(&fixture.run(prefix));
}
for exists in [false, true] {
let fixture = ConfigGuardFixture::new();
let unusable = fixture.root.join("unusable");
if exists {
std::fs::write(&unusable, "not a directory").unwrap();
}
let prefix = format!(
"CARGO_HOME={}",
shell_words::quote(unusable.to_str().unwrap())
);
fixture.assert_refused(&fixture.run(&prefix));
}
}
#[test]
fn source_pair_cargo_tokens_distinguishes_prefix_values_from_executable() {
for (command, cargo_index) in [
("cargo test", 0),
("/opt/bin/cargo.exe +nightly test", 0),
("/usr/bin/time -f cargo cargo test", 3),
("rustup run cargo /opt/bin/cargo test", 3),
(
"CARGO_MARK='cargo' /usr/bin/time -f cargo env -u cargo -- X=cargo /opt/bin/cargo test",
10,
),
] {
let (tokens, actual_index) = managed_clean_overlay_cargo_tokens(command).unwrap();
assert_eq!(actual_index, cargo_index, "{command}");
let mut expected = shell_words::split(command).unwrap();
if command.starts_with("CARGO_MARK=") {
expected.insert(0, "env".to_string());
}
assert_eq!(tokens, expected, "{command}");
assert!(matches!(
std::path::Path::new(&tokens[actual_index])
.file_name()
.unwrap()
.to_str(),
Some("cargo" | "cargo.exe")
));
}
}
#[test]
fn source_pair_cargo_tokens_rejects_unfinished_syntax_but_keeps_literal_backslash() {
for command in [
"cargo test --manifest-path unfinished\\",
"cargo test --manifest-path \"unfinished",
"cargo test --manifest-path 'unfinished",
] {
assert!(
managed_clean_overlay_cargo_tokens(command).is_err(),
"{command:?}"
);
}
for command in [
r#"cargo test --manifest-path 'trailing\'"#,
r#"cargo test --manifest-path "trailing\\""#,
] {
let (tokens, index) = managed_clean_overlay_cargo_tokens(command).unwrap();
assert_eq!(index, 0);
assert_eq!(
tokens,
["cargo", "test", "--manifest-path", "trailing\\"]
.into_iter()
.map(str::to_owned)
.collect::<Vec<_>>()
);
}
}
#[cfg(target_os = "linux")]
#[test]
fn source_pair_build_dir_real_cargo_overrides_file_env_and_cli() {
use std::io::Read as _;
use std::path::{Path, PathBuf};
let root = tempfile::tempdir().unwrap().keep();
for directory in ["src", ".cargo", "bin", "cargo-home"] {
std::fs::create_dir(root.join(directory)).unwrap();
}
std::fs::write(root.join("Cargo.toml"), "[package]\nname='managed_build_dir_fixture'\nversion='0.1.0'\nedition='2024'\n[workspace]\n").unwrap();
std::fs::write(root.join("fixture.txt"), "sealed fixture").unwrap();
std::fs::write(root.join("src/lib.rs"), "#[test] fn reads_fixture() { let root = std::path::Path::new(env!(\"CARGO_MANIFEST_DIR\")); assert_eq!(std::fs::read_to_string(root.join(\"fixture.txt\")).unwrap(), \"sealed fixture\"); }\n").unwrap();
let outside: Vec<_> = ["outside-A", "outside-B", "outside-C"]
.into_iter()
.map(|name| root.join(name))
.collect();
let config_value = |path: &Path| toml::Value::String(path.to_str().unwrap().to_string());
std::fs::write(
root.join(".cargo/config.toml"),
format!("[build]\nbuild-dir={}\n", config_value(&outside[0])),
)
.unwrap();
let mut cargo = PathBuf::from(env!("CARGO"));
if std::fs::metadata(&cargo).unwrap().len() <= 8 * 1024
&& std::fs::read_to_string(&cargo)
.unwrap()
.lines()
.any(|line| line.starts_with("# rch-toolchain-wrap-version:"))
{
cargo.set_file_name("cargo-rch-real");
}
let mut magic = [0; 4];
std::fs::File::open(&cargo)
.unwrap()
.read_exact(&mut magic)
.unwrap();
assert_eq!(
&magic, b"\x7fELF",
"fixture must execute a real Cargo binary"
);
let cargo_bin = cargo.parent().unwrap();
let executable = root.join("bin/cargo");
std::os::unix::fs::symlink(&cargo, &executable).unwrap();
let path = std::env::join_paths(
std::iter::once(cargo_bin.to_path_buf())
.chain(std::env::split_paths(&std::env::var_os("PATH").unwrap())),
)
.unwrap();
let pool = root.join("managed pool");
for (subcommand, passthrough) in [("test", "--nocapture"), ("clippy", "-D warnings")] {
let command = format!(
"{} {subcommand} --offline --jobs 1 --message-format=json --config {} -- {passthrough}",
shell_words::quote(executable.to_str().unwrap()),
shell_words::quote(&format!("build.build-dir={}", config_value(&outside[2])))
);
let managed =
managed_clean_overlay_cargo_build_dir(&command, pool.to_str().unwrap()).unwrap();
let output = std::process::Command::new("sh") .args(["-c", &managed])
.current_dir(&root)
.env("PATH", &path)
.env("CARGO_HOME", root.join("cargo-home"))
.env("CARGO_BUILD_BUILD_DIR", &outside[1])
.env("CARGO_TARGET_DIR", &pool)
.env("RUSTC", cargo_bin.join("rustc"))
.env("RUSTFLAGS", "")
.env("RUSTUP_AUTO_INSTALL", "0")
.env("RCH_CARGO_WRAPPER_BYPASS", "1")
.env_remove("RUSTUP_TOOLCHAIN")
.env_remove("CARGO_ENCODED_RUSTFLAGS")
.env_remove("CARGO_BUILD_RUSTC")
.env_remove("CARGO_BUILD_TARGET")
.env_remove("CARGO_BUILD_TARGET_DIR")
.env_remove("CARGO_BUILD_RUSTFLAGS")
.env_remove("RUSTC_WRAPPER")
.env_remove("RUSTC_WORKSPACE_WRAPPER")
.env_remove("CARGO_BUILD_RUSTC_WRAPPER")
.env_remove("CARGO_BUILD_RUSTC_WORKSPACE_WRAPPER")
.output()
.unwrap();
let stdout = String::from_utf8(output.stdout).unwrap();
assert!(
output.status.success(),
"{subcommand}: {stdout}\n{}",
String::from_utf8_lossy(&output.stderr)
);
let artifacts: Vec<_> = stdout
.lines()
.filter_map(|line| serde_json::from_str::<serde_json::Value>(line).ok())
.filter(|message| {
message["reason"] == "compiler-artifact"
&& message["target"]["name"] == "managed_build_dir_fixture"
})
.collect();
assert!(
!artifacts.is_empty(),
"real compiler artifact receipt required: {stdout}"
);
for artifact in artifacts {
assert_eq!(
artifact["manifest_path"].as_str(),
root.join("Cargo.toml").to_str()
);
assert!(!artifact["filenames"].as_array().unwrap().is_empty());
for filename in artifact["filenames"].as_array().unwrap() {
let filename = Path::new(filename.as_str().unwrap());
assert!(
filename.starts_with(&pool) && filename.is_file(),
"{}",
filename.display()
);
}
}
if subcommand == "test" {
assert!(stdout.contains("test reads_fixture ... ok"), "{stdout}");
}
assert!(
outside.iter().all(|path| !path.exists()),
"unmanaged cache directory was created"
);
}
eprintln!(
"managed build-dir real Cargo evidence retained at {}",
root.display()
);
}
#[test]
fn source_pair_build_dir_keeps_wrappers_and_literal_arguments() {
let command = "env -- CARGO_BUILD_BUILD_DIR='/outside cache' /usr/bin/time -f '%e seconds' rustup run nightly-2026-08-31 /opt/rust/bin/cargo +nightly test --config 'build.build-dir=\"/also outside\"' -p 'space name' -- 'literal $value; with quotes'";
let target = "/managed/cache with 'single' and \"double\" quotes";
let rewritten = managed_clean_overlay_cargo_build_dir(command, target).unwrap();
let original = shell_words::split(command).unwrap();
let actual = shell_words::split(&rewritten).unwrap();
let separator = original.iter().rposition(|token| token == "--").unwrap();
assert_eq!(&actual[..separator], &original[..separator]);
assert_eq!(actual[separator], "--config");
let config: toml::Value = toml::from_str(&actual[separator + 1]).unwrap();
assert_eq!(config["build"]["build-dir"].as_str(), Some(target));
assert_eq!(&actual[separator + 2..], &original[separator..]);
}
#[test]
fn source_pair_build_dir_final_config_wins_before_clippy_passthrough() {
let rewritten = managed_clean_overlay_cargo_build_dir(
"RUSTC_WRAPPER='/wrapper with spaces' cargo --config 'build.build-dir=\"/global\"' clippy --all-targets --config=build.build-dir='\"/later\"' -- -D warnings",
"/managed",
).unwrap();
let tokens = shell_words::split(&rewritten).unwrap();
assert_eq!(tokens[0], "env");
assert_eq!(tokens[1], "RUSTC_WRAPPER=/wrapper with spaces");
let separator = tokens.iter().position(|token| token == "--").unwrap();
assert_eq!(&tokens[separator..], ["--", "-D", "warnings"]);
assert_eq!(tokens[separator - 2], "--config");
let config: toml::Value = toml::from_str(&tokens[separator - 1]).unwrap();
assert_eq!(config["build"]["build-dir"].as_str(), Some("/managed"));
assert!(
tokens
.iter()
.any(|token| token == "--config=build.build-dir=\"/later\"")
);
}
#[test]
fn build_source_stamp_bind_places_config_before_cargo_separator() {
let stamp = "a".repeat(40);
let vergen_command = format!("env -- VERGEN_GIT_SHA={} cargo build", "b".repeat(40));
let alias_command = format!(
"RCH_GIT_COMMIT={} cargo test -- --config fixture",
"c".repeat(40)
);
for command in [
"cargo build",
"cargo +nightly test -- --nocapture",
"env -i cargo check",
"env --debug cargo build",
"env -uCARGO_HOME cargo build",
"time -f%U cargo build",
"time -l cargo build",
"cargo-zigbuild zigbuild --target x86_64-unknown-linux-gnu",
"env -i /opt/bin/cargo-zigbuild build --release",
"rustup run nightly cargo-zigbuild zigbuild --locked",
"cargo-xwin xwin build --release",
"nice -n 10 cargo build",
"nice --adjustment=+5 cargo build",
"timeout -s KILL 90 cargo test -- --nocapture",
"ionice -c 2 -n 4 cargo build",
"sudo nice -n 5 cargo build",
"/usr/bin/time -f cargo nice -n 5 cargo build",
vergen_command.as_str(),
alias_command.as_str(),
"/usr/bin/time -f cargo rustup run nightly cargo build",
] {
let bound = super::bind_build_source_stamp(command, &stamp)
.unwrap_or_else(|error| panic!("{command}: {error}"));
let original = shell_words::split(command).unwrap();
let mut expected = original.clone();
if original.first().is_some_and(|token| {
token.split_once('=').is_some_and(|(key, _)| {
!key.is_empty()
&& key
.chars()
.all(|ch| ch == '_' || ch.is_ascii_alphanumeric())
})
}) {
expected.insert(0, "env".to_string());
}
let actual = shell_words::split(&bound).unwrap();
let configs: Vec<_> = actual
.iter()
.enumerate()
.filter(|(index, token)| {
*token == "--config" && actual[index + 1].starts_with("env.RCH_BUILD_SOURCE.")
})
.collect();
assert_eq!(configs.len(), 2, "{command}: {bound}");
let (config_index, _) = configs[0];
let value_config: toml::Value = toml::from_str(&actual[config_index + 1]).unwrap();
assert_eq!(
value_config["env"]["RCH_BUILD_SOURCE"]["value"].as_str(),
Some(stamp.as_str()),
"{command}"
);
assert_eq!(actual[config_index + 2], "--config", "{command}: {bound}");
let force_config: toml::Value = toml::from_str(&actual[config_index + 3]).unwrap();
assert_eq!(
force_config["env"]["RCH_BUILD_SOURCE"]["force"].as_bool(),
Some(true),
"{command}"
);
assert_eq!(
&actual[..config_index],
&expected[..config_index],
"{command}"
);
assert_eq!(
&actual[config_index + 4..],
&expected[config_index..],
"{command}"
);
if let Some(token) = expected.get(config_index) {
assert_eq!(token, "--", "{command}: {bound}");
} else {
assert_eq!(config_index, expected.len(), "{command}: {bound}");
}
}
}
#[test]
fn build_source_stamp_binds_nextest_with_value_config_and_process_env() {
let stamp = format!("{}-dirty", "a".repeat(40));
for (command, expected) in [
(
"cargo nextest run --workspace",
"env RCH_BUILD_SOURCE={stamp} cargo nextest run --workspace --config {value}",
),
(
"cargo +nightly nextest run -- --nocapture",
"env RCH_BUILD_SOURCE={stamp} cargo +nightly nextest run --config {value} -- --nocapture",
),
(
"cargo --color never --locked nextest run",
"env RCH_BUILD_SOURCE={stamp} cargo --color never --locked nextest run --config {value}",
),
(
"CARGO_TERM_COLOR=never cargo nextest run",
"env CARGO_TERM_COLOR=never env RCH_BUILD_SOURCE={stamp} cargo nextest run --config {value}",
),
(
"rustup run nightly cargo nextest run",
"rustup run nightly env RCH_BUILD_SOURCE={stamp} cargo nextest run --config {value}",
),
] {
let value = format!(
"env.RCH_BUILD_SOURCE.value={}",
toml::Value::String(stamp.clone())
);
let expected: Vec<String> = expected
.split(' ')
.map(|token| token.replace("{stamp}", &stamp).replace("{value}", &value))
.collect();
let bound = super::bind_build_source_stamp(command, &stamp)
.unwrap_or_else(|error| panic!("{command}: {error}"));
assert_eq!(shell_words::split(&bound).unwrap(), expected, "{command}");
assert!(!bound.contains("force"), "{command}: {bound}");
}
for command in ["cargo test nextest", "cargo -C nextest build"] {
let bound = super::bind_build_source_stamp(command, &stamp).unwrap();
assert!(
bound.contains("env.RCH_BUILD_SOURCE.force=true") && !bound.starts_with("env "),
"{command}: {bound}"
);
}
}
#[test]
fn build_source_stamp_real_nextest_accepts_bound_command() {
let cargo = std::path::PathBuf::from(env!("CARGO"));
let cargo_bin = cargo.parent().unwrap().to_path_buf();
let path = std::env::join_paths(std::iter::once(cargo_bin.clone()).chain(
std::env::split_paths(&std::env::var_os("PATH").unwrap_or_default()),
))
.unwrap();
let cargo_home_bin = std::env::var_os("CARGO_HOME")
.map(std::path::PathBuf::from)
.or_else(|| {
std::env::var_os("HOME").map(|home| std::path::Path::new(&home).join(".cargo"))
})
.map(|home| home.join("bin"));
let has_nextest = std::env::split_paths(&path)
.chain(cargo_home_bin)
.any(|directory| directory.join("cargo-nextest").is_file());
if !has_nextest {
eprintln!("skipping: cargo-nextest is not installed");
return;
}
let root = tempfile::tempdir().unwrap();
std::fs::create_dir(root.path().join("src")).unwrap();
std::fs::write(
root.path().join("Cargo.toml"),
"[package]\nname='nextest_stamp_fixture'\nversion='0.1.0'\nedition='2021'\n[workspace]\n",
)
.unwrap();
std::fs::write(
root.path().join("src/lib.rs"),
"#[test]\nfn stamp() {\n assert_eq!(env!(\"RCH_BUILD_SOURCE\"), \"bound\");\n \
assert_eq!(std::env::var(\"RCH_BUILD_SOURCE\").unwrap(), \"bound\");\n}\n",
)
.unwrap();
let bound = super::bind_build_source_stamp("cargo nextest run", "bound").unwrap();
let output = std::process::Command::new("/bin/sh")
.args(["-c", &bound])
.current_dir(root.path())
.env("PATH", &path)
.env("CARGO_TARGET_DIR", root.path().join("target"))
.env("RCH_BUILD_SOURCE", "ambient")
.env("RCH_CARGO_WRAPPER_BYPASS", "1")
.env_remove("CARGO_BUILD_TARGET_DIR")
.output()
.unwrap();
assert!(
output.status.success(),
"{bound}: {:?}\n{}",
output.status,
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn build_source_stamp_bind_rejects_shell_evaluation_and_bad_stamps() {
let stamp = "a".repeat(40);
assert!(super::bind_build_source_stamp("cargo build $FLAGS", &stamp).is_err());
assert!(super::bind_build_source_stamp("cargo build; echo x", &stamp).is_err());
assert!(super::bind_build_source_stamp("env --debug cargo build; echo x", &stamp).is_err());
assert!(super::bind_build_source_stamp("env -u cargo build", &stamp).is_err());
assert!(super::bind_build_source_stamp("cargo test `id`", &stamp).is_err());
assert!(super::bind_build_source_stamp("sh -c 'cargo test'", &stamp).is_err());
assert!(super::bind_build_source_stamp("cargo build", "").is_err());
assert!(super::bind_build_source_stamp("cargo build", "bad\nstamp").is_err());
}
#[cfg(target_os = "linux")]
#[test]
fn build_source_stamp_real_cargo_binds_stamp_through_build_script() {
use std::io::Read as _;
use std::path::PathBuf;
let root = tempfile::tempdir().unwrap().keep();
for directory in ["src", "bin", "cargo-home", "target", ".cargo"] {
std::fs::create_dir(root.join(directory)).unwrap();
}
std::fs::write(
root.join("Cargo.toml"),
"[package]\nname='build_source_stamp_fixture'\nversion='0.1.0'\nedition='2021'\n[workspace]\n",
)
.unwrap();
std::fs::write(
root.join("build.rs"),
include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../rch-common/build.rs"
)),
)
.unwrap();
std::fs::write(
root.join("src/main.rs"),
"fn main() { println!(\"{}\", option_env!(\"RCH_GIT_COMMIT\").unwrap_or(\"\")); }\n",
)
.unwrap();
let fixture_git = |args: &[&str]| {
let output = std::process::Command::new("git")
.current_dir(&root)
.args(args)
.output()
.expect("git fixture command runs");
assert!(
output.status.success(),
"git {args:?}: {}",
String::from_utf8_lossy(&output.stderr)
);
String::from_utf8(output.stdout).unwrap().trim().to_owned()
};
fixture_git(&["init", "-q", "-b", "main"]);
fixture_git(&["add", "Cargo.toml", "build.rs", "src/main.rs"]);
fixture_git(&[
"-c",
"user.name=RCH-Test",
"-c",
"user.email=rch-test@example.invalid",
"commit",
"-q",
"--no-gpg-sign",
"-m",
"fixture",
]);
let fixture_head = fixture_git(&["rev-parse", "HEAD"]);
assert_ne!(fixture_head, "a".repeat(40));
let mut cargo = PathBuf::from(env!("CARGO"));
if std::fs::metadata(&cargo).unwrap().len() <= 8 * 1024
&& std::fs::read_to_string(&cargo)
.unwrap()
.lines()
.any(|line| line.starts_with("# rch-toolchain-wrap-version:"))
{
cargo.set_file_name("cargo-rch-real");
}
let mut magic = [0; 4];
std::fs::File::open(&cargo)
.unwrap()
.read_exact(&mut magic)
.unwrap();
assert_eq!(
&magic, b"\x7fELF",
"fixture must execute a real Cargo binary"
);
let cargo_bin = cargo.parent().unwrap();
let executable = root.join("bin/cargo");
std::os::unix::fs::symlink(&cargo, &executable).unwrap();
let path = std::env::join_paths(
std::iter::once(cargo_bin.to_path_buf())
.chain(std::env::split_paths(&std::env::var_os("PATH").unwrap())),
)
.unwrap();
let rustc = cargo_bin.join("rustc");
let source_a = "a".repeat(40);
let dirty_a = format!("{source_a}-dirty");
let overlay = format!("{source_a}-overlay-{}", "b".repeat(64));
let alias_c = "c".repeat(40);
let alias_d = "d".repeat(40);
let alias = |key: &str, value: &str| {
[(key.to_owned(), value.to_owned())]
.into_iter()
.collect::<std::collections::HashMap<_, _>>()
};
let cases: Vec<(&str, &str, std::collections::HashMap<String, String>, &str)> = vec![
("plain", &source_a, Default::default(), &source_a),
("dirty", &dirty_a, Default::default(), &dirty_a),
("overlay", &overlay, Default::default(), &overlay),
("unknown-stamp", "unknown", Default::default(), ""),
("malformed-stamp", "not a stamp!", Default::default(), ""),
("cargo-cli-config", &source_a, Default::default(), &alias_d),
(
"cargo-project-config",
&source_a,
Default::default(),
&alias_d,
),
(
"cargo-cli-config-caller-wins",
&source_a,
alias("VERGEN_GIT_SHA", &alias_c),
&alias_c,
),
(
"cargo-cli-config-empty-caller",
&source_a,
alias("VERGEN_GIT_SHA", ""),
&source_a,
),
(
"cargo-cli-config-invalid-caller",
&source_a,
alias("VERGEN_GIT_SHA", "not-a-revision"),
&source_a,
),
(
"explicit-rch-git-commit",
&source_a,
alias("RCH_GIT_COMMIT", &alias_c),
&alias_c,
),
(
"explicit-vergen",
&source_a,
alias("VERGEN_GIT_SHA", &alias_d),
&alias_d,
),
(
"caller-alias-precedence",
&source_a,
[
("RCH_GIT_COMMIT".to_owned(), alias_c.clone()),
("VERGEN_GIT_SHA".to_owned(), alias_d.clone()),
]
.into_iter()
.collect(),
&alias_c,
),
];
for (name, stamp, aliases, expected_stdout) in &cases {
std::fs::write(
root.join(".cargo/config.toml"),
if *name == "cargo-project-config" {
format!("[env]\nVERGEN_GIT_SHA = '{alias_d}'\n")
} else {
String::new()
},
)
.unwrap();
let extra_config = if name.starts_with("cargo-cli-config") {
format!(
" --config {}",
shell_words::quote(&format!("env.VERGEN_GIT_SHA='{alias_d}'"))
)
} else {
String::new()
};
let command = format!(
"{} run --quiet --offline --jobs 1{extra_config}",
shell_words::quote(executable.to_str().unwrap())
);
let bound = super::bind_build_source_stamp(&command, stamp).unwrap();
let env = super::super::source_fidelity::build_source_commit_env(|key| {
aliases.get(key).cloned()
});
let bound = super::super::source_fidelity::bind_build_source_aliases(&bound, &env);
let mut process = std::process::Command::new("sh");
process
.args(["-c", &bound])
.current_dir(&root)
.env("PATH", &path)
.env("HOME", &root)
.env("CARGO_HOME", root.join("cargo-home"))
.env("CARGO_TARGET_DIR", root.join("target"))
.env("RUSTC", &rustc)
.env("RUSTFLAGS", "")
.env("RUSTUP_AUTO_INSTALL", "0")
.env("RCH_CARGO_WRAPPER_BYPASS", "1")
.env_remove("RUSTUP_TOOLCHAIN")
.env_remove("CARGO_ENCODED_RUSTFLAGS")
.env_remove("CARGO_BUILD_RUSTC")
.env_remove("CARGO_BUILD_TARGET")
.env_remove("CARGO_BUILD_TARGET_DIR")
.env_remove("CARGO_BUILD_RUSTFLAGS")
.env_remove("RUSTC_WRAPPER")
.env_remove("RUSTC_WORKSPACE_WRAPPER")
.env_remove("CARGO_BUILD_RUSTC_WRAPPER")
.env_remove("CARGO_BUILD_RUSTC_WORKSPACE_WRAPPER")
.env_remove("RCH_BUILD_SOURCE");
for key in rch_common::BUILD_COMMIT_ENV_VARS {
process.env(key, "e".repeat(40));
}
let output = process.output().unwrap();
let stdout = String::from_utf8(output.stdout).unwrap();
assert!(
output.status.success(),
"{name}: {stdout}\n{}",
String::from_utf8_lossy(&output.stderr)
);
assert_eq!(
stdout.trim_end(),
*expected_stdout,
"{name}: stderr={}",
String::from_utf8_lossy(&output.stderr)
);
}
let env_i_command = format!(
"env -i PATH={} HOME={} RUSTC={} CARGO_HOME={} CARGO_TARGET_DIR={} RUSTUP_AUTO_INSTALL=0 RCH_CARGO_WRAPPER_BYPASS=1 {} run --quiet --offline --jobs 1",
shell_words::quote(path.to_str().unwrap()),
shell_words::quote(root.to_str().unwrap()),
shell_words::quote(rustc.to_str().unwrap()),
shell_words::quote(root.join("cargo-home").to_str().unwrap()),
shell_words::quote(root.join("target").to_str().unwrap()),
shell_words::quote(executable.to_str().unwrap()),
);
let bound = super::bind_build_source_stamp(&env_i_command, &source_a).unwrap();
let bound = super::super::source_fidelity::bind_build_source_aliases(
&bound,
&alias("RCH_GIT_COMMIT", &alias_c),
);
let output = std::process::Command::new("sh")
.args(["-c", &bound])
.current_dir(&root)
.output()
.unwrap();
let stdout = String::from_utf8(output.stdout).unwrap();
assert!(
output.status.success(),
"env -i: {stdout}\n{}",
String::from_utf8_lossy(&output.stderr)
);
assert_eq!(
stdout.trim_end(),
source_a,
"env -i: stderr={}",
String::from_utf8_lossy(&output.stderr)
);
std::fs::write(
root.join(".cargo/config.toml"),
format!("[env]\nVERGEN_GIT_SHA = '{alias_d}'\n"),
)
.unwrap();
let output = std::process::Command::new("sh")
.args(["-c", &bound])
.current_dir(&root)
.output()
.unwrap();
assert!(
output.status.success(),
"env -i with config: {}",
String::from_utf8_lossy(&output.stderr)
);
assert_eq!(
String::from_utf8(output.stdout).unwrap().trim_end(),
alias_d,
"Cargo config must apply after caller env -i clears restored aliases"
);
eprintln!(
"build-source real Cargo evidence retained at {}",
root.display()
);
}
#[test]
fn managed_xwin_build_preserves_plugin_argv_and_original_output_policy() {
for command in [
"cargo xwin build --release --target=x86_64-pc-windows-msvc --bin cli",
"cargo +nightly xwin build --release '--target=aarch64-pc-windows-msvc' --bin cli",
"cargo-xwin build --release --target=x86_64-pc-windows-msvc --bin cli",
"cargo-xwin xwin build --release --target=x86_64-pc-windows-msvc --bin cli",
] {
let managed = super::ManagedCargoCommand::new(command, Some("/managed/cache")).unwrap();
let original = shell_words::split(command).unwrap();
let actual = shell_words::split(managed.execution_command()).unwrap();
assert_eq!(&actual[..original.len()], original.as_slice(), "{command}");
assert_eq!(actual[original.len()], "--config");
assert_eq!(
actual[original.len() + 1],
"build.build-dir=\"/managed/cache\""
);
assert_eq!(actual.len(), original.len() + 2);
assert_eq!(managed.policy_command(), command);
assert!(rch_common::patterns::is_cargo_xwin_build(
managed.policy_command()
));
}
for command in [
"cargo xwin check --bin cli",
"cargo xwin build --help",
"cargo xwin install cli",
"cargo-xwin +nightly build --bin cli",
"cargo-xwin xwin test --bin cli",
"cargo xwin build --build-dir=/unmanaged",
"cargo xwin build --bin cli; echo surprise",
] {
assert!(
super::ManagedCargoCommand::new(command, Some("/managed/cache")).is_err(),
"{command}"
);
}
}
#[test]
fn source_pair_build_dir_preserves_format_and_refuses_ambiguous_commands() {
let fmt = "env RUSTUP_TOOLCHAIN=nightly cargo fmt --check";
assert_eq!(
managed_clean_overlay_cargo_build_dir(fmt, "/managed").unwrap(),
fmt
);
for command in [
"",
"cargo",
"cargo-zigbuild build --release",
"nice -n 5 cargo build",
"env --debug cargo build",
"cargo --config",
"cargo test 'unterminated",
"cargo test; echo surprise",
"cargo test $(echo filter)",
"cargo test $FILTER",
"cargo test > output",
"sh -c 'cargo test'",
"env -S 'cargo test'",
"env -u",
"rustup run",
"cargo custom-build",
"cargo test --build-dir /unmanaged",
"cargo test --build-dir=/unmanaged",
] {
assert!(
managed_clean_overlay_cargo_build_dir(command, "/managed").is_err(),
"{command}"
);
}
assert!(managed_clean_overlay_cargo_build_dir("cargo test", "").is_err());
assert!(managed_clean_overlay_cargo_build_dir("cargo test", "/bad\npath").is_err());
let passthrough =
managed_clean_overlay_cargo_build_dir("cargo test -- --build-dir=/literal", "/managed")
.unwrap();
assert_eq!(
shell_words::split(&passthrough).unwrap().last().unwrap(),
"--build-dir=/literal"
);
}
#[test]
fn target_dir_scope_wrappers_and_cli_precedence_agree_with_removal() {
for command in [
"env -- cargo build --target-dir 'caller target'",
"/usr/bin/time -f cargo -- cargo build --target-dir='caller target'",
"env -- rustup run nightly cargo +nightly test --target-dir 'caller target' -- --target-dir=program-value",
"nice -n 10 cargo build --target-dir 'caller target'",
"CARGO_TARGET_DIR=env-target cargo build --target-dir 'caller target'",
"env -- CARGO_TARGET_DIR=env-target cargo build --target-dir 'caller target'",
] {
let tokens = shell_words::split(command).unwrap();
assert_eq!(
super::extract_cargo_target_dir_from_command_tokens(&tokens).as_deref(),
Some("caller target"),
"{command}"
);
let (span, _) = super::cargo_target_dir_flag_span(&tokens).unwrap();
let mut expected = tokens.clone();
expected.drain(span);
assert_eq!(
super::strip_cargo_target_dir_flags_from_command_tokens(&tokens),
Some(expected),
"{command}"
);
let reporter = super::HookReporter::new(super::OutputVisibility::None);
let local = super::resolve_forwarded_cargo_target_dir_with_lookup(
Some(super::CompilationKind::CargoBuild),
std::path::Path::new("/project"),
&reporter,
|_| Some("ambient-target".to_string()),
Some(&tokens),
)
.unwrap();
assert_eq!(local, std::path::Path::new("/project/caller target"));
let rewritten = super::rewrite_cargo_target_dir_command_for_remote(
command,
Some(&tokens),
Some(&local),
&reporter,
);
assert!(
super::cargo_target_dir_flag_span(&shell_words::split(&rewritten).unwrap())
.is_none(),
"caller target-dir survived in remote Cargo argv: {rewritten}"
);
}
}
#[test]
fn target_dir_scope_keeps_opaque_values_passthrough_and_invalid_options() {
for option in [
"--config",
"--target",
"--manifest-path",
"--lockfile-path",
"--profile",
"--package",
"-p",
"--exclude",
"--features",
"-F",
"--bin",
"--example",
"--test",
"--bench",
"--color",
"--message-format",
"--jobs",
"-j",
"-Z",
"-C",
"--artifact-dir",
"--out-dir",
"--build-dir",
] {
let tokens = shell_words::split(&format!(
"env -- cargo build {option} --target-dir=decoy --target-dir actual -- --target-dir=program"
))
.unwrap();
assert_eq!(
super::extract_cargo_target_dir_from_command_tokens(&tokens).as_deref(),
Some("actual"),
"{option}"
);
let stripped =
super::strip_cargo_target_dir_flags_from_command_tokens(&tokens).unwrap();
assert!(stripped.iter().any(|word| word == "--target-dir=decoy"));
assert_eq!(stripped.last().unwrap(), "--target-dir=program");
}
for command in [
"env -- cargo test -- --target-dir=program",
"cargo build --config --target-dir=decoy",
"/usr/bin/time -f --target-dir=decoy cargo build",
"env -u --target-dir=decoy cargo build",
"printf cargo --target-dir decoy",
"cargo build --target-dir",
"cargo build --target-dir=",
"cargo build --target-dir --release",
"cargo build --target-dir one --target-dir two",
] {
let tokens = shell_words::split(command).unwrap();
assert_eq!(
super::cargo_target_dir_flag_span(&tokens),
None,
"{command}"
);
assert_eq!(
super::strip_cargo_target_dir_flags_from_command_tokens(&tokens),
None,
"{command}"
);
}
}
}