commit b917293748074783dc6202aa0553536bde8247a1
parent 90eaea3b890e0c6d54a19810b14e1feafc882186
Author: triesap <tyson@radroots.org>
Date: Sun, 6 Sep 2026 22:48:57 +0000
build: define exact unsigned artifact targets
- Add the frozen service source-lock v3 schema.
- Bind the Lib unsigned artifact contract.
- Narrow native and Nix systems to the supported pair.
- Reject excluded target and contract mutations.
Diffstat:
7 files changed, 455 insertions(+), 30 deletions(-)
diff --git a/build/nix/service/systems.nix b/build/nix/service/systems.nix
@@ -1,6 +1,4 @@
[
"aarch64-darwin"
- "aarch64-linux"
- "x86_64-darwin"
"x86_64-linux"
]
diff --git a/contracts/architecture/decisions/services_hardening_build_qualification.v3.json b/contracts/architecture/decisions/services_hardening_build_qualification.v3.json
@@ -0,0 +1,68 @@
+{
+ "schema": "radroots.services-hardening.build-qualification-decisions.v3",
+ "contract_version": 3,
+ "decision_state": "active",
+ "predecessor": {
+ "schema": "radroots.services-hardening.build-qualification-decisions.v2",
+ "filename": "services_hardening_build_qualification.v2.json",
+ "transition": "forward_only_replace"
+ },
+ "qualification_scope": "native_and_nix_release_foundation",
+ "fixture_root": "tools/xtask/fixtures/service-build-qualification",
+ "supported_rust_targets": [
+ "aarch64-apple-darwin",
+ "x86_64-unknown-linux-gnu"
+ ],
+ "supported_nix_systems": [
+ "aarch64-darwin",
+ "x86_64-linux"
+ ],
+ "excluded_nix_systems": [
+ "x86_64-darwin",
+ "aarch64-linux"
+ ],
+ "required_native_commands": [
+ "cargo build --locked --release",
+ "cargo fmt --all --check",
+ "cargo check --workspace --all-targets --locked",
+ "cargo test --workspace --all-targets --locked",
+ "cargo clippy --workspace --all-targets --locked -- -D warnings",
+ "RUSTDOCFLAGS=-D warnings cargo doc --workspace --no-deps --locked"
+ ],
+ "required_xtask_commands": [
+ "cargo test --locked -p xtask service_source_lock::tests",
+ "cargo test --locked -p xtask service_release_artifacts::tests",
+ "cargo test --locked -p xtask service_build_qualification::tests",
+ "cargo run --locked -q -p xtask -- contract validate",
+ "cargo run --locked -q -p xtask -- release preflight"
+ ],
+ "required_evidence": [
+ "cargo_lock",
+ "source_lock",
+ "package_metadata",
+ "release_metadata",
+ "binary_archive",
+ "oci_source_artifact",
+ "cyclonedx_sbom",
+ "notices",
+ "artifact_manifest",
+ "unsigned_provenance_input",
+ "checksums"
+ ],
+ "fixture_source_lock": "tools/xtask/fixtures/service-build-qualification/radroots.service.source-lock.v2.toml",
+ "fixture_contract": "historical_v2_fixture_until_v3_service_instances_are_owned",
+ "release_artifact_command": "cargo xtask service-release-artifacts",
+ "source_lock_command": "cargo xtask service-source-lock",
+ "source_lock_v3_definition": "contracts/architecture/decisions/services_hardening_source_lock.v3.json",
+ "artifact_contract_v3": "contracts/release/lib-artifact-contract.v3.json",
+ "nix_output_implementation_owner_step": 299,
+ "signing_authority": "external_only",
+ "deferred_outputs": [
+ "nix_packages",
+ "nix_apps",
+ "nix_checks",
+ "nix_development_shells",
+ "nixos_modules",
+ "nix_produced_oci"
+ ]
+}
diff --git a/contracts/architecture/decisions/services_hardening_source_lock.v3.json b/contracts/architecture/decisions/services_hardening_source_lock.v3.json
@@ -0,0 +1,258 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "radroots.services-hardening.rshr-200-service-source-lock.v3",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "schema",
+ "contract_version",
+ "service",
+ "repository",
+ "revision",
+ "architecture",
+ "workspace_catalog_sha256",
+ "version",
+ "source_archive_sha256",
+ "source_archive_contract",
+ "cargo_lock_sha256",
+ "rust_version",
+ "host_feature_profile",
+ "nix",
+ "artifact_contract",
+ "sqlite",
+ "contract_versions"
+ ],
+ "properties": {
+ "schema": {
+ "const": "radroots.service.source-lock.v3"
+ },
+ "contract_version": {
+ "const": 3
+ },
+ "service": {
+ "enum": [
+ "myc",
+ "rhi"
+ ]
+ },
+ "repository": {
+ "const": "https://github.com/radrootslabs/lib"
+ },
+ "revision": {
+ "$ref": "#/$defs/oid"
+ },
+ "architecture": {
+ "const": "radroots.crates.release.v2"
+ },
+ "workspace_catalog_sha256": {
+ "$ref": "#/$defs/sha256"
+ },
+ "version": {
+ "const": "0.1.0-alpha"
+ },
+ "source_archive_sha256": {
+ "$ref": "#/$defs/sha256"
+ },
+ "source_archive_contract": {
+ "const": {
+ "binding": "sha256_of_canonical_exact_lib_revision_tree_archive",
+ "format": "ustar",
+ "compression": "none",
+ "compression_timestamp": "not_applicable",
+ "entry_order": "bytewise_git_path",
+ "path_prefix": "none",
+ "file_mode": "git_index_100644_or_100755",
+ "uid": 0,
+ "gid": 0,
+ "uname": "",
+ "gname": "",
+ "mtime": "lib_revision_commit_timestamp",
+ "pax_headers": "forbidden",
+ "directory_entries": "omitted",
+ "symlinks": "forbidden",
+ "hardlinks": "forbidden",
+ "submodules": "forbidden",
+ "trailer": "two_zero_blocks"
+ }
+ },
+ "cargo_lock_sha256": {
+ "$ref": "#/$defs/sha256"
+ },
+ "rust_version": {
+ "const": "1.97.1"
+ },
+ "host_feature_profile": {
+ "const": "service-host"
+ },
+ "nix": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "material",
+ "lib_revision",
+ "public_input_lock",
+ "parent_result",
+ "supported_systems"
+ ],
+ "properties": {
+ "material": {
+ "const": "qualified"
+ },
+ "lib_revision": {
+ "$ref": "#/$defs/oid"
+ },
+ "public_input_lock": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "path",
+ "sha256",
+ "binding",
+ "mutable_reference",
+ "lib_input"
+ ],
+ "properties": {
+ "path": {
+ "const": "flake.lock"
+ },
+ "sha256": {
+ "$ref": "#/$defs/sha256"
+ },
+ "binding": {
+ "const": "exact_regular_file_bytes"
+ },
+ "mutable_reference": {
+ "const": "forbidden"
+ },
+ "lib_input": {
+ "const": "lib"
+ }
+ }
+ },
+ "parent_result": {
+ "const": {
+ "embedded_in_public_input_lock": false,
+ "embedded_in_source_lock": false,
+ "storage": "separate_generation_scoped_evidence"
+ }
+ },
+ "supported_systems": {
+ "const": [
+ "aarch64-darwin",
+ "x86_64-linux"
+ ]
+ }
+ }
+ },
+ "artifact_contract": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "path",
+ "sha256",
+ "binding"
+ ],
+ "properties": {
+ "path": {
+ "enum": [
+ "contracts/release/myc-artifact-contract.v3.json",
+ "contracts/release/rhi-artifact-contract.v3.json"
+ ]
+ },
+ "sha256": {
+ "$ref": "#/$defs/sha256"
+ },
+ "binding": {
+ "const": "exact_regular_file_bytes_in_same_source_revision"
+ }
+ }
+ },
+ "sqlite": {
+ "const": {
+ "high_level_authority": "sqlx_only",
+ "second_pool_connection_query_transaction_migration_authority": "forbidden",
+ "incremental_backup_adapter": "sealed_native_sqlx_owned_locked_handle_only",
+ "native_linkage_count": 1
+ }
+ },
+ "contract_versions": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "config",
+ "state",
+ "admin",
+ "status",
+ "provider"
+ ],
+ "properties": {
+ "config": {
+ "$ref": "#/$defs/nonzero_u32"
+ },
+ "state": {
+ "$ref": "#/$defs/nonzero_u32"
+ },
+ "admin": {
+ "$ref": "#/$defs/nonzero_u32"
+ },
+ "status": {
+ "$ref": "#/$defs/nonzero_u32"
+ },
+ "provider": {
+ "$ref": "#/$defs/nonzero_u32"
+ }
+ }
+ }
+ },
+ "allOf": [
+ {
+ "if": {
+ "properties": { "service": { "const": "myc" } },
+ "required": ["service"]
+ },
+ "then": {
+ "properties": {
+ "artifact_contract": {
+ "properties": {
+ "path": {
+ "const": "contracts/release/myc-artifact-contract.v3.json"
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "properties": { "service": { "const": "rhi" } },
+ "required": ["service"]
+ },
+ "then": {
+ "properties": {
+ "artifact_contract": {
+ "properties": {
+ "path": {
+ "const": "contracts/release/rhi-artifact-contract.v3.json"
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "$defs": {
+ "oid": {
+ "type": "string",
+ "pattern": "^[0-9a-f]{40}$"
+ },
+ "sha256": {
+ "type": "string",
+ "pattern": "^[0-9a-f]{64}$"
+ },
+ "nonzero_u32": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 4294967295
+ }
+ }
+}
diff --git a/contracts/release/lib-artifact-contract.v3.json b/contracts/release/lib-artifact-contract.v3.json
@@ -0,0 +1 @@
+{"artifact_policy":{"checksums":"required","cyclonedx_version":"1.6","exact_tree_source_archives":"required","fresh_install":"required","git_history_bundles":"forbidden","intoto_statement":"required","notices":"required","reproducibility_build_count":2,"secret_scan":"required","unsigned_packages":"required","unsigned_slsa_provenance":"required"},"contract_version":3,"delivery":{"candidate_class":"unsigned_nonpublishing","developer_id_signing":"forbidden","developer_team_id":"forbidden","distribution_signing":"forbidden","embedded_platform_adhoc_signing":"permitted_non_distribution_only","g2":"unauthorized","notarization":"unauthorized","production_activation":"unauthorized","publication":"unauthorized","signing":"unauthorized"},"implementation_owner_step":298,"output":[{"classification":"production","id":"package","platforms":["macos_aarch64","linux_x86_64"]},{"classification":"production","id":"app","platforms":["macos_aarch64","linux_x86_64"]},{"classification":"production","id":"check","platforms":["macos_aarch64","linux_x86_64"]},{"classification":"production","id":"devshell","platforms":["macos_aarch64","linux_x86_64"]},{"classification":"production","id":"overlay","platforms":["macos_aarch64","linux_x86_64"]},{"classification":"production","id":"shared_helpers","platforms":["macos_aarch64","linux_x86_64"]},{"classification":"fixture_test_only_nondefault","id":"fixture_test_only_nondefault","platforms":["macos_aarch64","linux_x86_64"]}],"package_contract":{"app_role":"installed_release_bundle_inspection","artifact_format":"nix_store_derivation","cargo_package":"radroots","flake_app":"apps.<system>.default","flake_package":"packages.<system>.default","identity":"radroots_lib","package_role":"public_library_workspace_release_bundle","package_version":"0.1.0-alpha","product_version":"0.1.0-alpha"},"platforms":["macos_aarch64","linux_x86_64"],"producer":{"command_authority":"repository_flake","kind":"nix_flake","nix_binding":"required","nix_produced":true,"source_task":"nix_build_repository_outputs"},"repository":"oss/lib","schema":"radroots.release.artifact-contract.v3","source_archive":{"binding":"canonical_exact_source_revision_tree_archive","compression":"none","compression_timestamp":"not_applicable","content":"exact_source_revision_tree","directory_entries":"omitted","entry_order":"bytewise_git_path","file_mode":"git_index_100644_or_100755","format":"ustar","gid":0,"git_history":"forbidden","gname":"","hardlinks":"forbidden","mtime_source":"candidate_source_date_epoch","path_prefix":"none","pax_headers":"forbidden","submodules":"forbidden","symlinks":"forbidden","trailer":"two_zero_blocks","uid":0,"uname":""},"source_binding":{"dirty_tree":"forbidden","kind":"exact_clean_git_commit","revision_location":"aggregate_source_revision"},"sqlite":{"high_level_authority":"sqlx_only","incremental_backup_adapter":"sealed_native_sqlx_owned_locked_handle_only","native_linkage_count":1,"second_pool_connection_query_transaction_migration_authority":"forbidden"}}
diff --git a/contracts/releases/target_matrix.toml b/contracts/releases/target_matrix.toml
@@ -11,8 +11,3 @@ cross_cflags = "-target x86_64-linux-gnu"
[[operating_system]]
name = "macos"
target = "aarch64-apple-darwin"
-
-[[operating_system]]
-name = "windows"
-target = "x86_64-pc-windows-gnu"
-cross_compiler = "x86_64-w64-mingw32-gcc"
diff --git a/tools/xtask/src/service_build_qualification.rs b/tools/xtask/src/service_build_qualification.rs
@@ -8,17 +8,20 @@ use crate::service_source_lock::{
};
const CONTRACT_RELATIVE: &str =
- "contracts/architecture/decisions/services_hardening_build_qualification.v2.json";
+ "contracts/architecture/decisions/services_hardening_build_qualification.v3.json";
const FIXTURE_RELATIVE: &str = "tools/xtask/fixtures/service-build-qualification";
const MAX_CONTRACT_BYTES: usize = 32_768;
const MAX_FIXTURE_FILE_BYTES: usize = 1_048_576;
+const SOURCE_LOCK_V3_SHA256: &str =
+ "3bc32c8ca2cecb06c8f8239ab1fe1fcfba93fe3ef0d60e9b078390347d08f817";
+const ARTIFACT_CONTRACT_V3_SHA256: &str =
+ "bc352a132dd4c0e6f1d2ae7449998833efe1fdda2ab851e512bc9241c49edbf0";
+const NIX_SYSTEMS_RELATIVE: &str = "build/nix/service/systems.nix";
+const NIX_SYSTEMS_BYTES: &[u8] = b"[\n \"aarch64-darwin\"\n \"x86_64-linux\"\n]\n";
-const SUPPORTED_RUST_TARGETS: [&str; 4] = [
- "aarch64-apple-darwin",
- "aarch64-unknown-linux-gnu",
- "x86_64-apple-darwin",
- "x86_64-unknown-linux-gnu",
-];
+const SUPPORTED_RUST_TARGETS: [&str; 2] = ["aarch64-apple-darwin", "x86_64-unknown-linux-gnu"];
+const SUPPORTED_NIX_SYSTEMS: [&str; 2] = ["aarch64-darwin", "x86_64-linux"];
+const EXCLUDED_NIX_SYSTEMS: [&str; 2] = ["x86_64-darwin", "aarch64-linux"];
const REQUIRED_XTASK_COMMANDS: [&str; 5] = [
"cargo test --locked -p xtask service_source_lock::tests",
"cargo test --locked -p xtask service_release_artifacts::tests",
@@ -83,6 +86,8 @@ struct BuildQualificationDecision {
qualification_scope: String,
fixture_root: String,
supported_rust_targets: Vec<String>,
+ supported_nix_systems: Vec<String>,
+ excluded_nix_systems: Vec<String>,
required_native_commands: Vec<String>,
required_xtask_commands: Vec<String>,
required_evidence: Vec<String>,
@@ -90,6 +95,9 @@ struct BuildQualificationDecision {
fixture_contract: String,
release_artifact_command: String,
source_lock_command: String,
+ source_lock_v3_definition: String,
+ artifact_contract_v3: String,
+ nix_output_implementation_owner_step: u32,
signing_authority: String,
deferred_outputs: Vec<String>,
}
@@ -115,28 +123,72 @@ fn validate_contract_inner(workspace_root: &Path) -> Result<(), BuildQualificati
let decision = serde_json::from_slice::<BuildQualificationDecision>(&bytes)
.map_err(|_| BuildQualificationError::InvalidContract)?;
validate_decision(&decision)?;
+ validate_bound_contract(
+ workspace_root,
+ &decision.source_lock_v3_definition,
+ SOURCE_LOCK_V3_SHA256,
+ )?;
+ validate_bound_contract(
+ workspace_root,
+ &decision.artifact_contract_v3,
+ ARTIFACT_CONTRACT_V3_SHA256,
+ )?;
+ if read_bounded(
+ &workspace_root.join(NIX_SYSTEMS_RELATIVE),
+ 1_024,
+ BuildQualificationError::InvalidContract,
+ )? != NIX_SYSTEMS_BYTES
+ {
+ return Err(BuildQualificationError::InvalidContract);
+ }
validate_fixture(workspace_root)
}
+fn validate_bound_contract(
+ workspace_root: &Path,
+ relative: &str,
+ expected_sha256: &str,
+) -> Result<(), BuildQualificationError> {
+ let bytes = read_bounded(
+ &workspace_root.join(relative),
+ MAX_CONTRACT_BYTES,
+ BuildQualificationError::InvalidContract,
+ )?;
+ let _: serde_json::Value =
+ serde_json::from_slice(&bytes).map_err(|_| BuildQualificationError::InvalidContract)?;
+ if digest(&bytes) == expected_sha256 {
+ Ok(())
+ } else {
+ Err(BuildQualificationError::InvalidContract)
+ }
+}
+
fn validate_decision(decision: &BuildQualificationDecision) -> Result<(), BuildQualificationError> {
- let exact = decision.schema == "radroots.services-hardening.build-qualification-decisions.v2"
- && decision.contract_version == 2
+ let exact = decision.schema == "radroots.services-hardening.build-qualification-decisions.v3"
+ && decision.contract_version == 3
&& decision.decision_state == "active"
&& decision.predecessor.schema
- == "radroots.services-hardening.build-qualification-decisions.v1"
- && decision.predecessor.filename == "services_hardening_build_qualification.v1.json"
+ == "radroots.services-hardening.build-qualification-decisions.v2"
+ && decision.predecessor.filename == "services_hardening_build_qualification.v2.json"
&& decision.predecessor.transition == "forward_only_replace"
- && decision.qualification_scope == "native_release_foundation"
+ && decision.qualification_scope == "native_and_nix_release_foundation"
&& decision.fixture_root == FIXTURE_RELATIVE
&& decision.supported_rust_targets == SUPPORTED_RUST_TARGETS
+ && decision.supported_nix_systems == SUPPORTED_NIX_SYSTEMS
+ && decision.excluded_nix_systems == EXCLUDED_NIX_SYSTEMS
&& decision.required_native_commands == REQUIRED_NATIVE_COMMANDS
&& decision.required_xtask_commands == REQUIRED_XTASK_COMMANDS
&& decision.required_evidence == REQUIRED_EVIDENCE
&& decision.fixture_source_lock
== "tools/xtask/fixtures/service-build-qualification/radroots.service.source-lock.v2.toml"
- && decision.fixture_contract == "source_lock_package_and_release_metadata_exact_agreement"
+ && decision.fixture_contract
+ == "historical_v2_fixture_until_v3_service_instances_are_owned"
&& decision.release_artifact_command == "cargo xtask service-release-artifacts"
&& decision.source_lock_command == "cargo xtask service-source-lock"
+ && decision.source_lock_v3_definition
+ == "contracts/architecture/decisions/services_hardening_source_lock.v3.json"
+ && decision.artifact_contract_v3 == "contracts/release/lib-artifact-contract.v3.json"
+ && decision.nix_output_implementation_owner_step == 299
&& decision.signing_authority == "external_only"
&& decision.deferred_outputs == DEFERRED_OUTPUTS;
if exact {
@@ -314,6 +366,8 @@ mod tests {
("/qualification_scope", serde_json::json!("other")),
("/fixture_root", serde_json::json!("other")),
("/supported_rust_targets", serde_json::json!([])),
+ ("/supported_nix_systems", serde_json::json!([])),
+ ("/excluded_nix_systems", serde_json::json!([])),
("/required_native_commands", serde_json::json!([])),
("/required_xtask_commands", serde_json::json!([])),
("/required_evidence", serde_json::json!([])),
@@ -321,6 +375,12 @@ mod tests {
("/fixture_contract", serde_json::json!("other")),
("/release_artifact_command", serde_json::json!("other")),
("/source_lock_command", serde_json::json!("other")),
+ ("/source_lock_v3_definition", serde_json::json!("other")),
+ ("/artifact_contract_v3", serde_json::json!("other")),
+ (
+ "/nix_output_implementation_owner_step",
+ serde_json::json!(1),
+ ),
("/signing_authority", serde_json::json!("internal")),
("/deferred_outputs", serde_json::json!([])),
] {
@@ -500,7 +560,9 @@ mod tests {
#[test]
fn contract_inventory_is_literal_and_complete() {
- assert_eq!(SUPPORTED_RUST_TARGETS.len(), 4);
+ assert_eq!(SUPPORTED_RUST_TARGETS.len(), 2);
+ assert_eq!(SUPPORTED_NIX_SYSTEMS.len(), 2);
+ assert_eq!(EXCLUDED_NIX_SYSTEMS.len(), 2);
assert_eq!(REQUIRED_NATIVE_COMMANDS.len(), 6);
assert_eq!(REQUIRED_XTASK_COMMANDS.len(), 5);
assert_eq!(REQUIRED_EVIDENCE.len(), 11);
diff --git a/tools/xtask/src/target_qualification.rs b/tools/xtask/src/target_qualification.rs
@@ -116,12 +116,6 @@ fn validate(matrix: &TargetMatrix) -> Result<(), String> {
Some("-target x86_64-linux-gnu"),
),
("macos", "aarch64-apple-darwin", None, None),
- (
- "windows",
- "x86_64-pc-windows-gnu",
- Some("x86_64-w64-mingw32-gcc"),
- None,
- ),
];
if matrix.operating_system.len() != expected.len()
|| expected.iter().any(|(name, target, compiler, cflags)| {
@@ -134,7 +128,8 @@ fn validate(matrix: &TargetMatrix) -> Result<(), String> {
})
{
return Err(
- "target matrix must contain the exact Linux, macOS, and Windows triples".to_owned(),
+ "target matrix must contain the exact Linux x86_64 and macOS aarch64 triples"
+ .to_owned(),
);
}
Ok(())
@@ -187,7 +182,7 @@ fn run_command(workspace_root: &Path, program: &str, args: &[&str]) -> Result<()
#[cfg(test)]
mod tests {
- use super::load;
+ use super::{OperatingSystem, TargetMatrix, load, validate};
#[test]
fn current_contract_selects_exact_toolchains_targets_and_packages() {
@@ -198,7 +193,55 @@ mod tests {
let (matrix, packages) = load(root).expect("target matrix");
assert_eq!(matrix.msrv_toolchain, "1.97.1");
assert_eq!(matrix.current_toolchain, "stable");
- assert_eq!(matrix.operating_system.len(), 3);
+ assert_eq!(matrix.operating_system.len(), 2);
+ assert_eq!(
+ matrix
+ .operating_system
+ .iter()
+ .map(|entry| (entry.name.as_str(), entry.target.as_str()))
+ .collect::<Vec<_>>(),
+ [
+ ("linux", "x86_64-unknown-linux-gnu"),
+ ("macos", "aarch64-apple-darwin"),
+ ]
+ );
assert_eq!(packages.len(), 19);
}
+
+ #[test]
+ fn unsupported_production_targets_are_rejected() {
+ let mut matrix = TargetMatrix {
+ schema_version: 1,
+ msrv_toolchain: "1.97.1".to_owned(),
+ current_toolchain: "stable".to_owned(),
+ operating_system: vec![
+ OperatingSystem {
+ name: "linux".to_owned(),
+ target: "x86_64-unknown-linux-gnu".to_owned(),
+ cross_compiler: Some("zig cc".to_owned()),
+ cross_cflags: Some("-target x86_64-linux-gnu".to_owned()),
+ },
+ OperatingSystem {
+ name: "macos".to_owned(),
+ target: "aarch64-apple-darwin".to_owned(),
+ cross_compiler: None,
+ cross_cflags: None,
+ },
+ ],
+ };
+ for (name, target) in [
+ ("windows", "x86_64-pc-windows-gnu"),
+ ("macos", "x86_64-apple-darwin"),
+ ("linux", "aarch64-unknown-linux-gnu"),
+ ] {
+ matrix.operating_system.push(OperatingSystem {
+ name: name.to_owned(),
+ target: target.to_owned(),
+ cross_compiler: None,
+ cross_cflags: None,
+ });
+ assert!(validate(&matrix).is_err(), "accepted {target}");
+ matrix.operating_system.pop();
+ }
+ }
}