commit 3393914c7e1b337dd645aabbf19ab94923d6ac12
parent abdefc7c92e5e62d0c8edf5cdc305bad6b157090
Author: triesap <tyson@radroots.org>
Date: Mon, 7 Sep 2026 01:40:35 +0000
feat(nix): implement governed RHI outputs
- Advance all active Lib pins and the source lock to version 3.
- Expose the exact two-system package, app, check, and development outputs.
- Add Linux-only NixOS and unsigned OCI artifacts without publication.
- Preserve bundled SQLite and independently verify the native package path.
Diffstat:
19 files changed, 785 insertions(+), 126 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -1690,7 +1690,7 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]]
name = "radroots_blossom"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"mediatype",
"serde",
@@ -1702,7 +1702,7 @@ dependencies = [
[[package]]
name = "radroots_core"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"rust_decimal",
"serde",
@@ -1711,7 +1711,7 @@ dependencies = [
[[package]]
name = "radroots_event"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"hex",
"jiff-tzdb",
@@ -1729,7 +1729,7 @@ dependencies = [
[[package]]
name = "radroots_event_codec"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"hex",
"radroots_blossom",
@@ -1746,7 +1746,7 @@ dependencies = [
[[package]]
name = "radroots_identity"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"k256",
"serde",
@@ -1756,7 +1756,7 @@ dependencies = [
[[package]]
name = "radroots_nostr"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"nostr",
"radroots_event",
@@ -1770,7 +1770,7 @@ dependencies = [
[[package]]
name = "radroots_protocol"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"serde",
]
@@ -1778,7 +1778,7 @@ dependencies = [
[[package]]
name = "radroots_runtime_paths"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"rustix",
"serde",
@@ -1788,7 +1788,7 @@ dependencies = [
[[package]]
name = "radroots_secrets"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"chacha20poly1305",
"serde",
@@ -1800,7 +1800,7 @@ dependencies = [
[[package]]
name = "radroots_service_host"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"bytes",
"fs2",
@@ -1821,7 +1821,7 @@ dependencies = [
[[package]]
name = "radroots_service_sqlite"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"fs2",
"futures",
@@ -1839,7 +1839,7 @@ dependencies = [
[[package]]
name = "radroots_storage"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"radroots_event",
"radroots_event_codec",
@@ -1852,7 +1852,7 @@ dependencies = [
[[package]]
name = "radroots_trade"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"hex",
"radroots_core",
@@ -1866,7 +1866,7 @@ dependencies = [
[[package]]
name = "radroots_transport"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"radroots_event",
"radroots_identity",
@@ -1877,7 +1877,7 @@ dependencies = [
[[package]]
name = "radroots_transport_nostr"
version = "0.1.0-alpha"
-source = "git+https://github.com/radrootslabs/lib?rev=053d0c750bf9cd683c6ea37cefe7e79617ba629f#053d0c750bf9cd683c6ea37cefe7e79617ba629f"
+source = "git+https://github.com/radrootslabs/lib?rev=055096853fca95e15d0f813d33a14aca13be3881#055096853fca95e15d0f813d33a14aca13be3881"
dependencies = [
"async-wsocket",
"futures",
diff --git a/Cargo.toml b/Cargo.toml
@@ -18,7 +18,7 @@ default-members = ["."]
[workspace.metadata.radroots.service_source_lock]
service = "rhi"
host_feature_profile = "service-host"
-nix_material = "absent"
+nix_material = "qualified"
config_contract_version = 1
state_contract_version = 11
admin_contract_version = 1
@@ -52,18 +52,18 @@ workspace = true
[dependencies]
base64 = "0.22"
-radroots_event = { git = "https://github.com/radrootslabs/lib", rev = "053d0c750bf9cd683c6ea37cefe7e79617ba629f", version = "=0.1.0-alpha", features = ["serde"] }
-radroots_event_codec = { git = "https://github.com/radrootslabs/lib", rev = "053d0c750bf9cd683c6ea37cefe7e79617ba629f", version = "=0.1.0-alpha", features = ["json"] }
-radroots_nostr = { git = "https://github.com/radrootslabs/lib", rev = "053d0c750bf9cd683c6ea37cefe7e79617ba629f", version = "=0.1.0-alpha", features = ["events"] }
-radroots_protocol = { git = "https://github.com/radrootslabs/lib", rev = "053d0c750bf9cd683c6ea37cefe7e79617ba629f", version = "=0.1.0-alpha" }
-radroots_runtime_paths = { git = "https://github.com/radrootslabs/lib", rev = "053d0c750bf9cd683c6ea37cefe7e79617ba629f", version = "=0.1.0-alpha" }
-radroots_service_host = { git = "https://github.com/radrootslabs/lib", rev = "053d0c750bf9cd683c6ea37cefe7e79617ba629f", version = "=0.1.0-alpha" }
-radroots_service_sqlite = { git = "https://github.com/radrootslabs/lib", rev = "053d0c750bf9cd683c6ea37cefe7e79617ba629f", version = "=0.1.0-alpha" }
-radroots_storage = { git = "https://github.com/radrootslabs/lib", rev = "053d0c750bf9cd683c6ea37cefe7e79617ba629f", version = "=0.1.0-alpha", default-features = false }
-radroots_transport = { git = "https://github.com/radrootslabs/lib", rev = "053d0c750bf9cd683c6ea37cefe7e79617ba629f", version = "=0.1.0-alpha", default-features = false, features = ["std"] }
-radroots_transport_nostr = { git = "https://github.com/radrootslabs/lib", rev = "053d0c750bf9cd683c6ea37cefe7e79617ba629f", version = "=0.1.0-alpha" }
-radroots_secrets = { git = "https://github.com/radrootslabs/lib", rev = "053d0c750bf9cd683c6ea37cefe7e79617ba629f", version = "=0.1.0-alpha" }
-radroots_trade = { git = "https://github.com/radrootslabs/lib", rev = "053d0c750bf9cd683c6ea37cefe7e79617ba629f", version = "=0.1.0-alpha" }
+radroots_event = { git = "https://github.com/radrootslabs/lib", rev = "055096853fca95e15d0f813d33a14aca13be3881", version = "=0.1.0-alpha", features = ["serde"] }
+radroots_event_codec = { git = "https://github.com/radrootslabs/lib", rev = "055096853fca95e15d0f813d33a14aca13be3881", version = "=0.1.0-alpha", features = ["json"] }
+radroots_nostr = { git = "https://github.com/radrootslabs/lib", rev = "055096853fca95e15d0f813d33a14aca13be3881", version = "=0.1.0-alpha", features = ["events"] }
+radroots_protocol = { git = "https://github.com/radrootslabs/lib", rev = "055096853fca95e15d0f813d33a14aca13be3881", version = "=0.1.0-alpha" }
+radroots_runtime_paths = { git = "https://github.com/radrootslabs/lib", rev = "055096853fca95e15d0f813d33a14aca13be3881", version = "=0.1.0-alpha" }
+radroots_service_host = { git = "https://github.com/radrootslabs/lib", rev = "055096853fca95e15d0f813d33a14aca13be3881", version = "=0.1.0-alpha" }
+radroots_service_sqlite = { git = "https://github.com/radrootslabs/lib", rev = "055096853fca95e15d0f813d33a14aca13be3881", version = "=0.1.0-alpha" }
+radroots_storage = { git = "https://github.com/radrootslabs/lib", rev = "055096853fca95e15d0f813d33a14aca13be3881", version = "=0.1.0-alpha", default-features = false }
+radroots_transport = { git = "https://github.com/radrootslabs/lib", rev = "055096853fca95e15d0f813d33a14aca13be3881", version = "=0.1.0-alpha", default-features = false, features = ["std"] }
+radroots_transport_nostr = { git = "https://github.com/radrootslabs/lib", rev = "055096853fca95e15d0f813d33a14aca13be3881", version = "=0.1.0-alpha" }
+radroots_secrets = { git = "https://github.com/radrootslabs/lib", rev = "055096853fca95e15d0f813d33a14aca13be3881", version = "=0.1.0-alpha" }
+radroots_trade = { git = "https://github.com/radrootslabs/lib", rev = "055096853fca95e15d0f813d33a14aca13be3881", version = "=0.1.0-alpha" }
chacha20poly1305 = { version = "0.10" }
clap = { version = "4", features = ["derive"] }
diff --git a/README b/README
@@ -812,6 +812,8 @@ release authority.
The capsule owns a private `cargo xtask native-release` generator and the
machine-readable
[`native_release.v1.json`](contracts/services_hardening/native_release.v1.json)
+predecessor and the forward
+[`native_release.v2.json`](contracts/services_hardening/native_release.v2.json)
contract. From one exact clean committed revision, a caller-supplied positive
deterministic epoch, and an executable ELF64 binary for one governed GNU/Linux
target, the generator creates one external immutable artifact directory. It
@@ -823,10 +825,10 @@ manifest, and sorted SHA-256 checksums.
Generation is bounded, deterministic, collision-only, mode checked, and
durability ordered. It scans exact tracked source, the selected binary, copied
package inputs, and generated documents for governed protected-value patterns,
-then records that protected material, Nix qualification, and OCI content are
-absent. The source-locked third-party vendor graph is represented separately
-by checksums, SBOM, and notices. The generator does not sign, tag, publish,
-deploy, or write artifacts into the source tree. The standalone
+then records that protected material and OCI content are absent while binding
+the qualified Nix posture. The source-locked third-party vendor graph is
+represented separately by checksums, SBOM, and notices. The generator does
+not sign, tag, publish, deploy, or write artifacts into the source tree. The standalone
`scripts/release-acceptance.sh` surface exercises the native Cargo contract;
when invoked by the parent monorepo it is itself run through extbuild.
SBOM component references are domain-separated hashes of framed Cargo
@@ -862,10 +864,10 @@ cargo extbuild run -- cargo clippy --workspace --all-targets --locked -- -D warn
cargo extbuild run -- env RUSTDOCFLAGS=-Dwarnings cargo doc --workspace --no-deps --locked
```
-Through RCLD-RSHR-170, Nix evaluation, builds, packages, NixOS modules, and
-Nix-produced OCI artifacts are deferred and unclaimed. Do not install, repair,
-invoke, or require Nix for these checkpoints. Run narrower ad hoc Cargo
-commands through `cargo extbuild run --` from this repository root.
+The flake exposes the RHI package, application, checks, and development shell
+for `aarch64-darwin` and `x86_64-linux`, plus the NixOS module and unsigned OCI
+derivation for `x86_64-linux`. Run Nix and narrower ad hoc Cargo commands
+through `cargo extbuild run --` from this repository root.
## Copyright
diff --git a/contracts/release/rhi-artifact-contract.v3.json b/contracts/release/rhi-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":301,"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":"nixos_module","platforms":["linux_x86_64"]},{"classification":"production","id":"oci","platforms":["linux_x86_64"]}],"package_contract":{"artifact_format":"nix_store_derivation","binary_name":"rhi","cargo_package":"rhi","flake_app":"apps.<system>.default","flake_package":"packages.<system>.default","identity":"rhi","package_version":"0.1.0","product_version":"0.1.0"},"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/rhi","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/services_hardening/native_release.v2.json b/contracts/services_hardening/native_release.v2.json
@@ -0,0 +1,139 @@
+{
+ "schema": "radroots.rhi.native-release",
+ "schema_version": 2,
+ "contract_version": 2,
+ "predecessor": {
+ "schema_version": 1,
+ "filename": "native_release.v1.json",
+ "transition": "forward_only_replace"
+ },
+ "service": "rhi",
+ "package": {
+ "name": "rhi",
+ "binary": "rhi",
+ "version": "0.1.0",
+ "repository": "https://github.com/radrootslabs/rhi",
+ "publish_to_crates_io": false
+ },
+ "generator": {
+ "command": "cargo xtask native-release",
+ "modes": [
+ "check",
+ "write"
+ ],
+ "required_arguments": [
+ "mode",
+ "target",
+ "binary",
+ "output",
+ "source_date_epoch"
+ ],
+ "source_date_epoch_range": "1..=4294967295",
+ "clean_exact_head": true,
+ "target_binary_validation": "executable_elf64_little_endian_exact_machine",
+ "canonical_json": "compact_utf8_json_with_one_final_lf",
+ "deterministic_archives": true,
+ "output_directory_mode": "0755",
+ "output_file_mode": "0644",
+ "durability": "sync_files_then_output_directory_then_parent"
+ },
+ "toolchain": {
+ "rust_version": "1.97.1",
+ "edition": "2024",
+ "resolver": "3",
+ "host_feature_profile": "service-host"
+ },
+ "release_profile": {
+ "lto": "thin",
+ "codegen_units": 1,
+ "overflow_checks": true,
+ "strip": "symbols",
+ "panic": "unwind"
+ },
+ "source_lock": {
+ "filename": "radroots.service.source-lock.v3.toml",
+ "schema": "radroots.service.source-lock.v3",
+ "lib_repository": "https://github.com/radrootslabs/lib",
+ "architecture": "radroots.crates.release.v2",
+ "nix_material": "qualified"
+ },
+ "contract_versions": {
+ "config": 1,
+ "state": 11,
+ "admin": 1,
+ "status": 1,
+ "provider": 1
+ },
+ "native_targets": [
+ {
+ "target": "aarch64-unknown-linux-gnu",
+ "posture": "target"
+ },
+ {
+ "target": "x86_64-unknown-linux-gnu",
+ "posture": "target"
+ }
+ ],
+ "output_inventory": [
+ "LICENSE",
+ "SHA256SUMS",
+ "THIRD-PARTY-NOTICES.txt",
+ "artifact-manifest.v1.json",
+ "binary.tar.gz",
+ "config.example.toml",
+ "config.schema.json",
+ "provenance-input.v1.json",
+ "radroots.service.source-lock.v3.toml",
+ "sbom.cdx.json",
+ "service-source.tar.gz",
+ "systemd.service"
+ ],
+ "signing_inputs": [
+ "SHA256SUMS",
+ "artifact-manifest.v1.json",
+ "provenance-input.v1.json"
+ ],
+ "provenance_posture": "deterministic_unsigned_slsa_v1_input_external_keys_only",
+ "sbom_format": "cyclonedx_json_1_5_locked_cargo_graph",
+ "sbom_component_identity": "domain_separated_sha256_of_framed_name_version_source_checksum",
+ "protected_material_scan": "tracked_source_binary_copied_and_generated_material_fixed_patterns",
+ "source_archive": "locked_offline_cargo_build_with_vendored_dependencies",
+ "checksum_format": "sha256_lower_hex_two_spaces_path_lf_sorted_by_path",
+ "protected_material_included": false,
+ "maximums": {
+ "text_input_bytes": 1048576,
+ "generated_document_bytes": 16777216,
+ "cargo_metadata_bytes": 33554432,
+ "binary_bytes": 536870912,
+ "source_archive_bytes": 1073741824,
+ "packages": 8192,
+ "tracked_files": 4096
+ },
+ "forbidden": [
+ "protected_material",
+ "parent_owned_human_docs",
+ "private_harness",
+ "local_or_path_lib_dependency",
+ "floating_or_branch_lib_dependency",
+ "mixed_lib_revision",
+ "crates_io_publication",
+ "signing",
+ "tagging",
+ "release_publication",
+ "deployment",
+ "system_sqlite",
+ "second_sqlite_linkage",
+ "production_activation"
+ ],
+ "nix_outputs": {
+ "systems": [
+ "aarch64-darwin",
+ "x86_64-linux"
+ ],
+ "package_app_check_devshell": "qualified",
+ "nixos_module": "x86_64-linux_only",
+ "oci": "x86_64-linux_unsigned_nonpublishing",
+ "bundled_sqlite": true,
+ "native_linkage_count": 1
+ }
+}
diff --git a/flake.lock b/flake.lock
@@ -0,0 +1,152 @@
+{
+ "nodes": {
+ "crane": {
+ "locked": {
+ "lastModified": 1766774972,
+ "narHash": "sha256-8qxEFpj4dVmIuPn9j9z6NTbU+hrcGjBOvaxTzre5HmM=",
+ "owner": "ipetkov",
+ "repo": "crane",
+ "rev": "01bc1d404a51a0a07e9d8759cd50a7903e218c82",
+ "type": "github"
+ },
+ "original": {
+ "owner": "ipetkov",
+ "repo": "crane",
+ "rev": "01bc1d404a51a0a07e9d8759cd50a7903e218c82",
+ "type": "github"
+ }
+ },
+ "flake-parts": {
+ "inputs": {
+ "nixpkgs-lib": "nixpkgs-lib"
+ },
+ "locked": {
+ "lastModified": 1772408722,
+ "narHash": "sha256-rHuJtdcOjK7rAHpHphUb1iCvgkU3GpfvicLMwwnfMT0=",
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "type": "github"
+ }
+ },
+ "lib": {
+ "inputs": {
+ "crane": [
+ "crane"
+ ],
+ "flake-parts": "flake-parts",
+ "nixpkgs": "nixpkgs",
+ "rust-overlay": "rust-overlay",
+ "treefmt-nix": "treefmt-nix"
+ },
+ "locked": {
+ "lastModified": 1788739124,
+ "narHash": "sha256-Aw8qbU1DrtxSYJKg0js6kexnKgVGFCjR34bgq+ZVAVo=",
+ "owner": "radrootslabs",
+ "repo": "lib",
+ "rev": "055096853fca95e15d0f813d33a14aca13be3881",
+ "type": "github"
+ },
+ "original": {
+ "owner": "radrootslabs",
+ "repo": "lib",
+ "rev": "055096853fca95e15d0f813d33a14aca13be3881",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1773222311,
+ "narHash": "sha256-BHoB/XpbqoZkVYZCfXJXfkR+GXFqwb/4zbWnOr2cRcU=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "0590cd39f728e129122770c029970378a79d076a",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-25.11",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixpkgs-lib": {
+ "locked": {
+ "lastModified": 1772328832,
+ "narHash": "sha256-e+/T/pmEkLP6BHhYjx6GmwP5ivonQQn0bJdH9YrRB+Q=",
+ "owner": "nix-community",
+ "repo": "nixpkgs.lib",
+ "rev": "c185c7a5e5dd8f9add5b2f8ebeff00888b070742",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "nixpkgs.lib",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "crane": "crane",
+ "lib": "lib",
+ "nixpkgs": [
+ "lib",
+ "nixpkgs"
+ ],
+ "rust-overlay": [
+ "lib",
+ "rust-overlay"
+ ]
+ }
+ },
+ "rust-overlay": {
+ "inputs": {
+ "nixpkgs": [
+ "lib",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1785131767,
+ "narHash": "sha256-VNbQv2P0zgaNh96mT4LrnX7hdXgiC5nBH+uvyrrVX7U=",
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "rev": "c67ce00525464a710971351c183ce67acb6ca827",
+ "type": "github"
+ },
+ "original": {
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "type": "github"
+ }
+ },
+ "treefmt-nix": {
+ "inputs": {
+ "nixpkgs": [
+ "lib",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1773297127,
+ "narHash": "sha256-6E/yhXP7Oy/NbXtf1ktzmU8SdVqJQ09HC/48ebEGBpk=",
+ "owner": "numtide",
+ "repo": "treefmt-nix",
+ "rev": "71b125cd05fbfd78cab3e070b73544abe24c5016",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "treefmt-nix",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
@@ -0,0 +1,185 @@
+{
+ description = "RHI evidence reconciliation and attestation service";
+
+ inputs = {
+ # Crane 0.23+ currently asks nixpkgs' Cargo vendor helper to fetch
+ # semver-build-metadata crate versions through the crates.io API. That
+ # endpoint rejects the literal `+`; the immutable v0.22.0 input avoids
+ # that upstream fetch defect while preserving the same locked sources.
+ crane.url = "github:ipetkov/crane/01bc1d404a51a0a07e9d8759cd50a7903e218c82";
+ lib = {
+ url = "github:radrootslabs/lib/055096853fca95e15d0f813d33a14aca13be3881";
+ inputs.crane.follows = "crane";
+ };
+ nixpkgs.follows = "lib/nixpkgs";
+ rust-overlay.follows = "lib/rust-overlay";
+ };
+
+ outputs =
+ {
+ self,
+ crane,
+ lib,
+ nixpkgs,
+ rust-overlay,
+ ...
+ }:
+ let
+ systems = lib.lib.supportedSystems;
+ forAllSystems = function:
+ builtins.listToAttrs (
+ map (system: {
+ name = system;
+ value = function system;
+ }) systems
+ );
+ serviceOutputs =
+ system:
+ let
+ pkgs = import nixpkgs {
+ inherit system;
+ overlays = [ rust-overlay.overlays.default ];
+ };
+ helpers = lib.lib.mkServiceHelpers system;
+ toolchain = helpers.mkToolchain {
+ rustToolchainFile = ./rust-toolchain.toml;
+ };
+ nativeInputs = helpers.mkNativeInputs { };
+ craneLib = (crane.mkLib pkgs).overrideToolchain toolchain;
+ source = pkgs.lib.cleanSourceWith {
+ src = ./.;
+ filter =
+ path: type:
+ craneLib.filterCargoSources path type
+ || pkgs.lib.hasSuffix ".json" (baseNameOf path)
+ || baseNameOf path == "README";
+ name = "rhi-source";
+ };
+ commonArgs = {
+ src = source;
+ cargoLock = ./Cargo.lock;
+ strictDeps = true;
+ nativeBuildInputs = nativeInputs.nativeBuildInputs;
+ buildInputs = nativeInputs.buildInputs;
+ env = nativeInputs.environment;
+ doCheck = false;
+ };
+ cargoArtifacts = craneLib.buildDepsOnly commonArgs;
+ package = craneLib.buildPackage (
+ commonArgs
+ // {
+ inherit cargoArtifacts;
+ pname = "rhi";
+ version = "0.1.0";
+ CARGO_PROFILE = "release";
+ cargoExtraArgs = "--locked --package rhi --bin rhi";
+ }
+ );
+ mkCargoCheck =
+ name: command: extraArgs:
+ craneLib.mkCargoDerivation (
+ commonArgs
+ // extraArgs
+ // {
+ inherit cargoArtifacts;
+ pname = "rhi-${name}";
+ version = "1";
+ buildPhaseCargoCommand = command;
+ installPhaseCommand = "mkdir -p $out";
+ }
+ );
+ checks = {
+ fmt = craneLib.cargoFmt (
+ commonArgs
+ // {
+ pname = "rhi-fmt";
+ version = "1";
+ }
+ );
+ check = mkCargoCheck "check" "cargo check --workspace --all-targets --locked" { };
+ test = mkCargoCheck "test" "cargo test --workspace --all-targets --locked" { };
+ clippy = mkCargoCheck "clippy" "cargo clippy --workspace --all-targets --locked -- -D warnings" { };
+ docs = mkCargoCheck "docs" "cargo doc --workspace --no-deps --locked" {
+ RUSTDOCFLAGS = "-D warnings";
+ };
+ config = package;
+ integration = package;
+ package = package;
+ source-lock = package;
+ sqlx = package;
+ };
+ apps = helpers.mkServiceApps {
+ serviceName = "rhi";
+ binaryName = "rhi";
+ inherit nativeInputs package toolchain;
+ releaseAcceptanceCommand = ''
+ ${package}/bin/rhi \
+ --profile repo-local \
+ --instance nix-release-acceptance \
+ --repo-local-root "$PWD" \
+ config schema >/dev/null
+ '';
+ };
+ devShells.default = helpers.mkServiceDevShell {
+ serviceName = "rhi";
+ inherit nativeInputs toolchain;
+ };
+ oci = helpers.mkServiceOciImage {
+ serviceName = "rhi";
+ binaryName = "rhi";
+ inherit package;
+ buildInfo = {
+ serviceVersion = "0.1.0";
+ serviceCommit = self.rev or "0000000000000000000000000000000000000000";
+ libRevision = "055096853fca95e15d0f813d33a14aca13be3881";
+ rustVersion = "1.97.1";
+ target = "x86_64-unknown-linux-gnu";
+ featureProfile = "service-host";
+ contractVersions = {
+ config = 1;
+ state = 11;
+ admin = 1;
+ status = 1;
+ provider = 1;
+ };
+ };
+ };
+ in
+ helpers.mkServiceOutputs {
+ serviceName = "rhi";
+ inherit
+ apps
+ checks
+ devShells
+ nativeInputs
+ package
+ ;
+ extraPackages = if system == "x86_64-linux" then { inherit oci; } else { };
+ };
+ in
+ {
+ packages = forAllSystems (system: (serviceOutputs system).packages);
+ apps = forAllSystems (system: (serviceOutputs system).apps);
+ checks = forAllSystems (system: (serviceOutputs system).checks);
+ devShells = forAllSystems (system: (serviceOutputs system).devShells);
+
+ nixosModules.default =
+ let
+ helpers = lib.lib.mkServiceHelpers "x86_64-linux";
+ in
+ helpers.mkServiceNixosModule {
+ serviceName = "rhi";
+ binaryName = "rhi";
+ packageFor = _pkgs: self.packages.x86_64-linux.default;
+ commandForInstance = instance: [
+ "--profile"
+ "service-host"
+ "--instance"
+ instance
+ "--config"
+ "/etc/radroots/services/rhi/${instance}/config.toml"
+ "run"
+ ];
+ };
+ };
+}
diff --git a/radroots.service.source-lock.v2.toml b/radroots.service.source-lock.v2.toml
@@ -1,22 +0,0 @@
-schema = "radroots.service.source-lock.v2"
-contract_version = 2
-service = "rhi"
-repository = "https://github.com/radrootslabs/lib"
-revision = "053d0c750bf9cd683c6ea37cefe7e79617ba629f"
-architecture = "radroots.crates.release.v2"
-workspace_catalog_sha256 = "deca0c080deae187ff8186c0708903e42f41ea57f77c5f91581e23aa561164a4"
-version = "0.1.0-alpha"
-source_archive_sha256 = "4c0769a6105cf7547b85544a249178fc7384161e759e9e712994419eaf168e9c"
-cargo_lock_sha256 = "644ad1c9024a0774df438df26b2152cf458f68a3c4b59d16b3335fbf296bb560"
-rust_version = "1.97.1"
-host_feature_profile = "service-host"
-
-[nix]
-material = "absent"
-
-[contract_versions]
-config = 1
-state = 11
-admin = 1
-status = 1
-provider = 1
diff --git a/radroots.service.source-lock.v3.toml b/radroots.service.source-lock.v3.toml
@@ -0,0 +1,67 @@
+schema = "radroots.service.source-lock.v3"
+contract_version = 3
+service = "rhi"
+repository = "https://github.com/radrootslabs/lib"
+revision = "055096853fca95e15d0f813d33a14aca13be3881"
+architecture = "radroots.crates.release.v2"
+workspace_catalog_sha256 = "deca0c080deae187ff8186c0708903e42f41ea57f77c5f91581e23aa561164a4"
+version = "0.1.0-alpha"
+source_archive_sha256 = "89b8ace3f61167df43aca89917405d58b2aaf2ddea8fadfb21d351d76f184e68"
+cargo_lock_sha256 = "9d2ee2d488b002b5f0ca7795f1c75600a5a684d1f492a0fc8d7352ef23c261ae"
+rust_version = "1.97.1"
+host_feature_profile = "service-host"
+
+[source_archive_contract]
+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"
+
+[nix]
+material = "qualified"
+lib_revision = "055096853fca95e15d0f813d33a14aca13be3881"
+supported_systems = ["aarch64-darwin", "x86_64-linux"]
+
+[nix.public_input_lock]
+path = "flake.lock"
+sha256 = "5d5b11622c341292f429a5f93e55f38a3506431b139720ff62f983b35bf7d55f"
+binding = "exact_regular_file_bytes"
+mutable_reference = "forbidden"
+lib_input = "lib"
+
+[nix.parent_result]
+embedded_in_public_input_lock = false
+embedded_in_source_lock = false
+storage = "separate_generation_scoped_evidence"
+
+[artifact_contract]
+path = "contracts/release/rhi-artifact-contract.v3.json"
+sha256 = "d2fedbe4e8bee8f2e6c4396e2cb361bd20b303782cc729b8ee790cfd72bd4682"
+binding = "exact_regular_file_bytes_in_same_source_revision"
+
+[sqlite]
+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]
+config = 1
+state = 11
+admin = 1
+status = 1
+provider = 1
diff --git a/tests/build_policy.rs b/tests/build_policy.rs
@@ -3,7 +3,8 @@
use sha2::{Digest, Sha256};
const MANIFEST: &str = include_str!("../Cargo.toml");
-const SOURCE_LOCK: &str = include_str!("../radroots.service.source-lock.v2.toml");
+const SOURCE_LOCK: &str = include_str!("../radroots.service.source-lock.v3.toml");
+const FLAKE_LOCK: &[u8] = include_bytes!("../flake.lock");
#[test]
fn manifest_freezes_the_native_service_policy() {
@@ -21,9 +22,9 @@ fn manifest_freezes_the_native_service_policy() {
}
#[test]
-fn source_lock_metadata_is_exact_and_nix_is_absent() {
+fn source_lock_metadata_is_exact_and_nix_is_qualified() {
assert!(MANIFEST.contains(
- "[workspace.metadata.radroots.service_source_lock]\nservice = \"rhi\"\nhost_feature_profile = \"service-host\"\nnix_material = \"absent\""
+ "[workspace.metadata.radroots.service_source_lock]\nservice = \"rhi\"\nhost_feature_profile = \"service-host\"\nnix_material = \"qualified\""
));
for field in [
"config_contract_version = 1",
@@ -43,7 +44,7 @@ fn source_lock_metadata_is_exact_and_nix_is_absent() {
fn shared_host_packages_are_exactly_source_locked() {
for dependency in ["radroots_service_host", "radroots_service_sqlite"] {
assert!(MANIFEST.contains(&format!(
- "{dependency} = {{ git = \"https://github.com/radrootslabs/lib\", rev = \"053d0c750bf9cd683c6ea37cefe7e79617ba629f\", version = \"=0.1.0-alpha\" }}"
+ "{dependency} = {{ git = \"https://github.com/radrootslabs/lib\", rev = \"055096853fca95e15d0f813d33a14aca13be3881\", version = \"=0.1.0-alpha\" }}"
)));
}
}
@@ -51,7 +52,7 @@ fn shared_host_packages_are_exactly_source_locked() {
#[test]
fn shared_service_sqlite_is_the_only_catalog_authority() {
assert!(MANIFEST.contains(
- "radroots_service_sqlite = { git = \"https://github.com/radrootslabs/lib\", rev = \"053d0c750bf9cd683c6ea37cefe7e79617ba629f\", version = \"=0.1.0-alpha\" }"
+ "radroots_service_sqlite = { git = \"https://github.com/radrootslabs/lib\", rev = \"055096853fca95e15d0f813d33a14aca13be3881\", version = \"=0.1.0-alpha\" }"
));
for forbidden in ["rusqlite", "libsqlite3-sys"] {
assert!(
@@ -64,37 +65,39 @@ fn shared_service_sqlite_is_the_only_catalog_authority() {
#[test]
fn shared_storage_generation_type_is_exactly_source_locked() {
assert!(MANIFEST.contains(
- "radroots_storage = { git = \"https://github.com/radrootslabs/lib\", rev = \"053d0c750bf9cd683c6ea37cefe7e79617ba629f\", version = \"=0.1.0-alpha\", default-features = false }"
+ "radroots_storage = { git = \"https://github.com/radrootslabs/lib\", rev = \"055096853fca95e15d0f813d33a14aca13be3881\", version = \"=0.1.0-alpha\", default-features = false }"
));
}
#[test]
fn shared_transport_spi_is_exactly_source_locked_without_serde() {
assert!(MANIFEST.contains(
- "radroots_transport = { git = \"https://github.com/radrootslabs/lib\", rev = \"053d0c750bf9cd683c6ea37cefe7e79617ba629f\", version = \"=0.1.0-alpha\", default-features = false, features = [\"std\"] }"
+ "radroots_transport = { git = \"https://github.com/radrootslabs/lib\", rev = \"055096853fca95e15d0f813d33a14aca13be3881\", version = \"=0.1.0-alpha\", default-features = false, features = [\"std\"] }"
));
assert!(MANIFEST.contains(
- "radroots_transport_nostr = { git = \"https://github.com/radrootslabs/lib\", rev = \"053d0c750bf9cd683c6ea37cefe7e79617ba629f\", version = \"=0.1.0-alpha\" }"
+ "radroots_transport_nostr = { git = \"https://github.com/radrootslabs/lib\", rev = \"055096853fca95e15d0f813d33a14aca13be3881\", version = \"=0.1.0-alpha\" }"
));
}
#[test]
fn source_lock_binds_the_current_cargo_lock() {
let digest = lower_hex(&Sha256::digest(include_bytes!("../Cargo.lock")));
+ let flake_digest = lower_hex(&Sha256::digest(FLAKE_LOCK));
assert!(SOURCE_LOCK.starts_with(
- "schema = \"radroots.service.source-lock.v2\"\ncontract_version = 2\nservice = \"rhi\"\n"
+ "schema = \"radroots.service.source-lock.v3\"\ncontract_version = 3\nservice = \"rhi\"\n"
));
assert!(SOURCE_LOCK.contains(&format!("cargo_lock_sha256 = \"{digest}\"")));
- assert!(SOURCE_LOCK.contains("revision = \"053d0c750bf9cd683c6ea37cefe7e79617ba629f\""));
+ assert!(SOURCE_LOCK.contains(&format!("sha256 = \"{flake_digest}\"")));
+ assert!(SOURCE_LOCK.contains("revision = \"055096853fca95e15d0f813d33a14aca13be3881\""));
assert!(SOURCE_LOCK.contains(
"workspace_catalog_sha256 = \"deca0c080deae187ff8186c0708903e42f41ea57f77c5f91581e23aa561164a4\""
));
assert!(SOURCE_LOCK.contains(
- "source_archive_sha256 = \"4c0769a6105cf7547b85544a249178fc7384161e759e9e712994419eaf168e9c\""
+ "source_archive_sha256 = \"89b8ace3f61167df43aca89917405d58b2aaf2ddea8fadfb21d351d76f184e68\""
+ ));
+ assert!(SOURCE_LOCK.contains(
+ "[nix]\nmaterial = \"qualified\"\nlib_revision = \"055096853fca95e15d0f813d33a14aca13be3881\"\nsupported_systems = [\"aarch64-darwin\", \"x86_64-linux\"]\n"
));
- assert!(SOURCE_LOCK.contains("\n[nix]\nmaterial = \"absent\"\n"));
- assert!(!SOURCE_LOCK.contains("flake_lock_sha256"));
- assert!(!SOURCE_LOCK.contains("lib_revision ="));
assert!(SOURCE_LOCK.ends_with(
"[contract_versions]\nconfig = 1\nstate = 11\nadmin = 1\nstatus = 1\nprovider = 1\n"
));
diff --git a/tests/package_boundary.rs b/tests/package_boundary.rs
@@ -1869,14 +1869,15 @@ fn readme_freezes_the_root_only_boundary_and_exact_baseline() {
}
#[test]
-fn human_verification_contract_is_extbuild_only_through_rcld_170() {
+fn human_verification_contract_routes_checks_and_records_nix_outputs() {
for required in [
"cargo extbuild doctor",
"cargo extbuild run -- cargo fmt --all --check",
"cargo extbuild run -- cargo check --workspace --all-targets --locked",
"cargo extbuild run -- cargo test --workspace --all-targets --locked",
"cargo extbuild run -- cargo clippy --workspace --all-targets --locked -- -D warnings",
- "Nix-produced OCI artifacts are deferred and unclaimed",
+ "The flake exposes the RHI package, application, checks, and development shell",
+ "unsigned OCI\nderivation for `x86_64-linux`",
] {
assert!(README.contains(required), "README is missing {required}");
}
diff --git a/tests/services_hardening_admin_wave_qualification.rs b/tests/services_hardening_admin_wave_qualification.rs
@@ -120,7 +120,8 @@ fn qualification_is_executable_source_locked_and_authority_safe() {
.bytes()
.all(|byte| byte.is_ascii_hexdigit() && !byte.is_ascii_uppercase())
);
- assert!(MANIFEST.contains(&format!("rev = \"{revision}\"")));
+ assert_eq!(revision, "053d0c750bf9cd683c6ea37cefe7e79617ba629f");
+ assert!(MANIFEST.contains("rev = \"055096853fca95e15d0f813d33a14aca13be3881\""));
assert!(
MANIFEST
.contains("radroots_service_host = { git = \"https://github.com/radrootslabs/lib\"")
diff --git a/tests/services_hardening_failure_qualification.rs b/tests/services_hardening_failure_qualification.rs
@@ -6,7 +6,6 @@ use serde_json::Value;
const CONTRACT: &str =
include_str!("../contracts/services_hardening/failure_qualification.v1.json");
-const SOURCE_LOCK: &str = include_str!("../radroots.service.source-lock.v2.toml");
const MANIFEST: &str = include_str!("../Cargo.toml");
const README: &str = include_str!("../README");
const AGENTS: &str = include_str!("../AGENTS.md");
@@ -174,13 +173,15 @@ fn every_component_contract_entry_names_an_executable_test() {
}
#[test]
-fn source_lock_binds_the_shared_sqlite_failure_corpus_without_a_second_authority() {
+fn historical_source_lock_binds_the_shared_sqlite_failure_corpus() {
let contract: Value = serde_json::from_str(CONTRACT).expect("failure qualification contract");
let revision = contract["source_lock"]["lib_revision"]
.as_str()
.expect("Lib revision");
- assert!(SOURCE_LOCK.contains(&format!("revision = \"{revision}\"")));
- assert!(MANIFEST.contains(&format!("radroots_service_sqlite = {{ git = \"https://github.com/radrootslabs/lib\", rev = \"{revision}\"")));
+ assert_eq!(revision, "053d0c750bf9cd683c6ea37cefe7e79617ba629f");
+ assert!(MANIFEST.contains(
+ "radroots_service_sqlite = { git = \"https://github.com/radrootslabs/lib\", rev = \"055096853fca95e15d0f813d33a14aca13be3881\""
+ ));
assert_eq!(
contract["source_locked_shared_sqlite_corpus"],
serde_json::json!([
diff --git a/tests/services_hardening_native_release.rs b/tests/services_hardening_native_release.rs
@@ -5,15 +5,19 @@ use std::collections::BTreeSet;
use serde_json::json;
const CONTRACT: &str = include_str!("../contracts/services_hardening/native_release.v1.json");
+const ACTIVE_CONTRACT: &str =
+ include_str!("../contracts/services_hardening/native_release.v2.json");
const MANIFEST: &str = include_str!("../Cargo.toml");
const LOCK: &str = include_str!("../Cargo.lock");
-const SOURCE_LOCK: &str = include_str!("../radroots.service.source-lock.v2.toml");
+const FLAKE: &str = include_str!("../flake.nix");
+const FLAKE_LOCK: &str = include_str!("../flake.lock");
+const SOURCE_LOCK: &str = include_str!("../radroots.service.source-lock.v3.toml");
const CARGO_CONFIG: &str = include_str!("../.cargo/config.toml");
const SYSTEMD_UNIT: &str = include_str!("../packaging/systemd/rhi@.service");
const RELEASE_ACCEPTANCE: &str = include_str!("../scripts/release-acceptance.sh");
const XTASK_MANIFEST: &str = include_str!("../tools/xtask/Cargo.toml");
-const LIB_REVISION: &str = "053d0c750bf9cd683c6ea37cefe7e79617ba629f";
+const LIB_REVISION: &str = "055096853fca95e15d0f813d33a14aca13be3881";
const LIB_REPOSITORY: &str = "https://github.com/radrootslabs/lib";
#[test]
@@ -164,6 +168,11 @@ fn native_release_contract_and_manifest_metadata_are_exact() {
version = "0.1.0"
})
);
+ assert_eq!(
+ manifest["workspace"]["metadata"]["radroots"]["service_source_lock"]["nix_material"]
+ .as_str(),
+ Some("qualified")
+ );
let source_lock: toml::Value = toml::from_str(SOURCE_LOCK).expect("source lock");
assert_eq!(
contract["contract_versions"]["state"].as_u64(),
@@ -253,35 +262,47 @@ fn every_radroots_dependency_is_exactly_source_locked() {
let source = sources.into_iter().next().expect("Lib source");
assert!(source.contains(&format!("?rev={LIB_REVISION}#{LIB_REVISION}")));
- assert!(SOURCE_LOCK.contains("\n[nix]\nmaterial = \"absent\"\n"));
- assert!(!SOURCE_LOCK.contains("lib_revision ="));
- assert!(!SOURCE_LOCK.contains("flake_lock_sha256 ="));
+ for required in [
+ "url = \"github:radrootslabs/lib/055096853fca95e15d0f813d33a14aca13be3881\";",
+ "systems = lib.lib.supportedSystems;",
+ "nixosModules.default",
+ ] {
+ assert!(
+ FLAKE.contains(required),
+ "flake source is missing `{required}`"
+ );
+ }
+ let flake_lock: serde_json::Value =
+ serde_json::from_str(FLAKE_LOCK).expect("flake source lock");
+ assert_eq!(flake_lock["version"], 7);
+ assert_eq!(flake_lock["root"], "root");
+ assert_eq!(flake_lock["nodes"]["root"]["inputs"]["lib"], "lib");
+ assert_eq!(flake_lock["nodes"]["lib"]["locked"]["rev"], LIB_REVISION);
+ assert_eq!(flake_lock["nodes"]["lib"]["original"]["rev"], LIB_REVISION);
}
#[test]
-fn native_release_surfaces_remain_external_and_preterminal() {
+fn native_release_surfaces_remain_external_and_nix_qualified() {
let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
for required in [
".cargo/config.toml",
"packaging/systemd/rhi@.service",
- "radroots.service.source-lock.v2.toml",
+ "radroots.service.source-lock.v3.toml",
"scripts/release-acceptance.sh",
"tools/xtask/Cargo.toml",
"tools/xtask/src/main.rs",
"contracts/services_hardening/native_release.v1.json",
+ "contracts/services_hardening/native_release.v2.json",
+ "contracts/release/rhi-artifact-contract.v3.json",
+ "flake.nix",
+ "flake.lock",
] {
assert!(root.join(required).is_file(), "missing `{required}`");
}
- assert!(
- !root
- .join("contracts/services_hardening/native_release.v2.json")
- .exists()
- );
+ assert!(!root.join("radroots.service.source-lock.v2.toml").exists());
for forbidden in [
".github",
".act",
- "flake.nix",
- "flake.lock",
"target",
"result",
"artifacts",
@@ -299,6 +320,18 @@ fn native_release_surfaces_remain_external_and_preterminal() {
assert!(!CONTRACT.contains("production_ready"));
assert!(!CONTRACT.contains("oci-image"));
assert!(!CONTRACT.contains("nixos-module"));
+ let active: serde_json::Value =
+ serde_json::from_str(ACTIVE_CONTRACT).expect("active release contract");
+ assert_eq!(active["schema_version"], 2);
+ assert_eq!(active["contract_version"], 2);
+ assert_eq!(active["predecessor"]["filename"], "native_release.v1.json");
+ assert_eq!(
+ active["source_lock"]["filename"],
+ "radroots.service.source-lock.v3.toml"
+ );
+ assert_eq!(active["source_lock"]["nix_material"], "qualified");
+ assert_eq!(active["nix_outputs"]["bundled_sqlite"], true);
+ assert_eq!(active["nix_outputs"]["native_linkage_count"], 1);
}
#[test]
diff --git a/tests/services_hardening_process.rs b/tests/services_hardening_process.rs
@@ -30,7 +30,7 @@ const PROCESS_QUALIFICATION_CONTRACT: &str =
include_str!("../contracts/services_hardening/process_qualification.v1.json");
const FAILURE_QUALIFICATION_CONTRACT: &[u8] =
include_bytes!("../contracts/services_hardening/failure_qualification.v1.json");
-const SOURCE_LOCK: &str = include_str!("../radroots.service.source-lock.v2.toml");
+const SOURCE_LOCK: &str = include_str!("../radroots.service.source-lock.v3.toml");
const PROCESS_DEADLINE: Duration = Duration::from_secs(30);
const POLL_INTERVAL: Duration = Duration::from_millis(2);
const CONNECT_DEADLINE_MILLISECONDS: u64 = 5_000;
@@ -652,7 +652,7 @@ fn process_qualification_contract_freezes_the_exact_wave_closure() {
lower_hex(&Sha256::digest(FAILURE_QUALIFICATION_CONTRACT)),
contract["component_qualification"]["sha256"]
);
- assert!(SOURCE_LOCK.contains("revision = \"053d0c750bf9cd683c6ea37cefe7e79617ba629f\""));
+ assert!(SOURCE_LOCK.contains("revision = \"055096853fca95e15d0f813d33a14aca13be3881\""));
}
#[test]
diff --git a/tests/services_hardening_state_catalog.rs b/tests/services_hardening_state_catalog.rs
@@ -579,7 +579,7 @@ fn secret_object() -> SchemaObject {
#[test]
fn catalog_source_is_pure_pinned_and_uses_only_the_shared_authority() {
assert!(MANIFEST.contains(
- "radroots_service_sqlite = { git = \"https://github.com/radrootslabs/lib\", rev = \"053d0c750bf9cd683c6ea37cefe7e79617ba629f\", version = \"=0.1.0-alpha\" }"
+ "radroots_service_sqlite = { git = \"https://github.com/radrootslabs/lib\", rev = \"055096853fca95e15d0f813d33a14aca13be3881\", version = \"=0.1.0-alpha\" }"
));
assert!(LIB_SOURCE.contains("mod state_catalog;"));
assert!(!LIB_SOURCE.contains("pub mod state_catalog;"));
diff --git a/tests/services_hardening_wave_100_a.rs b/tests/services_hardening_wave_100_a.rs
@@ -7,7 +7,7 @@ use serde_json::Value;
const CONFIG_EXAMPLE: &str = include_str!("../contracts/services_hardening/config.v1.example.toml");
const CONFIG_SCHEMA: &str = include_str!("../contracts/services_hardening/config.v1.schema.json");
-const SOURCE_LOCK: &str = include_str!("../radroots.service.source-lock.v2.toml");
+const SOURCE_LOCK: &str = include_str!("../radroots.service.source-lock.v3.toml");
#[test]
fn canonical_example_agrees_with_the_exact_schema_and_parser() {
@@ -29,12 +29,10 @@ fn canonical_example_agrees_with_the_exact_schema_and_parser() {
}
#[test]
-fn wave_one_removed_files_and_predecessor_lock_are_absent() {
+fn wave_one_removed_files_remain_absent_after_nix_qualification() {
let root = Path::new(env!("CARGO_MANIFEST_DIR"));
for removed in [
"config.toml",
- "flake.lock",
- "flake.nix",
"radroots.lib.source-lock.v1.toml",
"src/config.rs",
"src/host_nostr.rs",
@@ -46,20 +44,15 @@ fn wave_one_removed_files_and_predecessor_lock_are_absent() {
"removed path remains: {removed}"
);
}
- assert!(root.join("radroots.service.source-lock.v2.toml").is_file());
+ assert!(!root.join("radroots.service.source-lock.v2.toml").exists());
+ assert!(root.join("radroots.service.source-lock.v3.toml").is_file());
+ assert!(root.join("flake.nix").is_file());
+ assert!(root.join("flake.lock").is_file());
assert!(SOURCE_LOCK.starts_with(
- "schema = \"radroots.service.source-lock.v2\"\ncontract_version = 2\nservice = \"rhi\"\n"
+ "schema = \"radroots.service.source-lock.v3\"\ncontract_version = 3\nservice = \"rhi\"\n"
));
- for forbidden in [
- "lib_revision =",
- "flake_lock_sha256",
- "material = \"present\"",
- ] {
- assert!(
- !SOURCE_LOCK.contains(forbidden),
- "source lock retains predecessor behavior: {forbidden}"
- );
- }
+ assert!(SOURCE_LOCK.contains("material = \"qualified\""));
+ assert!(SOURCE_LOCK.contains("lib_revision = \"055096853fca95e15d0f813d33a14aca13be3881\""));
}
#[test]
diff --git a/tests/source_guards.rs b/tests/source_guards.rs
@@ -43,7 +43,7 @@ fn rhi_manifest_exact_pins_radroots_contract() {
);
assert_eq!(
dependency.get("rev").and_then(toml::Value::as_str),
- Some("053d0c750bf9cd683c6ea37cefe7e79617ba629f"),
+ Some("055096853fca95e15d0f813d33a14aca13be3881"),
"RHI must source-lock {name} to the exact promoted Lib revision"
);
assert_eq!(
@@ -145,8 +145,6 @@ fn rhi_runtime_context_retains_only_governed_artifacts() {
fn rhi_wave_one_removes_prototype_runtime_and_selection_authority() {
for forbidden_path in [
"config.toml",
- "flake.lock",
- "flake.nix",
"radroots.lib.source-lock.v1.toml",
"src/config.rs",
"src/host_nostr.rs",
diff --git a/tools/xtask/src/main.rs b/tools/xtask/src/main.rs
@@ -20,7 +20,7 @@ const REPOSITORY: &str = "https://github.com/radrootslabs/rhi";
const RUST_VERSION: &str = "1.97.1";
const HOST_FEATURE_PROFILE: &str = "service-host";
const RADROOTS_DEPENDENCY_COUNT: usize = 12;
-const SOURCE_LOCK: &str = "radroots.service.source-lock.v2.toml";
+const SOURCE_LOCK: &str = "radroots.service.source-lock.v3.toml";
const CONFIG_EXAMPLE: &str = "contracts/services_hardening/config.v1.example.toml";
const CONFIG_SCHEMA: &str = "contracts/services_hardening/config.v1.schema.json";
const SYSTEMD_UNIT: &str = "packaging/systemd/rhi@.service";
@@ -162,10 +162,13 @@ struct SourceLock {
workspace_catalog_sha256: String,
version: String,
source_archive_sha256: String,
+ source_archive_contract: SourceArchiveContract,
cargo_lock_sha256: String,
rust_version: String,
host_feature_profile: String,
nix: NixEvidence,
+ artifact_contract: ArtifactContract,
+ sqlite: SqliteContract,
contract_versions: ContractVersions,
}
@@ -173,8 +176,68 @@ struct SourceLock {
#[serde(deny_unknown_fields)]
struct NixEvidence {
material: String,
- lib_revision: Option<String>,
- flake_lock_sha256: Option<String>,
+ lib_revision: String,
+ public_input_lock: PublicInputLock,
+ parent_result: ParentResult,
+ supported_systems: Vec<String>,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct PublicInputLock {
+ path: String,
+ sha256: String,
+ binding: String,
+ mutable_reference: String,
+ lib_input: String,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct ParentResult {
+ embedded_in_public_input_lock: bool,
+ embedded_in_source_lock: bool,
+ storage: String,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct SourceArchiveContract {
+ binding: String,
+ format: String,
+ compression: String,
+ compression_timestamp: String,
+ entry_order: String,
+ path_prefix: String,
+ file_mode: String,
+ uid: u32,
+ gid: u32,
+ uname: String,
+ gname: String,
+ mtime: String,
+ pax_headers: String,
+ directory_entries: String,
+ symlinks: String,
+ hardlinks: String,
+ submodules: String,
+ trailer: String,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct ArtifactContract {
+ path: String,
+ sha256: String,
+ binding: String,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct SqliteContract {
+ high_level_authority: String,
+ second_pool_connection_query_transaction_migration_authority: String,
+ incremental_backup_adapter: String,
+ native_linkage_count: u32,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
@@ -466,7 +529,7 @@ fn native_release(root: &Path, args: &NativeReleaseArgs) -> Result<(), ReleaseEr
host_feature_profile: HOST_FEATURE_PROFILE,
contract_versions: source_lock.contract_versions.clone(),
protected_material_included: false,
- nix_qualified: false,
+ nix_qualified: true,
oci_included: false,
artifacts: payload,
};
@@ -477,8 +540,8 @@ fn native_release(root: &Path, args: &NativeReleaseArgs) -> Result<(), ReleaseEr
schema: "radroots.service.provenance-input.v1",
contract_version: 1,
predicate_type: "https://slsa.dev/provenance/v1",
- build_type: "https://radroots.dev/contracts/rhi-native-release/v1",
- builder_id: "https://radroots.dev/builders/rhi-native-release/v1",
+ build_type: "https://radroots.dev/contracts/rhi-native-release/v2",
+ builder_id: "https://radroots.dev/builders/rhi-native-release/v2",
service: SERVICE,
version: VERSION,
target: args.target.clone(),
@@ -625,9 +688,14 @@ fn read_source_lock(root: &Path) -> Result<SourceLock, ReleaseError> {
let text = std::str::from_utf8(&bytes).map_err(|_| ReleaseError::InvalidSourceLock)?;
let lock: SourceLock = toml::from_str(text).map_err(|_| ReleaseError::InvalidSourceLock)?;
let cargo_lock = hash_regular(&root.join("Cargo.lock"), MAX_DOCUMENT_BYTES)?;
+ let flake_lock = hash_regular(&root.join("flake.lock"), MAX_DOCUMENT_BYTES)?;
+ let artifact_contract = hash_regular(
+ &root.join("contracts/release/rhi-artifact-contract.v3.json"),
+ MAX_DOCUMENT_BYTES,
+ )?;
let revisions = cargo_dependency_revisions(root)?;
- if lock.schema != "radroots.service.source-lock.v2"
- || lock.contract_version != 2
+ if lock.schema != "radroots.service.source-lock.v3"
+ || lock.contract_version != 3
|| lock.service != SERVICE
|| lock.repository != "https://github.com/radrootslabs/lib"
|| !lower_hex(&lock.revision, 40)
@@ -638,9 +706,46 @@ fn read_source_lock(root: &Path) -> Result<SourceLock, ReleaseError> {
|| lock.cargo_lock_sha256 != cargo_lock.sha256
|| lock.rust_version != RUST_VERSION
|| lock.host_feature_profile != HOST_FEATURE_PROFILE
- || lock.nix.material != "absent"
- || lock.nix.lib_revision.is_some()
- || lock.nix.flake_lock_sha256.is_some()
+ || lock.source_archive_contract.binding
+ != "sha256_of_canonical_exact_lib_revision_tree_archive"
+ || lock.source_archive_contract.format != "ustar"
+ || lock.source_archive_contract.compression != "none"
+ || lock.source_archive_contract.compression_timestamp != "not_applicable"
+ || lock.source_archive_contract.entry_order != "bytewise_git_path"
+ || lock.source_archive_contract.path_prefix != "none"
+ || lock.source_archive_contract.file_mode != "git_index_100644_or_100755"
+ || lock.source_archive_contract.uid != 0
+ || lock.source_archive_contract.gid != 0
+ || !lock.source_archive_contract.uname.is_empty()
+ || !lock.source_archive_contract.gname.is_empty()
+ || lock.source_archive_contract.mtime != "lib_revision_commit_timestamp"
+ || lock.source_archive_contract.pax_headers != "forbidden"
+ || lock.source_archive_contract.directory_entries != "omitted"
+ || lock.source_archive_contract.symlinks != "forbidden"
+ || lock.source_archive_contract.hardlinks != "forbidden"
+ || lock.source_archive_contract.submodules != "forbidden"
+ || lock.source_archive_contract.trailer != "two_zero_blocks"
+ || lock.nix.material != "qualified"
+ || lock.nix.lib_revision != lock.revision
+ || lock.nix.supported_systems != ["aarch64-darwin", "x86_64-linux"]
+ || lock.nix.public_input_lock.path != "flake.lock"
+ || lock.nix.public_input_lock.sha256 != flake_lock.sha256
+ || lock.nix.public_input_lock.binding != "exact_regular_file_bytes"
+ || lock.nix.public_input_lock.mutable_reference != "forbidden"
+ || lock.nix.public_input_lock.lib_input != "lib"
+ || lock.nix.parent_result.embedded_in_public_input_lock
+ || lock.nix.parent_result.embedded_in_source_lock
+ || lock.nix.parent_result.storage != "separate_generation_scoped_evidence"
+ || lock.artifact_contract.path != "contracts/release/rhi-artifact-contract.v3.json"
+ || lock.artifact_contract.sha256 != artifact_contract.sha256
+ || lock.artifact_contract.binding != "exact_regular_file_bytes_in_same_source_revision"
+ || lock.sqlite.high_level_authority != "sqlx_only"
+ || lock
+ .sqlite
+ .second_pool_connection_query_transaction_migration_authority
+ != "forbidden"
+ || lock.sqlite.incremental_backup_adapter != "sealed_native_sqlx_owned_locked_handle_only"
+ || lock.sqlite.native_linkage_count != 1
|| revisions != BTreeSet::from([lock.revision.clone()])
|| [
lock.contract_versions.config,