diff --git a/flake.lock b/flake.lock index efa8062..bc72556 100644 --- a/flake.lock +++ b/flake.lock @@ -59,11 +59,11 @@ ] }, "locked": { - "lastModified": 1779533061, - "narHash": "sha256-orWNYXtYURhEj3X4+xGMAhaEcKRvwXqTtJ8x2jV/M+Q=", + "lastModified": 1780368078, + "narHash": "sha256-tLzA5XveUF4PfuKNz3KuhmVhuME3PX5zvtFa17hhQPU=", "ref": "refs/heads/main", - "rev": "b818e345ec4470e4b3e335bd2f864183c512116d", - "revCount": 13, + "rev": "1626405d46ff3595b91c9e2d3ed9399f67c18b83", + "revCount": 15, "type": "git", "url": "https://git.oleks.space/oleks/fleet-pins" }, diff --git a/flake.nix b/flake.nix index 2b8c122..d0e0d5e 100644 --- a/flake.nix +++ b/flake.nix @@ -28,9 +28,13 @@ wrap = name: pkgs: args: (builders pkgs).${name} args; + imageLayers = import ./lib/image-layers.nix; in { mkParityBuilders = builders; + # Pkgs-independent nix2container layer-chain helper (lib/image-layers.nix): + # parity.lib.foldImageLayers buildLayer [ { deps = …; } … ] + inherit (imageLayers) foldImageLayers; mkPyPiWheelPublish = wrap "mkPyPiWheelPublish"; mkPyPiWheelPublishMulti = wrap "mkPyPiWheelPublishMulti"; mkS390xNpmPublish = wrap "mkS390xNpmPublish"; @@ -60,8 +64,15 @@ text = ''exec bash ${./ci/pipeline-doctor.sh} "$@"''; }; - # Smoke check: instantiate every builder with stub args so the apps eval. + # Smoke check: instantiate a builder with stub args so the apps eval, and + # exercise foldImageLayers with a stub buildLayer so its contract (each + # layer gets reproducible=false + the prior layers) can't silently break. builders = import ./lib/builders.nix { inherit pkgs; }; + imageLayers = import ./lib/image-layers.nix; + layerProbe = imageLayers.foldImageLayers (c: c) [ + { deps = [ pkgs.hello ]; } + { deps = [ pkgs.coreutils ]; } + ]; smoke = pkgs.runCommand "parity-lib-smoke" { } '' : "${ builtins.toString ( @@ -74,6 +85,9 @@ ) ) }" + ${lib.optionalString ( + builtins.length layerProbe != 2 || (builtins.elemAt layerProbe 1).reproducible + ) ''echo "foldImageLayers contract broken" >&2; exit 1''} touch $out ''; in @@ -90,6 +104,8 @@ }; checks.smoke = smoke; + + formatter = pkgs.nixfmt-rfc-style; } ); } diff --git a/lib/image-layers.nix b/lib/image-layers.nix new file mode 100644 index 0000000..8770411 --- /dev/null +++ b/lib/image-layers.nix @@ -0,0 +1,37 @@ +# Pkgs-independent nix2container layer helpers, shared across the parity image +# repos (ii-agent, ii-researcher, temporal-based-ci, mempalace image, +# ComfyUI, …) so the reproducible=false rationale lives in exactly one place. +{ + # foldImageLayers buildLayer layers + # + # buildLayer : nix2container's buildLayer function. Pass whichever attr the + # consumer's nix2container input exposes — + # `n2c.nix2container.buildLayer` or `n2c.buildLayer`. + # layers : list of buildLayer component attrsets (deps / copyToRoot / + # perms / …) in base→top order. + # + # Each layer is built referencing all prior layers, with reproducible = false. + # That is a DELIBERATE choice: it materialises each layer tar into the store so + # the image streams verbatim from any host (remote-builder + binary-cache safe) + # and avoids the cross-host "Digest did not match" that non-reproducible layer + # deps (fenix rust, libllvm, …) otherwise trigger via nix2container's lazy tar + # regeneration. Parity is asserted at the published digest, not byte-identical + # tars — mkNix2ContainerPublish enforces that contract downstream. + foldImageLayers = + buildLayer: layers: + let + mergeToLayer = + priorLayers: component: + priorLayers + ++ [ + (buildLayer ( + component + // { + layers = priorLayers; + reproducible = false; + } + )) + ]; + in + builtins.foldl' mergeToLayer [ ] layers; +}