lib

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

oci.nix (6059B)


      1 {
      2   lib,
      3   pkgs,
      4 }:
      5 {
      6   serviceName,
      7   package,
      8   binaryName,
      9   buildInfo,
     10 }:
     11 assert lib.assertMsg pkgs.stdenv.isLinux "service OCI images require a Linux builder";
     12 assert lib.assertMsg (
     13   pkgs.stdenv.hostPlatform.isx86_64
     14 ) "service OCI images support only x86_64-linux";
     15 assert lib.assertMsg (
     16   builtins.isString serviceName
     17   && builtins.stringLength serviceName <= 128
     18   && builtins.match "^[a-z][a-z0-9_]*$" serviceName != null
     19 ) "serviceName must be a lowercase snake-case identifier";
     20 assert lib.assertMsg (lib.isDerivation package) "package must be a derivation";
     21 assert lib.assertMsg (
     22   (package.passthru.radrootsServicePackage.schema or null) == "radroots.service-package.v1"
     23   && (package.passthru.radrootsServicePackage.servicePackage or null) == binaryName
     24   && (package.passthru.radrootsServicePackage.binaryName or null) == binaryName
     25   && (package.passthru.radrootsServicePackage.serviceLicense or null) == "AGPL-3.0-or-later"
     26 ) "package must carry the governed Cargo-derived service identity and license";
     27 assert lib.assertMsg (
     28   builtins.isString binaryName
     29   && builtins.stringLength binaryName <= 128
     30   && builtins.match "^[a-z][a-z0-9_-]*$" binaryName != null
     31 ) "binaryName must be a lowercase Cargo binary identifier";
     32 assert lib.assertMsg (builtins.isAttrs buildInfo) "buildInfo must be an attribute set";
     33 assert lib.assertMsg (
     34   builtins.attrNames buildInfo == [
     35     "contractVersions"
     36     "featureProfile"
     37     "libRevision"
     38     "rustVersion"
     39     "serviceCommit"
     40     "serviceVersion"
     41     "target"
     42   ]
     43 ) "buildInfo must contain exactly the governed service build fields";
     44 assert lib.assertMsg (
     45   builtins.isString buildInfo.serviceVersion
     46   && builtins.stringLength buildInfo.serviceVersion <= 128
     47   && builtins.match "^[A-Za-z0-9][A-Za-z0-9_.-]*$" buildInfo.serviceVersion != null
     48 ) "buildInfo.serviceVersion must be a bounded image-tag-safe value";
     49 assert lib.assertMsg (
     50   builtins.isString buildInfo.serviceCommit
     51   && builtins.match "^[0-9a-f]{40}$" buildInfo.serviceCommit != null
     52 ) "buildInfo.serviceCommit must be a full lowercase Git revision";
     53 assert lib.assertMsg (
     54   builtins.isString buildInfo.libRevision
     55   && builtins.match "^[0-9a-f]{40}$" buildInfo.libRevision != null
     56 ) "buildInfo.libRevision must be a full lowercase Git revision";
     57 assert lib.assertMsg (
     58   buildInfo.rustVersion == "1.97.1"
     59 ) "buildInfo.rustVersion must match the governed Rust toolchain";
     60 assert lib.assertMsg (
     61   buildInfo.target == pkgs.stdenv.hostPlatform.rust.rustcTarget
     62 ) "buildInfo.target must match the package host platform";
     63 assert lib.assertMsg (
     64   buildInfo.featureProfile == "service-host"
     65 ) "buildInfo.featureProfile must select the service-host profile";
     66 assert lib.assertMsg (builtins.isAttrs buildInfo.contractVersions) (
     67   "buildInfo.contractVersions must be an attribute set"
     68 );
     69 assert lib.assertMsg (
     70   builtins.attrNames buildInfo.contractVersions == [
     71     "admin"
     72     "config"
     73     "provider"
     74     "state"
     75     "status"
     76   ]
     77 ) "buildInfo.contractVersions must contain exactly the governed contract versions";
     78 assert lib.assertMsg (lib.all
     79   (version: builtins.isInt version && version > 0 && version <= 4294967295)
     80   (builtins.attrValues buildInfo.contractVersions)
     81 ) "every buildInfo contract version must be a positive u32";
     82 let
     83   imageName = lib.replaceStrings [ "_" ] [ "-" ] serviceName;
     84   user = "65532:65532";
     85   mountPaths = [
     86     "/etc/radroots/services/${serviceName}"
     87     "/etc/radroots/secrets/services/${serviceName}"
     88     "/run/radroots/services/${serviceName}"
     89     "/var/lib/radroots/services/${serviceName}"
     90   ];
     91   labels = {
     92     "dev.radroots.build.feature-profile" = buildInfo.featureProfile;
     93     "dev.radroots.build.lib-revision" = buildInfo.libRevision;
     94     "dev.radroots.build.rust-version" = buildInfo.rustVersion;
     95     "dev.radroots.build.target" = buildInfo.target;
     96     "dev.radroots.contract.admin-version" = toString buildInfo.contractVersions.admin;
     97     "dev.radroots.contract.config-version" = toString buildInfo.contractVersions.config;
     98     "dev.radroots.contract.provider-version" = toString buildInfo.contractVersions.provider;
     99     "dev.radroots.contract.state-version" = toString buildInfo.contractVersions.state;
    100     "dev.radroots.contract.status-version" = toString buildInfo.contractVersions.status;
    101     "dev.radroots.mount.config" = "/etc/radroots/services/${serviceName}";
    102     "dev.radroots.mount.config.mode" = "read-only";
    103     "dev.radroots.mount.credentials" = "/etc/radroots/secrets/services/${serviceName}";
    104     "dev.radroots.mount.credentials.mode" = "read-only";
    105     "dev.radroots.mount.runtime" = "/run/radroots/services/${serviceName}";
    106     "dev.radroots.mount.runtime.mode" = "read-write";
    107     "dev.radroots.mount.state" = "/var/lib/radroots/services/${serviceName}";
    108     "dev.radroots.mount.state.mode" = "read-write";
    109     "dev.radroots.rootfs" = "read-only-compatible";
    110     "org.opencontainers.image.description" = "Hardened ${serviceName} service image";
    111     "org.opencontainers.image.licenses" = package.passthru.radrootsServicePackage.serviceLicense;
    112     "org.opencontainers.image.revision" = buildInfo.serviceCommit;
    113     "org.opencontainers.image.title" = serviceName;
    114     "org.opencontainers.image.version" = buildInfo.serviceVersion;
    115   };
    116 in
    117 pkgs.dockerTools.buildLayeredImage {
    118   name = imageName;
    119   tag = buildInfo.serviceVersion;
    120   created = "1970-01-01T00:00:01Z";
    121   maxLayers = 2;
    122   contents = [
    123     package
    124     pkgs.dockerTools.caCertificates
    125   ];
    126   config = {
    127     User = user;
    128     Entrypoint = [ "${package}/bin/${binaryName}" ];
    129     WorkingDir = "/";
    130     Env = [ "SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt" ];
    131     StopSignal = "SIGTERM";
    132     Labels = labels;
    133   };
    134   passthru.radrootsServiceOci = {
    135     schema = "radroots.service-oci.v1";
    136     schemaVersion = 1;
    137     inherit
    138       buildInfo
    139       imageName
    140       labels
    141       mountPaths
    142       serviceName
    143       user
    144       ;
    145     entrypoint = "${package}/bin/${binaryName}";
    146   };
    147   meta = {
    148     description = "Hardened rootless OCI image for ${serviceName}";
    149     platforms = [
    150       "x86_64-linux"
    151     ];
    152   };
    153 }