rhi

Coordinated trade for connected markets
git clone https://radroots.dev/git/rhi.git
Log | Files | Refs | README | LICENSE

services_hardening_native_release.rs (15903B)


      1 #![forbid(unsafe_code)]
      2 
      3 use std::collections::BTreeSet;
      4 
      5 use serde_json::json;
      6 
      7 const CONTRACT: &str = include_str!("../contracts/services_hardening/native_release.v1.json");
      8 const ACTIVE_CONTRACT: &str =
      9     include_str!("../contracts/services_hardening/native_release.v2.json");
     10 const MANIFEST: &str = include_str!("../Cargo.toml");
     11 const LOCK: &str = include_str!("../Cargo.lock");
     12 const FLAKE: &str = include_str!("../flake.nix");
     13 const FLAKE_LOCK: &str = include_str!("../flake.lock");
     14 const SOURCE_LOCK: &str = include_str!("../radroots.service.source-lock.v3.toml");
     15 const CARGO_CONFIG: &str = include_str!("../.cargo/config.toml");
     16 const SYSTEMD_UNIT: &str = include_str!("../packaging/systemd/rhi@.service");
     17 const RELEASE_ACCEPTANCE: &str = include_str!("../scripts/release-acceptance.sh");
     18 const XTASK_MANIFEST: &str = include_str!("../tools/xtask/Cargo.toml");
     19 
     20 const LIB_REVISION: &str = "055096853fca95e15d0f813d33a14aca13be3881";
     21 const LIB_REPOSITORY: &str = "https://github.com/radrootslabs/lib";
     22 
     23 #[test]
     24 fn native_release_contract_and_manifest_metadata_are_exact() {
     25     let contract: serde_json::Value = serde_json::from_str(CONTRACT).expect("release contract");
     26     assert_eq!(
     27         contract,
     28         json!({
     29             "schema": "radroots.rhi.native-release",
     30             "schema_version": 1,
     31             "contract_version": 1,
     32             "service": "rhi",
     33             "package": {
     34                 "name": "rhi",
     35                 "binary": "rhi",
     36                 "version": "0.1.0",
     37                 "repository": "https://github.com/radrootslabs/rhi",
     38                 "publish_to_crates_io": false
     39             },
     40             "generator": {
     41                 "command": "cargo xtask native-release",
     42                 "modes": ["check", "write"],
     43                 "required_arguments": [
     44                     "mode", "target", "binary", "output", "source_date_epoch"
     45                 ],
     46                 "source_date_epoch_range": "1..=4294967295",
     47                 "clean_exact_head": true,
     48                 "target_binary_validation": "executable_elf64_little_endian_exact_machine",
     49                 "canonical_json": "compact_utf8_json_with_one_final_lf",
     50                 "deterministic_archives": true,
     51                 "output_directory_mode": "0755",
     52                 "output_file_mode": "0644",
     53                 "durability": "sync_files_then_output_directory_then_parent"
     54             },
     55             "toolchain": {
     56                 "rust_version": "1.97.1",
     57                 "edition": "2024",
     58                 "resolver": "3",
     59                 "host_feature_profile": "service-host"
     60             },
     61             "release_profile": {
     62                 "lto": "thin",
     63                 "codegen_units": 1,
     64                 "overflow_checks": true,
     65                 "strip": "symbols",
     66                 "panic": "unwind"
     67             },
     68             "source_lock": {
     69                 "filename": "radroots.service.source-lock.v2.toml",
     70                 "schema": "radroots.service.source-lock.v2",
     71                 "lib_repository": LIB_REPOSITORY,
     72                 "architecture": "radroots.crates.release.v2",
     73                 "nix_material": "absent"
     74             },
     75             "contract_versions": {
     76                 "config": 1,
     77                 "state": 11,
     78                 "admin": 1,
     79                 "status": 1,
     80                 "provider": 1
     81             },
     82             "native_targets": [
     83                 { "target": "aarch64-unknown-linux-gnu", "posture": "target" },
     84                 { "target": "x86_64-unknown-linux-gnu", "posture": "target" }
     85             ],
     86             "output_inventory": [
     87                 "LICENSE",
     88                 "SHA256SUMS",
     89                 "THIRD-PARTY-NOTICES.txt",
     90                 "artifact-manifest.v1.json",
     91                 "binary.tar.gz",
     92                 "config.example.toml",
     93                 "config.schema.json",
     94                 "provenance-input.v1.json",
     95                 "radroots.service.source-lock.v2.toml",
     96                 "sbom.cdx.json",
     97                 "service-source.tar.gz",
     98                 "systemd.service"
     99             ],
    100             "signing_inputs": [
    101                 "SHA256SUMS",
    102                 "artifact-manifest.v1.json",
    103                 "provenance-input.v1.json"
    104             ],
    105             "provenance_posture": "deterministic_unsigned_slsa_v1_input_external_keys_only",
    106             "sbom_format": "cyclonedx_json_1_5_locked_cargo_graph",
    107             "sbom_component_identity": "domain_separated_sha256_of_framed_name_version_source_checksum",
    108             "protected_material_scan": "tracked_source_binary_copied_and_generated_material_fixed_patterns",
    109             "source_archive": "locked_offline_cargo_build_with_vendored_dependencies",
    110             "checksum_format": "sha256_lower_hex_two_spaces_path_lf_sorted_by_path",
    111             "protected_material_included": false,
    112             "maximums": {
    113                 "text_input_bytes": 1048576,
    114                 "generated_document_bytes": 16777216,
    115                 "cargo_metadata_bytes": 33554432,
    116                 "binary_bytes": 536870912,
    117                 "source_archive_bytes": 1073741824,
    118                 "packages": 8192,
    119                 "tracked_files": 4096
    120             },
    121             "deferred_through_rcld_rshr_170": [
    122                 "nix_evaluation",
    123                 "nix_build",
    124                 "nixos_module_qualification",
    125                 "oci_artifact"
    126             ],
    127             "forbidden": [
    128                 "nix_input",
    129                 "nixos_module_output",
    130                 "oci_input",
    131                 "oci_output",
    132                 "protected_material",
    133                 "parent_owned_human_docs",
    134                 "private_harness",
    135                 "local_or_path_lib_dependency",
    136                 "floating_or_branch_lib_dependency",
    137                 "mixed_lib_revision",
    138                 "crates_io_publication",
    139                 "signing",
    140                 "tagging",
    141                 "release_publication",
    142                 "deployment"
    143             ]
    144         })
    145     );
    146 
    147     let manifest: toml::Value = toml::from_str(MANIFEST).expect("Cargo manifest");
    148     let package = manifest["package"].as_table().expect("package");
    149     assert_eq!(
    150         package["repository"].as_str(),
    151         Some("https://github.com/radrootslabs/rhi")
    152     );
    153     assert_eq!(package["readme"].as_str(), Some("README"));
    154     assert_eq!(package["publish"].as_bool(), Some(false));
    155     assert_eq!(
    156         manifest["workspace"]["members"],
    157         toml::Value::Array(vec![
    158             toml::Value::String(".".to_owned()),
    159             toml::Value::String("tools/xtask".to_owned())
    160         ])
    161     );
    162     assert_eq!(
    163         manifest["workspace"]["metadata"]["radroots"]["service_release"],
    164         toml::Value::Table(toml::toml! {
    165             service = "rhi"
    166             service_package = "rhi"
    167             binary_name = "rhi"
    168             version = "0.1.0"
    169         })
    170     );
    171     assert_eq!(
    172         manifest["workspace"]["metadata"]["radroots"]["service_source_lock"]["nix_material"]
    173             .as_str(),
    174         Some("qualified")
    175     );
    176     let source_lock: toml::Value = toml::from_str(SOURCE_LOCK).expect("source lock");
    177     assert_eq!(
    178         contract["contract_versions"]["state"].as_u64(),
    179         source_lock["contract_versions"]["state"]
    180             .as_integer()
    181             .and_then(|value| u64::try_from(value).ok())
    182     );
    183     assert_eq!(
    184         contract["contract_versions"]["state"].as_u64(),
    185         manifest["workspace"]["metadata"]["radroots"]["service_source_lock"]
    186             ["state_contract_version"]
    187             .as_integer()
    188             .and_then(|value| u64::try_from(value).ok())
    189     );
    190     assert_eq!(
    191         manifest["profile"]["release"],
    192         toml::Value::Table(toml::toml! {
    193             lto = "thin"
    194             codegen-units = 1
    195             overflow-checks = true
    196             strip = "symbols"
    197             panic = "unwind"
    198         })
    199     );
    200     assert_eq!(
    201         CARGO_CONFIG,
    202         "[alias]\nxtask = \"run --locked -p rhi_xtask --\"\n"
    203     );
    204     for required in [
    205         "ExecStart=/usr/bin/rhi --profile service-host --instance %i run",
    206         "ConfigurationDirectory=radroots/services/rhi/%i",
    207         "StateDirectory=radroots/services/rhi/%i",
    208         "CacheDirectory=radroots/services/rhi/%i",
    209         "LogsDirectory=radroots/services/rhi/%i",
    210         "RuntimeDirectory=radroots/services/rhi/%i",
    211         "UMask=0077",
    212         "NoNewPrivileges=yes",
    213         "ProtectSystem=strict",
    214         "CapabilityBoundingSet=",
    215     ] {
    216         assert!(SYSTEMD_UNIT.contains(required), "missing `{required}`");
    217     }
    218 }
    219 
    220 #[test]
    221 fn every_radroots_dependency_is_exactly_source_locked() {
    222     let manifest: toml::Value = toml::from_str(MANIFEST).expect("Cargo manifest");
    223     let dependencies = manifest["dependencies"].as_table().expect("dependencies");
    224     let radroots = dependencies
    225         .iter()
    226         .filter(|(name, _)| name.starts_with("radroots_"))
    227         .collect::<Vec<_>>();
    228     assert_eq!(radroots.len(), 12);
    229     for (name, dependency) in radroots {
    230         let dependency = dependency.as_table().expect("detailed dependency");
    231         assert_eq!(
    232             dependency.get("git").and_then(toml::Value::as_str),
    233             Some(LIB_REPOSITORY),
    234             "{name}"
    235         );
    236         assert_eq!(
    237             dependency.get("rev").and_then(toml::Value::as_str),
    238             Some(LIB_REVISION),
    239             "{name}"
    240         );
    241         assert_eq!(
    242             dependency.get("version").and_then(toml::Value::as_str),
    243             Some("=0.1.0-alpha"),
    244             "{name}"
    245         );
    246         for forbidden in ["path", "branch", "tag"] {
    247             assert!(
    248                 !dependency.contains_key(forbidden),
    249                 "{name} contains `{forbidden}`"
    250             );
    251         }
    252     }
    253     assert!(!MANIFEST.contains("[patch."));
    254 
    255     let sources = LOCK
    256         .lines()
    257         .filter_map(|line| line.strip_prefix("source = \"git+"))
    258         .filter_map(|line| line.strip_suffix('"'))
    259         .filter(|source| source.contains("radrootslabs/lib"))
    260         .collect::<BTreeSet<_>>();
    261     assert_eq!(sources.len(), 1);
    262     let source = sources.into_iter().next().expect("Lib source");
    263     assert!(source.contains(&format!("?rev={LIB_REVISION}#{LIB_REVISION}")));
    264 
    265     for required in [
    266         "url = \"github:radrootslabs/lib/055096853fca95e15d0f813d33a14aca13be3881\";",
    267         "systems = lib.lib.supportedSystems;",
    268         "nixosModules.default",
    269     ] {
    270         assert!(
    271             FLAKE.contains(required),
    272             "flake source is missing `{required}`"
    273         );
    274     }
    275     let flake_lock: serde_json::Value =
    276         serde_json::from_str(FLAKE_LOCK).expect("flake source lock");
    277     assert_eq!(flake_lock["version"], 7);
    278     assert_eq!(flake_lock["root"], "root");
    279     assert_eq!(flake_lock["nodes"]["root"]["inputs"]["lib"], "lib");
    280     assert_eq!(flake_lock["nodes"]["lib"]["locked"]["rev"], LIB_REVISION);
    281     assert_eq!(flake_lock["nodes"]["lib"]["original"]["rev"], LIB_REVISION);
    282 }
    283 
    284 #[test]
    285 fn native_release_surfaces_remain_external_and_nix_qualified() {
    286     let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
    287     for required in [
    288         ".cargo/config.toml",
    289         "packaging/systemd/rhi@.service",
    290         "radroots.service.source-lock.v3.toml",
    291         "scripts/release-acceptance.sh",
    292         "tools/xtask/Cargo.toml",
    293         "tools/xtask/src/main.rs",
    294         "contracts/services_hardening/native_release.v1.json",
    295         "contracts/services_hardening/native_release.v2.json",
    296         "contracts/release/rhi-artifact-contract.v3.json",
    297         "flake.nix",
    298         "flake.lock",
    299     ] {
    300         assert!(root.join(required).is_file(), "missing `{required}`");
    301     }
    302     assert!(!root.join("radroots.service.source-lock.v2.toml").exists());
    303     for forbidden in [
    304         ".github",
    305         ".act",
    306         "target",
    307         "result",
    308         "artifacts",
    309         "dist",
    310         "sbom.cdx.json",
    311         "provenance-input.v1.json",
    312         "oci-image.tar.gz",
    313     ] {
    314         assert!(
    315             !root.join(forbidden).exists(),
    316             "forbidden generated or deferred surface `{forbidden}` exists"
    317         );
    318     }
    319     assert!(!CONTRACT.contains("qualified"));
    320     assert!(!CONTRACT.contains("production_ready"));
    321     assert!(!CONTRACT.contains("oci-image"));
    322     assert!(!CONTRACT.contains("nixos-module"));
    323     let active: serde_json::Value =
    324         serde_json::from_str(ACTIVE_CONTRACT).expect("active release contract");
    325     assert_eq!(active["schema_version"], 2);
    326     assert_eq!(active["contract_version"], 2);
    327     assert_eq!(active["predecessor"]["filename"], "native_release.v1.json");
    328     assert_eq!(
    329         active["source_lock"]["filename"],
    330         "radroots.service.source-lock.v3.toml"
    331     );
    332     assert_eq!(active["source_lock"]["nix_material"], "qualified");
    333     assert_eq!(active["nix_outputs"]["bundled_sqlite"], true);
    334     assert_eq!(active["nix_outputs"]["native_linkage_count"], 1);
    335 }
    336 
    337 #[test]
    338 fn release_acceptance_is_standalone_and_has_no_deferred_toolchain() {
    339     for required in [
    340         "cargo fmt --all --check",
    341         "cargo metadata --locked --format-version 1 --no-deps",
    342         "cargo check --locked --all-targets --no-default-features",
    343         "cargo check --locked --all-targets --no-default-features --features service-host",
    344         "cargo clippy --locked --all-targets -- -D warnings",
    345         "cargo test --locked",
    346         "cargo test --locked -p rhi_xtask",
    347         "git diff --check",
    348     ] {
    349         assert!(
    350             RELEASE_ACCEPTANCE.contains(required),
    351             "release acceptance is missing `{required}`"
    352         );
    353     }
    354     for forbidden in [
    355         "nix ",
    356         "nix-",
    357         "docker ",
    358         "podman ",
    359         "cosign ",
    360         "gh release",
    361     ] {
    362         assert!(
    363             !RELEASE_ACCEPTANCE.contains(forbidden),
    364             "release acceptance contains deferred or unauthorized command `{forbidden}`"
    365         );
    366     }
    367 }
    368 
    369 #[test]
    370 fn release_tool_dependency_and_file_mode_boundaries_are_exact() {
    371     let manifest: toml::Value = toml::from_str(XTASK_MANIFEST).expect("xtask manifest");
    372     assert_eq!(manifest["package"]["name"].as_str(), Some("rhi_xtask"));
    373     assert_eq!(manifest["package"]["publish"].as_bool(), Some(false));
    374     let dependencies = manifest["dependencies"]
    375         .as_table()
    376         .expect("xtask dependencies")
    377         .keys()
    378         .map(String::as_str)
    379         .collect::<BTreeSet<_>>();
    380     assert_eq!(
    381         dependencies,
    382         BTreeSet::from([
    383             "flate2",
    384             "hex",
    385             "serde",
    386             "serde_json",
    387             "sha2",
    388             "tar",
    389             "tempfile",
    390             "toml",
    391         ])
    392     );
    393     assert_eq!(
    394         manifest["target"]["cfg(unix)"]["dependencies"]
    395             .as_table()
    396             .expect("Unix dependencies")
    397             .keys()
    398             .map(String::as_str)
    399             .collect::<BTreeSet<_>>(),
    400         BTreeSet::from(["rustix"])
    401     );
    402     for forbidden in [
    403         "sqlx", "rusqlite", "reqwest", "tokio", "\nnix =", "nix::", "oci", "cosign", "path =",
    404         "git =",
    405     ] {
    406         assert!(
    407             !XTASK_MANIFEST.contains(forbidden),
    408             "release tool contains unauthorized dependency or authority `{forbidden}`"
    409         );
    410     }
    411 
    412     #[cfg(unix)]
    413     {
    414         use std::os::unix::fs::PermissionsExt as _;
    415 
    416         let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
    417         assert_eq!(
    418             std::fs::metadata(root.join("scripts/release-acceptance.sh"))
    419                 .expect("release script metadata")
    420                 .permissions()
    421                 .mode()
    422                 & 0o777,
    423             0o755
    424         );
    425         assert_eq!(
    426             std::fs::metadata(root.join("packaging/systemd/rhi@.service"))
    427                 .expect("systemd unit metadata")
    428                 .permissions()
    429                 .mode()
    430                 & 0o777,
    431             0o644
    432         );
    433     }
    434 }