commit 37990e397ea6836ea83e38aa88acff9f97173b2b
parent 22787c02c6493165ba1c68b52e1d7688928206de
Author: triesap <tyson@radroots.org>
Date: Fri, 21 Aug 2026 06:10:25 +0000
test: qualify service release gate branches
- Cover release-artifact file admission, identity, mode, inventory, and comparison failures.
- Exercise source-lock root, parser, digest, command, and bounded-read rejection paths.
- Restore the required xtask branch gate without weakening coverage policy or exclusions.
- Verify the exact tree with workspace check, xtask tests, Clippy, coverage, and release preflight.
Diffstat:
2 files changed, 299 insertions(+), 0 deletions(-)
diff --git a/tools/xtask/src/service_release_artifacts.rs b/tools/xtask/src/service_release_artifacts.rs
@@ -2585,6 +2585,189 @@ version = "0.1.0-alpha"
}
#[test]
+ fn low_level_release_admission_and_comparison_branches_are_qualified() {
+ let root = TempDir::new().expect("low-level release fixture");
+ let regular = root.path().join("regular");
+ write_file(®ular, b"same");
+ assert_eq!(
+ read_bounded_regular(®ular, 4, ReleaseArtifactError::InvalidInputArtifact)
+ .expect("bounded regular file"),
+ b"same"
+ );
+ assert!(!contains_bytes(b"bytes", b""));
+
+ let directory = root.path().join("directory");
+ fs::create_dir(&directory).expect("directory fixture");
+ assert_eq!(
+ read_bounded_regular(&directory, 4, ReleaseArtifactError::InvalidInputArtifact),
+ Err(ReleaseArtifactError::InvalidInputArtifact)
+ );
+ let oversized = root.path().join("oversized");
+ write_file(&oversized, b"12345");
+ assert_eq!(
+ read_bounded_regular(&oversized, 4, ReleaseArtifactError::InvalidInputArtifact),
+ Err(ReleaseArtifactError::InvalidInputArtifact)
+ );
+
+ #[cfg(unix)]
+ {
+ use std::os::unix::fs::{MetadataExt as _, PermissionsExt as _};
+
+ let symlink = root.path().join("regular-link");
+ std::os::unix::fs::symlink(®ular, &symlink).expect("regular symlink");
+ assert_eq!(
+ read_bounded_regular(&symlink, 4, ReleaseArtifactError::InvalidInputArtifact),
+ Err(ReleaseArtifactError::InvalidInputArtifact)
+ );
+
+ let expected = fs::symlink_metadata(®ular).expect("regular metadata");
+ assert_eq!(
+ validate_unchanged_input(&symlink, &expected),
+ Err(ReleaseArtifactError::InvalidInputArtifact)
+ );
+ assert_eq!(
+ validate_unchanged_input(&directory, &expected),
+ Err(ReleaseArtifactError::InvalidInputArtifact)
+ );
+
+ let other = root.path().join("other");
+ write_file(&other, b"same");
+ assert_eq!(
+ validate_unchanged_input(&other, &expected),
+ Err(ReleaseArtifactError::InvalidInputArtifact)
+ );
+
+ let device_metadata = fs::symlink_metadata("/dev/null").expect("device metadata");
+ assert_ne!(device_metadata.dev(), expected.dev());
+ assert_eq!(
+ validate_unchanged_input(®ular, &device_metadata),
+ Err(ReleaseArtifactError::InvalidInputArtifact)
+ );
+
+ let same_inode = fs::symlink_metadata(®ular).expect("same-inode metadata");
+ write_file(®ular, b"changed length");
+ assert_eq!(
+ validate_unchanged_input(®ular, &same_inode),
+ Err(ReleaseArtifactError::InvalidInputArtifact)
+ );
+
+ let inventory = root.path().join("symlink-inventory");
+ fs::create_dir(&inventory).expect("symlink inventory");
+ std::os::unix::fs::symlink(&other, inventory.join("entry")).expect("inventory symlink");
+ assert_eq!(
+ directory_inventory(&inventory, ReleaseArtifactError::InvalidInputRoot),
+ Err(ReleaseArtifactError::InvalidInputRoot)
+ );
+
+ let mode_file = root.path().join("mode-file");
+ write_file(&mode_file, b"mode");
+ fs::set_permissions(&mode_file, fs::Permissions::from_mode(0o600))
+ .expect("set invalid file mode");
+ assert_eq!(
+ validate_file_mode(&mode_file),
+ Err(ReleaseArtifactError::StaleOutput)
+ );
+ fs::set_permissions(&directory, fs::Permissions::from_mode(0o700))
+ .expect("set invalid directory mode");
+ assert_eq!(
+ validate_directory_mode(&directory),
+ Err(ReleaseArtifactError::StaleOutput)
+ );
+ }
+
+ let incomplete = root.path().join("incomplete-output");
+ fs::create_dir(&incomplete).expect("incomplete output");
+ write_file(&incomplete.join("LICENSE-MIT"), b"x");
+ assert_eq!(
+ validate_exact_output_inventory(&incomplete),
+ Err(ReleaseArtifactError::GenerationFailure)
+ );
+
+ let expected = root.path().join("expected-output");
+ let actual = root.path().join("actual-output");
+ fs::create_dir(&expected).expect("expected output");
+ fs::create_dir(&actual).expect("actual output");
+ set_directory_mode(&expected).expect("expected directory mode");
+ set_directory_mode(&actual).expect("actual directory mode");
+ for name in OUTPUT_NAMES {
+ write_file(&expected.join(name), b"a");
+ write_file(&actual.join(name), b"a");
+ set_file_mode(&expected.join(name)).expect("expected file mode");
+ set_file_mode(&actual.join(name)).expect("actual file mode");
+ }
+ compare_output(&expected, &actual).expect("matching output");
+ let records = inventory_records(&actual).expect("actual records");
+ validate_output_records(&actual, &records).expect("matching records");
+ write_file(&actual.join("LICENSE-MIT"), b"b");
+ set_file_mode(&actual.join("LICENSE-MIT")).expect("restored file mode");
+ assert_eq!(
+ compare_output(&expected, &actual),
+ Err(ReleaseArtifactError::StaleOutput)
+ );
+
+ let mut oversized_stdout = Command::new("sh");
+ oversized_stdout.args(["-c", "printf 12345"]);
+ assert_eq!(command_stdout(&mut oversized_stdout, 4), Err(()));
+ let mut failed_stdout = Command::new("sh");
+ failed_stdout.args(["-c", "exit 7"]);
+ assert_eq!(command_stdout(&mut failed_stdout, 4), Err(()));
+ assert_eq!(
+ git_status(root.path(), ["rev-parse", "--verify", "refs/heads/missing"]),
+ Err(())
+ );
+ }
+
+ #[test]
+ fn release_service_and_workspace_binding_fail_closed() {
+ let fixture = ReleaseFixture::new();
+ let current = ServiceSourceLockV1::from_canonical_bytes(
+ &fs::read(fixture.service.join(LOCK_FILENAME)).expect("source lock"),
+ )
+ .expect("source lock");
+ let versions = current.contract_versions();
+ let mismatched = ServiceSourceLockV1::new(ServiceSourceLockParts {
+ service: "other_service",
+ revision: current.revision(),
+ workspace_catalog_sha256: current.workspace_catalog_sha256(),
+ source_archive_sha256: current.source_archive_sha256(),
+ cargo_lock_sha256: current.cargo_lock_sha256(),
+ flake_lock_sha256: current.flake_lock_sha256(),
+ contract_versions: ContractVersions::new(
+ versions.config(),
+ versions.state(),
+ versions.admin(),
+ versions.status(),
+ versions.provider(),
+ ),
+ })
+ .expect("mismatched source lock");
+ write_file(
+ &fixture.service.join(LOCK_FILENAME),
+ mismatched.canonical_bytes(),
+ );
+ git(&fixture.service, &["add", LOCK_FILENAME]);
+ git(
+ &fixture.service,
+ &["commit", "--quiet", "-m", "mismatched service lock"],
+ );
+ assert_eq!(
+ fixture.check(&fixture.output_a),
+ Err(ReleaseArtifactError::InvalidSourceLock)
+ );
+
+ let mut cargo = sample_cargo_metadata();
+ let dependency_id = cargo.packages[1].id.clone();
+ cargo.packages[0].source =
+ Some("registry+https://github.com/rust-lang/crates.io-index".into());
+ cargo.packages[0].checksum = Some("a".repeat(64));
+ cargo.workspace_members = vec![dependency_id];
+ assert!(matches!(
+ build_supply_chain_documents(&sample_metadata(), cargo),
+ Err(ReleaseArtifactError::InvalidPackageInventory)
+ ));
+ }
+
+ #[test]
fn identifier_predicates_reject_each_independent_boundary() {
for value in ["", "1service", "service_", "service__name", "service-name"] {
assert!(!valid_snake_identifier(value), "{value}");
diff --git a/tools/xtask/src/service_source_lock_command.rs b/tools/xtask/src/service_source_lock_command.rs
@@ -1647,6 +1647,122 @@ name = "radroots_service_host"
}
#[test]
+ fn low_level_source_lock_admission_branches_are_qualified() {
+ let root = TempDir::new().expect("low-level source-lock fixture");
+ let regular = root.path().join("regular");
+ fs::write(®ular, b"same").expect("regular file");
+ assert_eq!(
+ read_bounded_regular(®ular, 4, CommandError::InvalidSourceLock)
+ .expect("bounded regular file"),
+ b"same"
+ );
+ assert_eq!(
+ validate_service_root(Path::new("relative")),
+ Err(CommandError::InvalidServiceRoot)
+ );
+ assert_eq!(
+ validate_service_root(®ular),
+ Err(CommandError::InvalidServiceRoot)
+ );
+
+ let directory = root.path().join("directory");
+ fs::create_dir(&directory).expect("directory fixture");
+ assert_eq!(
+ read_bounded_regular(&directory, 4, CommandError::InvalidSourceLock),
+ Err(CommandError::InvalidSourceLock)
+ );
+ let oversized = root.path().join("oversized");
+ fs::write(&oversized, b"12345").expect("oversized file");
+ assert_eq!(
+ read_bounded_regular(&oversized, 4, CommandError::InvalidSourceLock),
+ Err(CommandError::InvalidSourceLock)
+ );
+
+ #[cfg(unix)]
+ {
+ let symlink = root.path().join("regular-link");
+ std::os::unix::fs::symlink(®ular, &symlink).expect("regular symlink");
+ assert_eq!(
+ validate_service_root(&symlink),
+ Err(CommandError::InvalidServiceRoot)
+ );
+ assert_eq!(
+ read_bounded_regular(&symlink, 4, CommandError::InvalidSourceLock),
+ Err(CommandError::InvalidSourceLock)
+ );
+ }
+
+ let repository = root.path().join("repository");
+ fs::create_dir(&repository).expect("repository");
+ git(&repository, &["init", "--quiet"]);
+ let child = repository.join("child");
+ fs::create_dir(&child).expect("nested directory");
+ assert_eq!(
+ validate_service_root(&child),
+ Err(CommandError::InvalidServiceRoot)
+ );
+
+ let empty_catalog = br#"schema = "radroots.workspace.catalog.v2"
+architecture = "radroots.crates.release.v2"
+version = "0.1.0-alpha"
+package_count = 0
+package = []
+"#;
+ assert_eq!(
+ catalog_package_names(empty_catalog),
+ Err(CommandError::InvalidSourceArchive)
+ );
+
+ let dependency = toml::Value::String("=0.1.0-alpha".into());
+ let packages = BTreeSet::from([HOST_PACKAGE.to_owned()]);
+ assert_eq!(
+ validate_manifest_node(
+ &dependency,
+ Some(HOST_PACKAGE),
+ false,
+ true,
+ Some(&packages),
+ &mut ManifestState::default(),
+ ),
+ Err(CommandError::InvalidCargoManifest)
+ );
+
+ assert_eq!(
+ validate_flake_lock(
+ br#"{"nodes":{"root":{"inputs":{}}},"root":"root","version":7}"#,
+ &"a".repeat(40),
+ ),
+ Err(CommandError::InvalidFlakeLock)
+ );
+ assert_eq!(
+ validate_flake_lock(
+ br#"{"nodes":{"root":{"inputs":{"lib":"lib"}},"lib":{"original":{"owner":"radrootslabs","repo":"lib"}}},"root":"root","version":7}"#,
+ &"a".repeat(40),
+ ),
+ Err(CommandError::InvalidFlakeLock)
+ );
+
+ assert!(!valid_nix_sha256("not-a-digest"));
+ assert!(!valid_nix_sha256(
+ "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ ));
+ assert!(!valid_nix_sha256(
+ "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?="
+ ));
+
+ let mut oversized_stdout = Command::new("sh");
+ oversized_stdout.args(["-c", "printf 12345"]);
+ assert_eq!(command_stdout(&mut oversized_stdout, 4), Err(()));
+ let mut failed_stdout = Command::new("sh");
+ failed_stdout.args(["-c", "exit 7"]);
+ assert_eq!(command_stdout(&mut failed_stdout, 4), Err(()));
+ assert_eq!(
+ git_status(root.path(), ["rev-parse", "--verify", "refs/heads/missing"]),
+ Err(())
+ );
+ }
+
+ #[test]
fn operational_diagnostics_are_fixed_and_source_free() {
let errors = [
CommandError::InvalidServiceRoot,