lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

commit 9a9520c4ada7caf0492497fce19edac9e2648da9
parent f4948427d48fe7aa1b7cdc6de58a370870354807
Author: triesap <tyson@radroots.org>
Date:   Sun,  6 Sep 2026 23:46:23 +0000

build: publish real Lib Nix outputs

- Replace fixture-owned defaults with the public library release bundle.
- Expose governed overlays and shared service helpers on exact systems.
- Require typed nonsecret environment inputs at helper construction.
- Reject non-normal credential paths and multiline service arguments.

Diffstat:
Abuild/nix/library.nix | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbuild/nix/service/apps.nix | 1+
Mbuild/nix/service/checks.nix | 1+
Mbuild/nix/service/compose.nix | 1+
Mbuild/nix/service/devshell.nix | 1+
Mbuild/nix/service/fixture.nix | 116++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mbuild/nix/service/native-inputs.nix | 22+++++++++++++++++++++-
Mbuild/nix/service/nixos-module.nix | 13+++++++++++--
Mbuild/nix/service/package.nix | 1+
Mflake.nix | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
10 files changed, 253 insertions(+), 37 deletions(-)

diff --git a/build/nix/library.nix b/build/nix/library.nix @@ -0,0 +1,53 @@ +{ + lib, + pkgs, + version, +}: +let + root = ../..; + releaseSource = lib.fileset.toSource { + inherit root; + fileset = lib.fileset.unions [ + ../../Cargo.toml + ../../Cargo.lock + ../../CHANGELOG.md + ../../LICENSE-APACHE + ../../LICENSE-MIT + ../../README.md + ../../contracts + ../../crates + ]; + }; + package = pkgs.runCommand "radroots-lib-release-bundle-${version}" { } '' + install -d "$out/share/radroots-lib" + cp -R ${releaseSource}/. "$out/share/radroots-lib/" + cat > "$out/share/radroots-lib/release-bundle.json" <<EOF + {"artifact":"public_library_workspace_release_bundle","package":"radroots","version":"${version}"} + EOF + ''; + inspector = pkgs.writeShellApplication { + name = "radroots-lib-bundle-inspect"; + runtimeInputs = [ pkgs.coreutils ]; + text = '' + set -euo pipefail + test -f ${package}/share/radroots-lib/Cargo.toml + test -f ${package}/share/radroots-lib/Cargo.lock + exec cat ${package}/share/radroots-lib/release-bundle.json + ''; + }; +in +{ + inherit package; + app = { + type = "app"; + program = "${inspector}/bin/radroots-lib-bundle-inspect"; + meta.description = "Inspect the installed Radroots Lib release bundle"; + }; + check = pkgs.runCommand "radroots-lib-release-bundle-check" { } '' + test -f ${package}/share/radroots-lib/Cargo.toml + test -f ${package}/share/radroots-lib/Cargo.lock + test -f ${package}/share/radroots-lib/release-bundle.json + test ! -e ${package}/share/radroots-lib/build/nix/service/fixture-service + touch "$out" + ''; +} diff --git a/build/nix/service/apps.nix b/build/nix/service/apps.nix @@ -20,6 +20,7 @@ assert lib.assertMsg ( assert lib.assertMsg (lib.isDerivation toolchain) "toolchain must be a derivation"; assert lib.assertMsg ( builtins.isAttrs nativeInputs + && (nativeInputs.schema or null) == "radroots.service.native-inputs.v1" && builtins.isList (nativeInputs.nativeBuildInputs or null) && builtins.isList (nativeInputs.buildInputs or null) && builtins.isAttrs (nativeInputs.environment or null) diff --git a/build/nix/service/checks.nix b/build/nix/service/checks.nix @@ -21,6 +21,7 @@ assert lib.assertMsg (builtins.pathExists source) "source must exist"; assert lib.assertMsg (builtins.pathExists cargoLock) "cargoLock must exist"; assert lib.assertMsg ( builtins.isAttrs nativeInputs + && (nativeInputs.schema or null) == "radroots.service.native-inputs.v1" && builtins.isList (nativeInputs.nativeBuildInputs or null) && builtins.isList (nativeInputs.buildInputs or null) && builtins.isAttrs (nativeInputs.environment or null) diff --git a/build/nix/service/compose.nix b/build/nix/service/compose.nix @@ -14,6 +14,7 @@ assert lib.assertMsg ( assert lib.assertMsg (lib.isDerivation package) "package must be a derivation"; assert lib.assertMsg ( builtins.isAttrs nativeInputs + && (nativeInputs.schema or null) == "radroots.service.native-inputs.v1" && builtins.isList (nativeInputs.nativeBuildInputs or null) && builtins.isList (nativeInputs.buildInputs or null) && builtins.isAttrs (nativeInputs.environment or null) diff --git a/build/nix/service/devshell.nix b/build/nix/service/devshell.nix @@ -13,6 +13,7 @@ assert lib.assertMsg ( assert lib.assertMsg (lib.isDerivation toolchain) "toolchain must be a derivation"; assert lib.assertMsg ( builtins.isAttrs nativeInputs + && (nativeInputs.schema or null) == "radroots.service.native-inputs.v1" && builtins.isList (nativeInputs.nativeBuildInputs or null) && builtins.isList (nativeInputs.buildInputs or null) && builtins.isAttrs (nativeInputs.environment or null) diff --git a/build/nix/service/fixture.nix b/build/nix/service/fixture.nix @@ -9,7 +9,10 @@ let nativeInputs = service.mkNativeInputs { nativeBuildInputs = [ pkgs.coreutils ]; environment = { - RADROOTS_SERVICE_FIXTURE = "1"; + RADROOTS_SERVICE_FIXTURE = { + classification = "nonsecret"; + value = "1"; + }; }; }; fixtureSource = ./fixture-service; @@ -351,6 +354,42 @@ let nativeInputs = { }; }).nativeInputs ); + invalidNativeInputDefinitions = + map + ( + environment: + builtins.tryEval (builtins.deepSeq (service.mkNativeInputs { inherit environment; }) true) + ) + [ + { + LEGACY_VALUE = "untyped"; + } + { + CLASSIFIED_SECRET = { + classification = "secret"; + value = "redacted"; + }; + } + { + EXTRA_FIELD = { + classification = "nonsecret"; + value = "value"; + unexpected = true; + }; + } + { + API_TOKEN = { + classification = "nonsecret"; + value = "redacted"; + }; + } + { + OVERLONG_VALUE = { + classification = "nonsecret"; + value = lib.concatStrings (lib.replicate 4097 "a"); + }; + } + ]; invalidServicePackage = builtins.tryEval ( (service.mkServicePackage { inherit nativeInputs toolchain; @@ -384,7 +423,10 @@ let cargoLock = fixtureSource + "/Cargo.lock"; servicePackage = "fixture-service"; nativeInputs = service.mkNativeInputs { - environment.CARGO_PROFILE = "dev"; + environment.CARGO_PROFILE = { + classification = "nonsecret"; + value = "dev"; + }; }; }).outPath ); @@ -439,7 +481,10 @@ let checkArgs // { nativeInputs = service.mkNativeInputs { - environment.${variable} = "override"; + environment.${variable} = { + classification = "nonsecret"; + value = "override"; + }; }; } )).check.outPath @@ -506,7 +551,12 @@ let (service.mkServiceApps ( appArgs // { - nativeInputs = service.mkNativeInputs { environment."INVALID-NAME" = "value"; }; + nativeInputs = service.mkNativeInputs { + environment."INVALID-NAME" = { + classification = "nonsecret"; + value = "value"; + }; + }; } )).default.program )) @@ -514,7 +564,12 @@ let (service.mkServiceApps ( appArgs // { - nativeInputs = service.mkNativeInputs { environment.PATH = "/tmp"; }; + nativeInputs = service.mkNativeInputs { + environment.PATH = { + classification = "nonsecret"; + value = "/tmp"; + }; + }; } )).default.program )) @@ -554,7 +609,12 @@ let (service.mkServiceDevShell ( devShellArgs // { - nativeInputs = service.mkNativeInputs { environment."INVALID-NAME" = "value"; }; + nativeInputs = service.mkNativeInputs { + environment."INVALID-NAME" = { + classification = "nonsecret"; + value = "value"; + }; + }; } )).drvPath )) @@ -562,7 +622,12 @@ let (service.mkServiceDevShell ( devShellArgs // { - nativeInputs = service.mkNativeInputs { environment.RUSTC = "/tmp/rustc"; }; + nativeInputs = service.mkNativeInputs { + environment.RUSTC = { + classification = "nonsecret"; + value = "/tmp/rustc"; + }; + }; } )).drvPath )) @@ -853,6 +918,36 @@ let ( baseNixosModuleConfiguration // { + instances.primary.credentials.token = "/run//operator/token"; + } + ) + ( + baseNixosModuleConfiguration + // { + instances.primary.credentials.token = "/run/operator/./token"; + } + ) + ( + baseNixosModuleConfiguration + // { + instances.primary.credentials.token = "/run/operator/../token"; + } + ) + ( + baseNixosModuleConfiguration + // { + instances.primary.credentials.token = "/run/operator/token/"; + } + ) + ( + baseNixosModuleConfiguration + // { + instances.primary.credentials.token = "/"; + } + ) + ( + baseNixosModuleConfiguration + // { instances.primary.credentials.token = "/${lib.concatStrings (lib.replicate 4096 "a")}"; } ) @@ -898,6 +993,7 @@ let (lib.replicate 65 "argument") [ (lib.concatStrings (lib.replicate 4097 "a")) ] [ "argument\nvalue" ] + [ "argument\rvalue" ] ]; maximumNixosModule = service.mkServiceNixosModule ( nixosModuleArguments @@ -956,6 +1052,11 @@ assert assert nativeInputs.nativeBuildInputs == [ pkgs.coreutils ]; assert nativeInputs.buildInputs == [ ]; assert nativeInputs.environment.RADROOTS_SERVICE_FIXTURE == "1"; +assert + nativeInputs.environmentContract.RADROOTS_SERVICE_FIXTURE == { + classification = "nonsecret"; + value = "1"; + }; assert outputs.serviceName == "fixture_service"; assert outputs.packages.default == package; assert (pkgs.stdenv.isLinux -> outputs.packages.oci == ociImage); @@ -1010,6 +1111,7 @@ assert invalidName.success == false; assert defaultOverride.success == false; assert invalidPackage.success == false; assert invalidNativeInputs.success == false; +assert lib.all (result: result.success == false) invalidNativeInputDefinitions; assert invalidServicePackage.success == false; assert invalidBinaryName.success == false; assert invalidReleaseProfile.success == false; diff --git a/build/nix/service/native-inputs.nix b/build/nix/service/native-inputs.nix @@ -7,8 +7,28 @@ assert lib.assertMsg (builtins.isList nativeBuildInputs) "nativeBuildInputs must be a list"; assert lib.assertMsg (builtins.isList buildInputs) "buildInputs must be a list"; assert lib.assertMsg (builtins.isAttrs environment) "environment must be an attribute set"; +assert lib.assertMsg (lib.all (name: builtins.match "^[A-Za-z_][A-Za-z0-9_]*$" name != null) ( + builtins.attrNames environment +)) "environment names must be shell identifiers"; +assert lib.assertMsg (lib.all ( + name: builtins.match ".*(CREDENTIAL|PASSWORD|PRIVATE_KEY|SECRET|TOKEN).*" (lib.toUpper name) == null +) (builtins.attrNames environment)) "environment names must not identify secret material"; +assert lib.assertMsg (lib.all ( + entry: + builtins.isAttrs entry + && + builtins.attrNames entry == [ + "classification" + "value" + ] + && entry.classification == "nonsecret" + && builtins.isString entry.value + && builtins.stringLength entry.value <= 4096 +) (builtins.attrValues environment)) "environment values must be bounded typed nonsecret values"; { + schema = "radroots.service.native-inputs.v1"; nativeBuildInputs = lib.unique nativeBuildInputs; buildInputs = lib.unique buildInputs; - inherit environment; + environment = lib.mapAttrs (_: entry: entry.value) environment; + environmentContract = environment; } diff --git a/build/nix/service/nixos-module.nix b/build/nix/service/nixos-module.nix @@ -67,12 +67,20 @@ let builtins.stringLength name <= 128 && builtins.match "^[A-Za-z0-9][A-Za-z0-9_.-]*$" name != null; validCredentialPath = path: + let + segments = if builtins.isString path then lib.splitString "/" path else [ ]; + in builtins.isString path + && builtins.stringLength path > 1 && builtins.stringLength path <= 4096 && lib.hasPrefix "/" path + && lib.last segments != "" + && lib.all (segment: segment != "" && segment != "." && segment != "..") (lib.drop 1 segments) && path != "/nix/store" && !(lib.hasPrefix "/nix/store/" path) - && builtins.match "^[^:\n]+$" path != null; + && !(lib.hasInfix ":" path) + && !(lib.hasInfix "\r" path) + && !(lib.hasInfix "\n" path); validCredentials = instance: builtins.length (builtins.attrNames instance.credentials) <= 32 @@ -91,7 +99,8 @@ let argument: builtins.isString argument && builtins.stringLength argument <= 4096 - && builtins.match "^[^\n]*$" argument != null + && !(lib.hasInfix "\r" argument) + && !(lib.hasInfix "\n" argument) ) command; package = cfg.package; assertions = [ diff --git a/build/nix/service/package.nix b/build/nix/service/package.nix @@ -27,6 +27,7 @@ assert lib.assertMsg ( ) "releaseProfile must be release or a release-prefixed Cargo profile"; assert lib.assertMsg ( builtins.isAttrs nativeInputs + && (nativeInputs.schema or null) == "radroots.service.native-inputs.v1" && builtins.isList (nativeInputs.nativeBuildInputs or null) && builtins.isList (nativeInputs.buildInputs or null) && builtins.isAttrs (nativeInputs.environment or null) diff --git a/flake.nix b/flake.nix @@ -25,14 +25,33 @@ imports = [ inputs.treefmt-nix.flakeModule ]; systems = import ./build/nix/service/systems.nix; - flake.nixosModules.default = - (import ./build/nix/service/nixos-module.nix { lib = inputs.nixpkgs.lib; }) - { - serviceName = "fixture_service"; - binaryName = "fixture-service"; - packageFor = pkgs: self.packages.${pkgs.stdenv.hostPlatform.system}.default; - commandForInstance = _: [ "--help" ]; + flake.lib = { + supportedSystems = import ./build/nix/service/systems.nix; + mkServiceHelpers = + system: + assert inputs.nixpkgs.lib.assertMsg (builtins.elem system ( + import ./build/nix/service/systems.nix + )) "service helpers support only the governed Nix systems"; + let + pkgs = import inputs.nixpkgs { + inherit system; + overlays = [ inputs.rust-overlay.overlays.default ]; + }; + in + import ./build/nix/service { + crane = inputs.crane; + lib = inputs.nixpkgs.lib; + inherit pkgs; }; + }; + + flake.overlays.default = final: _previous: { + radroots-lib = + assert inputs.nixpkgs.lib.assertMsg + (builtins.elem final.stdenv.hostPlatform.system self.lib.supportedSystems) + "the Radroots Lib overlay supports only the governed Nix systems"; + self.packages.${final.stdenv.hostPlatform.system}.default; + }; perSystem = { @@ -62,43 +81,51 @@ crane = inputs.crane; inherit lib pkgs toolchains; }; + library = import ./build/nix/library.nix { + inherit lib pkgs; + inherit (common) version; + }; serviceFixture = import ./build/nix/service/fixture.nix { inherit lib pkgs service; nixosSystem = inputs.nixpkgs.lib.nixosSystem; toolchain = toolchains.stable; }; + fixtureChecks = lib.mapAttrs' ( + name: value: lib.nameValuePair "service-fixture-${name}" value + ) serviceFixture.outputs.checks; in { treefmt = import ./treefmt.nix; - apps = - (import ./build/nix/apps.nix { - inherit - common - config - lib - pkgs - toolchains - ; - }) - // serviceFixture.outputs.apps; + apps = { + default = library.app; + } + // (import ./build/nix/apps.nix { + inherit + common + config + lib + pkgs + toolchains + ; + }); checks = lib.filterAttrs (_: value: value != null) ( (import ./build/nix/checks.nix { inherit common pkgs; }) - // serviceFixture.outputs.checks + // fixtureChecks + // { + release-bundle = library.check; + } ); - devShells = - (import ./build/nix/devshells.nix { - inherit common pkgs toolchains; - }) - // { - service-fixture = serviceFixture.outputs.devShells.default; - }; + devShells = import ./build/nix/devshells.nix { + inherit common pkgs toolchains; + }; - packages = serviceFixture.outputs.packages // { + packages = { + default = library.package; xtask = common.xtaskPackage; }; };