#![cfg(test)]
use std::fs;
use std::io::{Cursor, Write};
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use tempfile::TempDir;
use super::*;
const VERSION: &str = "1.2.3-unstable.20260923";
const HASH: &str = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
const PLATFORMS: &[&str] = &[
"darwin-arm64",
"darwin-x64",
"linux-arm64",
"linux-x64",
"linuxmusl-arm64",
"linuxmusl-x64",
"win32-arm64",
"win32-x64",
];
#[test]
fn archive_integrity_keeps_exact_lowercase_digest_and_mismatch_checks() {
let hash = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
assert!(verify_hash(b"abc", hash));
assert!(!verify_hash(b"abd", hash));
assert!(!verify_hash(b"abc", &hash.to_ascii_uppercase()));
assert!(!verify_hash(b"abc", &hash[..62]));
}
#[test]
fn windows_runtime_archive_preserves_oneauth_and_its_terms_beside_the_runtime() {
let platform = Platform {
package_name: "copilot-win32-x64",
binary_name: "copilot.exe",
};
let package = tar_archive(&[
("package/copilot-runtime.exe", b"runtime wrapper"),
("package/prebuilds/win32-x64/runtime.node", b"runtime"),
(
"package/prebuilds/win32-x64/OneAuthInterop.dll",
b"native authentication",
),
(
"package/prebuilds/win32-x64/OneAuthInterop.LICENSE.txt",
b"native terms",
),
]);
let archive = build_embedded_runtime_archive(&package, platform, false);
let root = fixture_dir();
tar::Archive::new(flate2::read::GzDecoder::new(Cursor::new(archive)))
.unpack(root.path())
.unwrap();
assert_eq!(
fs::read(root.path().join("OneAuthInterop.dll")).unwrap(),
b"native authentication"
);
assert_eq!(
fs::read(root.path().join("OneAuthInterop.LICENSE.txt")).unwrap(),
b"native terms"
);
assert_eq!(
fs::read(root.path().join("runtime.node")).unwrap(),
b"runtime"
);
}
fn release(sdk: bool) -> Release {
Release::new(
VERSION.into(),
sdk.then_some(format!(
"https://github.com/github/copilot-sdk/releases/download/runtime-{VERSION}"
))
.as_deref(),
)
.unwrap()
}
#[test]
fn legacy_and_unstable_snapshots_resolve_every_asset_and_checksums_consistently() {
for sdk in [false, true] {
let release = release(sdk);
let base = if sdk {
format!("https://github.com/github/copilot-sdk/releases/download/runtime-{VERSION}")
} else {
format!("https://github.com/github/copilot-cli/releases/download/v{VERSION}")
};
let metadata = if sdk {
format!("release-url={base}\r\n")
} else {
String::new()
};
assert_eq!(
release.asset_url("SHA256SUMS.txt"),
format!("{base}/SHA256SUMS.txt")
);
for target in PLATFORMS {
let extension = if target.starts_with("win32") {
"zip"
} else {
"tar.gz"
};
let cli_asset = format!("copilot-{target}.{extension}");
let runtime_asset = format!("github-copilot-{VERSION}-{target}.tgz");
for (key, asset) in [
(cli_asset.clone(), cli_asset),
(format!("copilot-{target}"), runtime_asset),
] {
let snapshot = format!(
"# fixture\r\n\r\nversion={VERSION}\r\n{metadata}{key}={}\r\n",
HASH.to_ascii_uppercase()
);
let (parsed, hash) = parse_snapshot(&snapshot, &key).unwrap();
assert_eq!(parsed, release);
assert_eq!(hash, HASH);
assert_eq!(parsed.asset_url(&asset), format!("{base}/{asset}"));
let expected_key = if sdk {
format!("copilot-sdk-runtime-{VERSION}-{asset}")
} else {
format!("v{VERSION}-{asset}")
};
assert_eq!(parsed.cache_key(&asset), expected_key);
assert_eq!(
find_sha256_for_asset(&format!("{HASH} *{asset}\r\n"), &asset),
HASH
);
}
}
}
}
#[test]
fn explicit_legacy_url_and_omitted_url_have_the_same_identity() {
for version in [
"1.2.3",
"1.2.3-4",
"0.0.0-dev",
"1.2.3-unstable.r123.gabcdef0",
"1.2.3-4.unstable.r123.gabcdef0",
] {
let implicit = Release::new(version.into(), None).unwrap();
let explicit = Release::new(
version.into(),
Some(&format!(
"https://github.com/github/copilot-cli/releases/download/v{version}"
)),
)
.unwrap();
assert_eq!(implicit, explicit);
assert_eq!(implicit.cache_identity(), version);
}
assert_ne!(
release(false).cache_identity(),
release(true).cache_identity()
);
}
#[test]
fn source_checkouts_without_snapshots_resolve_canonical_unstable_releases() {
let root = fixture_dir();
let manifest_dir = root.path().join("rust");
let node_dir = root.path().join("nodejs");
fs::create_dir_all(&manifest_dir).unwrap();
fs::create_dir_all(&node_dir).unwrap();
assert!(!manifest_dir.join("cli-version.txt").exists());
assert!(!manifest_dir.join("cli-version-in-process.txt").exists());
for (version, sdk_release) in [
("1.2.3", false),
("1.2.3-4", false),
("0.0.0-dev", false),
("1.2.3-unstable.r123.gabcdef0", true),
("1.2.3-4.unstable.r123.gabcdef0", true),
("0.0.0-0.unstable.r1.g0000000", true),
("1.2.3-unstable.20260923", false),
("1.2.3.unstable.r123.gabcdef0", false),
("1.2.3-unstable.r0.gabcdef0", false),
("1.2.3-unstable.r0123.gabcdef0", false),
("01.2.3-unstable.r123.gabcdef0", false),
("1.2.3-04.unstable.r123.gabcdef0", false),
("1.2.3-unstable.r123.gabcdef00", false),
("1.2.3-unstable.r123.gABCDEF0", false),
] {
fs::write(
node_dir.join("package.json"),
serde_json::json!({ "copilotCliVersion": version }).to_string(),
)
.unwrap();
let (release, hash) = resolve_version_and_optional_hash(&manifest_dir, "copilot-linux-x64");
assert_eq!(release.version, version);
assert_eq!(hash, None);
let base = if sdk_release {
format!("https://github.com/github/copilot-sdk/releases/download/runtime-{version}")
} else {
format!("https://github.com/github/copilot-cli/releases/download/v{version}")
};
for asset in [
"SHA256SUMS.txt".into(),
"copilot-linux-x64.tar.gz".into(),
format!("github-copilot-{version}-linux-x64.tgz"),
] {
assert_eq!(release.asset_url(&asset), format!("{base}/{asset}"));
let key = if sdk_release {
format!("copilot-sdk-runtime-{version}-{asset}")
} else {
format!("v{version}-{asset}")
};
assert_eq!(release.cache_key(&asset), key);
}
}
}
#[test]
fn source_checkouts_still_prefer_snapshots_and_preserve_legacy_locations() {
let root = fixture_dir();
let manifest_dir = root.path().join("rust");
let node_dir = root.path().join("nodejs");
fs::create_dir_all(&manifest_dir).unwrap();
fs::create_dir_all(&node_dir).unwrap();
fs::write(
node_dir.join("package.json"),
r#"{"copilotCliVersion":"9.9.9"}"#,
)
.unwrap();
let version = "1.2.3-4.unstable.r123.gabcdef0";
for sdk_release in [false, true] {
let base = if sdk_release {
format!("https://github.com/github/copilot-sdk/releases/download/runtime-{version}")
} else {
format!("https://github.com/github/copilot-cli/releases/download/v{version}")
};
let location = if sdk_release {
format!("release-url={base}\n")
} else {
String::new()
};
fs::write(
manifest_dir.join("cli-version-in-process.txt"),
format!("version={version}\n{location}copilot-linux-x64={HASH}\n"),
)
.unwrap();
let (release, hash) = resolve_version_and_optional_hash(&manifest_dir, "copilot-linux-x64");
assert_eq!(release.version, version);
assert_eq!(hash.as_deref(), Some(HASH));
assert_eq!(
release.asset_url("SHA256SUMS.txt"),
format!("{base}/SHA256SUMS.txt")
);
}
}
#[test]
fn snapshots_reject_mismatched_versions_untrusted_locations_and_invalid_hashes() {
for url in [
"https://github.com/github/copilot-sdk/releases/download/runtime-9.9.9",
"https://github.com/github/copilot-sdk/releases/latest",
"https://github.com/github/docs/releases/download/runtime-1.2.3",
"https://token@github.com/github/copilot-sdk/releases/download/runtime-1.2.3",
"https://github.com/github/copilot-cli/releases/download/v1.2.3/",
"https://github.com/github/copilot-cli/releases/download/v1.2.3?token=secret",
"http://github.com/github/copilot-cli/releases/download/v1.2.3",
] {
let snapshot = format!("version=1.2.3\nrelease-url={url}\nasset={HASH}");
assert!(parse_snapshot(&snapshot, "asset").is_err(), "{url}");
}
for snapshot in [
format!("version=\nasset={HASH}"),
format!("version=../1.2.3\nasset={HASH}"),
format!("version=1.2.3\nversion=1.2.4\nasset={HASH}"),
format!("version=1.2.3\nasset={HASH}\nasset={HASH}"),
format!("version=1.2.3\nrelease-url=\nrelease-url=\nasset={HASH}"),
format!("version=1.2.3\nother={HASH}"),
"version=1.2.3\nasset=bad-hash".into(),
format!("version=1.2.3\nmalformed line\nasset={HASH}"),
] {
assert!(parse_snapshot(&snapshot, "asset").is_err(), "{snapshot}");
}
}
#[test]
fn checksum_lookup_rejects_missing_duplicate_and_invalid_entries() {
for sums in [
format!("{HASH} asset-other\n"),
format!("{HASH} asset\n{HASH} *asset\n"),
"invalid asset\n".into(),
] {
assert!(std::panic::catch_unwind(|| find_sha256_for_asset(&sums, "asset")).is_err());
}
}
fn fixture_dir() -> TempDir {
let root = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("target")
.join("acquisition-tests");
fs::create_dir_all(&root).unwrap();
tempfile::Builder::new()
.prefix("fixture-")
.tempdir_in(root)
.unwrap()
}
#[test]
fn cache_hits_are_verified_and_corruption_is_evicted() {
let fixture = fixture_dir();
let bytes = b"verified release archive";
let hash = "bed93df9281ee06f13474bdf2a1280a32da01daf3926139e5b22b98c0f8122af".to_owned();
let path = fixture.path().join(release(true).cache_key("asset"));
assert_eq!(read_verified_cache(&path, &hash), None);
fs::write(&path, bytes).unwrap();
assert_eq!(
read_verified_cache(&path, &hash).as_deref(),
Some(bytes.as_slice())
);
fs::write(&path, b"corrupt release archive").unwrap();
assert_eq!(read_verified_cache(&path, &hash), None);
assert!(!path.exists());
}
fn tar_archive(files: &[(&str, &[u8])]) -> Vec<u8> {
let encoder = flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::default());
let mut archive = tar::Builder::new(encoder);
for (name, bytes) in files {
append_archive_file(&mut archive, name, bytes, 0o755);
}
archive.into_inner().unwrap().finish().unwrap()
}
struct Fixture {
dir: TempDir,
platform: Platform,
release: Release,
}
impl Fixture {
fn new(sdk: bool, windows: bool) -> Self {
let fixture = Self {
dir: fixture_dir(),
platform: Platform {
package_name: if windows {
"copilot-win32-x64"
} else {
"copilot-linux-x64"
},
binary_name: if windows { "copilot.exe" } else { "copilot" },
},
release: release(sdk),
};
for name in ["out", "cache", "extracted"] {
fs::create_dir_all(fixture.path(name)).unwrap();
}
let cli = if windows {
let mut archive = zip::ZipWriter::new(Cursor::new(Vec::new()));
archive
.start_file("copilot.exe", zip::write::SimpleFileOptions::default())
.unwrap();
archive.write_all(b"MZ fixture CLI").unwrap();
archive.finish().unwrap().into_inner()
} else {
tar_archive(&[("copilot", b"fixture CLI")])
};
let target = fixture
.platform
.package_name
.strip_prefix("copilot-")
.unwrap();
let runtime = tar_archive(&[
(
&format!("package/{}", fixture.platform.runtime_wrapper_name()),
b"fixture wrapper",
),
(
&format!("package/prebuilds/{target}/runtime.node"),
b"fixture native library",
),
("package/tls/roots.pem", b"fixture support file"),
]);
for (snapshot, key, asset, bytes) in [
(
"cli-version.txt",
fixture.platform.cli_asset_name(),
fixture.platform.cli_asset_name(),
cli,
),
(
"cli-version-in-process.txt",
fixture.platform.package_name.into(),
format!("github-copilot-{VERSION}-{target}.tgz"),
runtime,
),
] {
let location = if sdk {
format!(
"release-url=https://github.com/github/copilot-sdk/releases/download/runtime-{VERSION}\n"
)
} else {
String::new()
};
fs::write(
fixture.path(snapshot),
format!(
"version={VERSION}\n{location}{key}={}\n",
archive_hash::sha256(&bytes)
.iter()
.map(|byte| format!("{byte:02x}"))
.collect::<String>()
),
)
.unwrap();
fs::write(
fixture
.path("cache")
.join(fixture.release.cache_key(&asset)),
bytes,
)
.unwrap();
}
fixture
}
fn path(&self, path: &str) -> PathBuf {
self.dir.path().join(path)
}
fn command(&self, bundled: bool, in_process: bool) -> Command {
let mut command = Command::new(std::env::current_exe().unwrap());
command
.current_dir(self.dir.path())
.args([
"--exact",
"implementation::tests::run_build_script",
"--nocapture",
])
.env("COPILOT_ACQUISITION_TEST_CHILD", "1")
.env("CARGO_MANIFEST_DIR", self.dir.path())
.env("OUT_DIR", self.path("out"))
.env("BUNDLED_CLI_CACHE_DIR", self.path("cache"))
.env("COPILOT_CLI_EXTRACT_DIR", self.path("extracted"))
.env(
"CARGO_CFG_TARGET_OS",
if self.platform.package_name.contains("win32") {
"windows"
} else {
"linux"
},
)
.env("CARGO_CFG_TARGET_ARCH", "x86_64")
.env("CARGO_CFG_TARGET_ENV", "")
.env("HOST", "test-host")
.env("TARGET", "test-target")
.env("OPENSSL_STATIC", "0")
.env("OPENSSL_NO_VENDOR", "1")
.env("CARGO_FEATURE_RUNTIME", "1")
.env_remove("COPILOT_SKIP_CLI_DOWNLOAD")
.env_remove("DOCS_RS")
.env_remove("CARGO_FEATURE_LOCAL_RUNTIME")
.env_remove("CARGO_FEATURE_BUNDLED_CLI")
.env_remove("CARGO_FEATURE_NETWORK_FORWARDING")
.env_remove("DEP_OPENSSL_VERSION_NUMBER")
.env_remove("DEP_OPENSSL_RUNTIME_BINDINGS")
.env_remove("DEP_OPENSSL_VENDORED")
.env_remove("TEST_HOST_OPENSSL_STATIC")
.env_remove("TEST_HOST_OPENSSL_NO_VENDOR")
.env_remove("TEST_TARGET_OPENSSL_STATIC")
.env_remove("TEST_TARGET_OPENSSL_NO_VENDOR")
.env_remove("CARGO_FEATURE_IN_PROCESS");
if bundled {
command.env("CARGO_FEATURE_BUNDLED_CLI", "1");
}
if in_process {
command.env("CARGO_FEATURE_IN_PROCESS", "1");
}
#[cfg(windows)]
{
use std::os::windows::process::CommandExt;
const CREATE_NO_WINDOW: u32 = 0x0800_0000;
command.creation_flags(CREATE_NO_WINDOW);
}
command
}
}
#[track_caller]
fn succeeded(output: Output) -> String {
assert!(
output.status.success(),
"stdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8(output.stdout).unwrap();
assert!(!stdout.contains("Downloading "), "{stdout}");
stdout
}
#[test]
fn run_build_script() {
match std::env::var("COPILOT_ACQUISITION_TEST_CHILD").as_deref() {
Ok("verified-host-overrides") => {
require_dynamic_openssl("Linux SDK build host", "test-host", true);
}
Ok("verify-target-provider") => {
openssl_linkage::require_target_provider(false);
}
Ok(_) => super::main(),
Err(_) => {}
}
}
#[test]
fn verified_shared_hosts_accept_unset_overrides_but_reject_incompatible_values() {
let fixture = Fixture::new(true, false);
for (name, value, accepted) in [
("OPENSSL_STATIC", None, true),
("OPENSSL_NO_VENDOR", None, true),
("OPENSSL_STATIC", Some("1"), false),
("OPENSSL_STATIC", Some(""), false),
("OPENSSL_NO_VENDOR", Some("0"), false),
("TEST_HOST_OPENSSL_STATIC", Some("1"), false),
("TEST_HOST_OPENSSL_NO_VENDOR", Some("0"), false),
("DEP_OPENSSL_VENDORED", Some("1"), false),
] {
let mut command = fixture.command(false, false);
command
.env("COPILOT_ACQUISITION_TEST_CHILD", "verified-host-overrides")
.env_remove("OPENSSL_STATIC")
.env_remove("OPENSSL_NO_VENDOR");
if let Some(value) = value {
command.env(name, value);
}
let output = command.output().unwrap();
assert_eq!(
output.status.success(),
accepted,
"{name}={value:?}:\nstdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
if !accepted {
assert!(
String::from_utf8_lossy(&output.stderr).contains("requires OS OpenSSL 3"),
"{name}={value:?}"
);
}
}
}
#[cfg(target_os = "linux")]
#[test]
fn linux_shared_host_build_modes_need_no_repository_openssl_overrides() {
for skip in [
None,
Some("CARGO_FEATURE_LOCAL_RUNTIME"),
Some("COPILOT_SKIP_CLI_DOWNLOAD"),
Some("DOCS_RS"),
] {
let fixture = Fixture::new(true, false);
let mut command = fixture.command(false, true);
command
.env_remove("OPENSSL_STATIC")
.env_remove("OPENSSL_NO_VENDOR");
if let Some(skip) = skip {
command.env(skip, "1");
} else {
command.env_remove("CARGO_FEATURE_RUNTIME");
}
let stdout = succeeded(command.output().unwrap());
assert!(!stdout.contains("cargo:rustc-cfg=has_"));
}
let fixture = Fixture::new(true, false);
let stdout = succeeded(
fixture
.command(true, true)
.env_remove("OPENSSL_STATIC")
.env_remove("OPENSSL_NO_VENDOR")
.output()
.unwrap(),
);
assert!(stdout.contains("cargo:rustc-cfg=has_bundled_cli"));
}
#[cfg(target_os = "linux")]
#[test]
fn native_linux_forwarding_uses_the_attested_shared_provider_without_overrides() {
let fixture = Fixture::new(true, false);
let output = fixture
.command(true, true)
.env("HOST", "test-target")
.env("CARGO_FEATURE_NETWORK_FORWARDING", "1")
.env("DEP_OPENSSL_VERSION_NUMBER", "30000000")
.env_remove("OPENSSL_STATIC")
.env_remove("OPENSSL_NO_VENDOR")
.output()
.unwrap();
assert!(succeeded(output).contains("cargo:rustc-cfg=has_bundled_cli"));
}
#[cfg(target_os = "macos")]
const APPLE_TARGETS: [&str; 2] = ["aarch64-apple-darwin", "x86_64-apple-darwin"];
fn consumer_sdk_packages(
features: &[&str],
edges: &str,
depth: Option<u32>,
target: Option<&str>,
) -> Vec<String> {
let root = fixture_dir();
let sdk = Path::new(env!("CARGO_MANIFEST_DIR"));
let manifest = format!(
"[package]\nname = \"sdk-consumer-fixture\"\nversion = \"0.0.0\"\nedition = \"2024\"\n\
[workspace]\n[dependencies]\ngithub-copilot-sdk = {{ path = {}, default-features = false, features = {} }}\n",
serde_json::to_string(&sdk.to_string_lossy()).unwrap(),
serde_json::to_string(features).unwrap()
);
fs::write(root.path().join("Cargo.toml"), manifest).unwrap();
fs::copy(sdk.join("Cargo.lock"), root.path().join("Cargo.lock")).unwrap();
fs::create_dir(root.path().join("src")).unwrap();
fs::write(root.path().join("src/lib.rs"), "").unwrap();
let mut command = Command::new(env!("CARGO"));
command.current_dir(root.path()).args([
"tree",
"--package",
"github-copilot-sdk",
"--edges",
edges,
"--prefix",
"none",
"--format",
"{p}",
"--offline",
]);
if let Some(depth) = depth {
command.args(["--depth", &depth.to_string()]);
}
if let Some(target) = target {
command.args(["--target", target]);
}
#[cfg(windows)]
{
use std::os::windows::process::CommandExt;
const CREATE_NO_WINDOW: u32 = 0x0800_0000;
command.creation_flags(CREATE_NO_WINDOW);
}
let output = command.output().unwrap();
assert!(
output.status.success(),
"Cargo dependency resolution for {features:?} on {target:?} failed:\n{}",
String::from_utf8_lossy(&output.stderr)
);
let tree = String::from_utf8(output.stdout).unwrap();
let packages: Vec<_> = tree
.lines()
.map(|line| {
line.split_whitespace()
.next()
.expect("Cargo package name")
.to_owned()
})
.collect();
assert!(
packages
.iter()
.any(|package| package == "github-copilot-sdk"),
"{tree}"
);
packages
}
#[test]
fn stream_only_consumers_do_not_resolve_native_acquisition_dependencies() {
let packages = consumer_sdk_packages(&[], "normal,build", None, None);
assert_excludes(
&packages,
&[
"ureq",
"native-tls",
"openssl",
"openssl-sys",
"rustls",
"aws-lc-rs",
"aws-lc-sys",
],
"stream-only consumer",
);
}
#[track_caller]
fn assert_excludes(packages: &[String], forbidden: &[&str], consumer: &str) {
for package in forbidden {
assert!(
!packages.iter().any(|resolved| resolved == package),
"{consumer} unexpectedly resolves {package}: {packages:?}"
);
}
}
#[track_caller]
fn assert_includes(packages: &[String], required: &[&str], consumer: &str) {
for package in required {
assert!(
packages.iter().any(|resolved| resolved == package),
"{consumer} does not resolve {package}: {packages:?}"
);
}
}
#[test]
fn acquisition_without_forwarding_does_not_resolve_target_tls_dependencies() {
let forwarding_tls = [
"native-tls",
"openssl-sys",
"reqwest",
"tokio-tungstenite",
"tokio-rustls",
"rustls",
"rustls-platform-verifier",
"aws-lc-rs",
"aws-lc-sys",
];
#[cfg(target_os = "macos")]
let targets = [None, Some(APPLE_TARGETS[0]), Some(APPLE_TARGETS[1])];
#[cfg(not(target_os = "macos"))]
let targets = [None];
for target in targets {
for features in [["runtime"], ["local-runtime"]] {
let packages = consumer_sdk_packages(&features, "normal", None, target);
assert_excludes(
&packages,
&forwarding_tls,
&format!("{features:?} on {target:?}"),
);
if features == ["local-runtime"] {
assert_includes(
&packages,
&["libloading"],
&format!("{features:?} on {target:?}"),
);
}
}
}
#[cfg(feature = "network-forwarding")]
{
let forwarding = consumer_sdk_packages(&["network-forwarding"], "normal", None, None);
assert_includes(&forwarding, &["reqwest"], "forwarding on the host");
#[cfg(target_os = "macos")]
for target in APPLE_TARGETS {
let forwarding =
consumer_sdk_packages(&["network-forwarding"], "normal", None, Some(target));
assert_includes(
&forwarding,
&[
"reqwest",
"tokio-rustls",
"rustls",
"aws-lc-rs",
"aws-lc-sys",
],
&format!("forwarding on {target}"),
);
}
}
}
#[test]
#[cfg(feature = "network-forwarding")]
fn forwarding_without_acquisition_does_not_resolve_acquisition_build_dependencies() {
let acquisition = ["ureq", "openssl", "rustls"];
let forwarding = consumer_sdk_packages(&["network-forwarding"], "normal,build", Some(1), None);
assert_excludes(&forwarding, &acquisition, "forwarding");
let runtime = consumer_sdk_packages(&["runtime"], "normal,build", Some(1), None);
assert_includes(&runtime, &["ureq"], "runtime");
#[cfg(target_os = "macos")]
assert_includes(&runtime, &["rustls"], "runtime");
#[cfg(target_os = "linux")]
assert_includes(&runtime, &["openssl"], "runtime");
}
#[test]
fn seeded_builds_support_bundled_in_process_and_extracted_modes_for_both_locations() {
for sdk in [false, true] {
for windows in [false, true] {
for bundled in [false, true] {
for in_process in [false, true] {
let fixture = Fixture::new(sdk, windows);
let stdout = succeeded(fixture.command(bundled, in_process).output().unwrap());
assert!(stdout.contains(&format!(
"cargo:rustc-env=COPILOT_SDK_CLI_CACHE_ID={}",
fixture.release.cache_identity()
)));
if bundled {
assert!(stdout.contains("cargo:rustc-cfg=has_bundled_cli"));
assert!(fixture.path("out/copilot_cli.archive").is_file());
let runtime =
fs::read(fixture.path("out/copilot_runtime.archive")).unwrap();
assert!(archive_contains_tar_entry(
&runtime,
fixture.platform.runtime_wrapper_name()
));
assert!(archive_contains_tar_entry(&runtime, "roots.pem"));
assert_eq!(
archive_contains_tar_entry(
&runtime,
fixture.platform.runtime_library_name()
),
in_process
);
} else {
assert!(stdout.contains("cargo:rustc-cfg=has_extracted_cli"));
assert!(
fixture
.path("extracted")
.join(fixture.platform.runtime_wrapper_name())
.is_file()
);
assert!(fixture.path("extracted/tls/roots.pem").is_file());
assert_eq!(
fixture
.path("extracted")
.join(fixture.platform.runtime_library_name())
.is_file(),
in_process
);
fs::remove_dir_all(fixture.path("cache")).unwrap();
succeeded(fixture.command(bundled, in_process).output().unwrap());
}
}
}
}
}
}
#[test]
fn seeded_acquisition_verifies_archives_without_external_toolchains() {
let fixture = Fixture::new(true, false);
let output = fixture
.command(true, true)
.env("PATH", fixture.dir.path())
.env("DEVELOPER_DIR", fixture.path("missing-developer-tools"))
.output()
.unwrap();
let stdout = succeeded(output);
assert!(stdout.contains("cargo:rustc-cfg=has_bundled_cli"));
let runtime = fs::read(fixture.path("out/copilot_runtime.archive")).unwrap();
assert!(archive_contains_tar_entry(
&runtime,
fixture.platform.runtime_library_name()
));
assert!(archive_contains_tar_entry(
&runtime,
fixture.platform.runtime_wrapper_name()
));
}
#[test]
fn stale_extracted_markers_reinstall_verified_runtime_assets() {
let fixture = Fixture::new(true, false);
succeeded(fixture.command(false, true).output().unwrap());
let wrapper = fixture
.path("extracted")
.join(fixture.platform.runtime_wrapper_name());
fs::write(&wrapper, b"stale wrapper").unwrap();
fs::write(
fixture.path("extracted/.hostless-runtime-assets-v1"),
format!("{VERSION}\n{HASH}\n"),
)
.unwrap();
fs::write(fixture.path("extracted/stale-file"), b"old payload").unwrap();
succeeded(fixture.command(false, true).output().unwrap());
assert_eq!(fs::read(wrapper).unwrap(), b"fixture wrapper");
assert!(!fixture.path("extracted/stale-file").exists());
}
#[test]
fn builds_reject_inconsistent_snapshot_versions_and_locations_before_acquisition() {
for change_version in [false, true] {
let fixture = Fixture::new(true, false);
let path = fixture.path("cli-version.txt");
let contents = fs::read_to_string(&path).unwrap();
let changed = if change_version {
contents.replace(VERSION, "9.9.9")
} else {
contents.replace(
&format!("release-url=https://github.com/github/copilot-sdk/releases/download/runtime-{VERSION}\n"),
""
)
};
fs::write(path, changed).unwrap();
let output = fixture.command(true, false).output().unwrap();
assert!(!output.status.success());
assert!(String::from_utf8_lossy(&output.stderr).contains("same version and release URL"));
assert!(!String::from_utf8_lossy(&output.stdout).contains("Downloading "));
}
}
#[test]
fn external_stream_only_builds_need_no_runtime_artifacts() {
let fixture = Fixture::new(true, false);
fs::remove_file(fixture.path("cli-version.txt")).unwrap();
fs::remove_file(fixture.path("cli-version-in-process.txt")).unwrap();
fs::remove_dir_all(fixture.path("cache")).unwrap();
let mut command = fixture.command(false, false);
command.env_remove("CARGO_FEATURE_RUNTIME");
let stdout = succeeded(command.output().unwrap());
assert!(!stdout.contains("cargo:rustc-env=COPILOT_SDK_CLI_VERSION"));
assert!(!stdout.contains("cargo:rustc-cfg=has_"));
assert!(!fixture.path("extracted/copilot-runtime").exists());
}
#[test]
fn skip_modes_need_no_snapshots_and_local_runtime_preserves_bundled_precedence() {
for skip in [
"DOCS_RS",
"COPILOT_SKIP_CLI_DOWNLOAD",
"CARGO_FEATURE_LOCAL_RUNTIME",
] {
let fixture = Fixture::new(true, false);
fs::remove_file(fixture.path("cli-version.txt")).unwrap();
fs::remove_file(fixture.path("cli-version-in-process.txt")).unwrap();
fs::remove_dir_all(fixture.path("cache")).unwrap();
let mut command = fixture.command(false, true);
command.env(skip, "1");
let stdout = succeeded(command.output().unwrap());
assert!(!stdout.contains("cargo:rustc-cfg=has_"));
}
let fixture = Fixture::new(true, false);
let mut command = fixture.command(true, true);
command.env("CARGO_FEATURE_LOCAL_RUNTIME", "1");
assert!(succeeded(command.output().unwrap()).contains("cargo:rustc-cfg=has_bundled_cli"));
}
#[test]
fn openssl_version_guard_preserves_the_major_3_build_host_and_target_contract() {
for boundary in ["Linux SDK build host", "Linux SDK target"] {
for version in [0x3000_0000, 0x3000_0120, 0x3050_0090] {
require_openssl_3(boundary, version);
}
for version in [0, 0x1000_20bf, 0x1010_107f, 0x2000_0000, 0x4000_0000] {
assert!(
std::panic::catch_unwind(|| require_openssl_3(boundary, version)).is_err(),
"{boundary} accepted unsupported version {version:#x}"
);
}
}
}
#[test]
fn runtime_loaded_targets_require_the_exact_common_api_profile() {
let fixture = Fixture::new(true, false);
for (version, accepted) in [
("1010117f", true),
("1010107f", false),
("10100000", false),
("30000000", false),
("40000000", false),
("invalid", false),
] {
let output = fixture
.command(false, true)
.env("COPILOT_ACQUISITION_TEST_CHILD", "verify-target-provider")
.env("CARGO_FEATURE_NETWORK_FORWARDING", "1")
.env("DEP_OPENSSL_RUNTIME_BINDINGS", "1")
.env("DEP_OPENSSL_VERSION_NUMBER", version)
.env_remove("OPENSSL_STATIC")
.env_remove("OPENSSL_NO_VENDOR")
.output()
.unwrap();
assert_eq!(
output.status.success(),
accepted,
"runtime profile {version}: stdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
if !accepted {
assert!(
String::from_utf8_lossy(&output.stderr).contains("runtime-loaded OpenSSL"),
"profile {version}: {}",
String::from_utf8_lossy(&output.stderr)
);
}
}
}
#[test]
fn runtime_loaded_targets_still_reject_static_and_vendored_overrides() {
let fixture = Fixture::new(true, false);
for (name, value) in [
("OPENSSL_STATIC", "1"),
("OPENSSL_NO_VENDOR", "0"),
("TEST_TARGET_OPENSSL_STATIC", "1"),
("TEST_TARGET_OPENSSL_NO_VENDOR", "0"),
("DEP_OPENSSL_VENDORED", "1"),
] {
let output = fixture
.command(false, true)
.env("COPILOT_ACQUISITION_TEST_CHILD", "verify-target-provider")
.env("CARGO_FEATURE_NETWORK_FORWARDING", "1")
.env("DEP_OPENSSL_RUNTIME_BINDINGS", "1")
.env("DEP_OPENSSL_VERSION_NUMBER", "1010117f")
.env(name, value)
.output()
.unwrap();
assert!(!output.status.success(), "accepted {name}={value}");
assert!(
String::from_utf8_lossy(&output.stderr)
.contains("requires non-vendored runtime OpenSSL bindings"),
"{name}={value}: {}",
String::from_utf8_lossy(&output.stderr)
);
}
}
#[test]
fn linux_forwarding_builds_reject_unsupported_openssl_before_acquisition_or_skip_modes() {
let fixture = Fixture::new(true, false);
for version in [
None,
Some("1010107f"),
Some("20000000"),
Some("40000000"),
Some("invalid"),
] {
for skip in [
None,
Some("DOCS_RS"),
Some("COPILOT_SKIP_CLI_DOWNLOAD"),
Some("CARGO_FEATURE_LOCAL_RUNTIME"),
] {
let mut command = fixture.command(false, true);
command.env("CARGO_FEATURE_NETWORK_FORWARDING", "1");
if let Some(version) = version {
command.env("DEP_OPENSSL_VERSION_NUMBER", version);
}
if let Some(skip) = skip {
command.env(skip, "1");
}
let output = command.output().unwrap();
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
!output.status.success(),
"accepted OpenSSL metadata {version:?}, skip {skip:?}:\n{stdout}\n{stderr}"
);
assert!(
stderr.contains("Linux SDK target requires OS OpenSSL 3"),
"OpenSSL metadata {version:?}, skip {skip:?}:\n{stdout}\n{stderr}"
);
assert!(!stdout.contains("Downloading "), "{stdout}");
}
}
}
#[test]
fn linux_forwarding_builds_accept_openssl_3_0_without_requiring_optional_hpke_apis() {
let fixture = Fixture::new(true, false);
for version in ["30000000", "30000120", "30500090"] {
let mut command = fixture.command(false, false);
command
.env("CARGO_FEATURE_NETWORK_FORWARDING", "1")
.env("DEP_OPENSSL_VERSION_NUMBER", version)
.env("COPILOT_SKIP_CLI_DOWNLOAD", "1");
succeeded(command.output().unwrap());
}
}
#[test]
fn linux_forwarding_rejects_static_or_vendored_inputs_before_skip_modes() {
let fixture = Fixture::new(true, false);
for (name, value) in [
("OPENSSL_STATIC", None),
("OPENSSL_STATIC", Some("1")),
("OPENSSL_NO_VENDOR", None),
("OPENSSL_NO_VENDOR", Some("0")),
("TEST_TARGET_OPENSSL_STATIC", Some("1")),
("TEST_TARGET_OPENSSL_NO_VENDOR", Some("0")),
("DEP_OPENSSL_VENDORED", Some("1")),
] {
for skip in [
"DOCS_RS",
"COPILOT_SKIP_CLI_DOWNLOAD",
"CARGO_FEATURE_LOCAL_RUNTIME",
] {
let mut command = fixture.command(false, true);
command
.env("CARGO_FEATURE_NETWORK_FORWARDING", "1")
.env("DEP_OPENSSL_VERSION_NUMBER", "30000000")
.env(skip, "1");
if let Some(value) = value {
command.env(name, value);
} else {
command.env_remove(name);
}
let output = command.output().unwrap();
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
!output.status.success(),
"accepted {name}={value:?}, skip {skip}:\n{stdout}\n{stderr}"
);
assert!(
stderr.contains("requires OS OpenSSL 3"),
"{name}={value:?}, skip {skip}:\n{stdout}\n{stderr}"
);
assert!(!stdout.contains("Downloading "), "{stdout}");
}
}
}
#[test]
fn linux_forwarding_accepts_target_prefixed_dynamic_settings() {
let fixture = Fixture::new(true, false);
let mut command = fixture.command(false, false);
command
.env("CARGO_FEATURE_NETWORK_FORWARDING", "1")
.env("DEP_OPENSSL_VERSION_NUMBER", "30000000")
.env("COPILOT_SKIP_CLI_DOWNLOAD", "1")
.env("OPENSSL_STATIC", "1")
.env("OPENSSL_NO_VENDOR", "0");
for prefix in ["TEST_HOST", "TEST_TARGET"] {
command
.env(format!("{prefix}_OPENSSL_STATIC"), "0")
.env(format!("{prefix}_OPENSSL_NO_VENDOR"), "1");
}
succeeded(command.output().unwrap());
}