├── .editorconfig ├── .envrc ├── .github └── workflows │ └── push.yml ├── .gitignore ├── LICENSE ├── README.md ├── default.nix ├── image.nix ├── nix ├── default.nix ├── sources.json └── sources.nix ├── overlay.nix ├── scripts ├── bash-tmate ├── export-profile ├── image-update ├── run-tests └── start-tmate ├── shell.nix ├── static-root-files └── etc │ ├── bashrc │ ├── group │ ├── nix │ └── nix.conf │ ├── nsswitch.conf │ ├── passwd │ └── shadow └── tests ├── curl ├── .dockerignore ├── Dockerfile ├── default.nix └── driver ├── minimal ├── .dockerignore ├── Dockerfile ├── default.nix └── driver └── prefetching ├── .dockerignore ├── Dockerfile ├── default.nix └── driver /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://EditorConfig.org 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | charset = utf-8 9 | indent_size = 2 10 | indent_style = space 11 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use nix 2 | -------------------------------------------------------------------------------- /.github/workflows/push.yml: -------------------------------------------------------------------------------- 1 | name: Image update 2 | on: 3 | push: 4 | branches: 5 | - master 6 | 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | schedule: 12 | # Every hour at the 47th minute (randomly chosen) 13 | - cron: '47 * * * *' 14 | 15 | # Allow triggering manually from the Actions Tab 16 | workflow_dispatch: 17 | 18 | 19 | jobs: 20 | image-update: 21 | name: Update images 22 | runs-on: ubuntu-latest 23 | strategy: 24 | matrix: 25 | channel: [ "nixos-23.05" ] #, "nixos-22.11", "nixos-22.05", "nixos-21.11", "nixos-21.05", "nixos-20.09"] 26 | fail-fast: false 27 | steps: 28 | - uses: actions/checkout@v2 29 | - uses: cachix/install-nix-action@v20 30 | with: 31 | nix_path: nixpkgs=channel:nixos-unstable 32 | - uses: cachix/cachix-action@v12 33 | with: 34 | name: nix-docker-base 35 | signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}' 36 | # - name: Running non-pushing updater 37 | # if: github.event_name == 'pull_request' 38 | # run: nix-shell --run 'scripts/image-update test "$PWD" ${{ matrix.channel }} 16' 39 | # env: 40 | # REGISTRY_USER: niteo 41 | - name: Running pushing updater 42 | # Only push image updates to DockerHub for master commits 43 | # if: github.event_name == 'pull_request' 44 | run: nix-shell --run 'scripts/image-update push "$PWD" ${{ matrix.channel }} 16' 45 | env: 46 | REGISTRY_USER: niteo 47 | REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Nix 2 | result 3 | result-* 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 zimbatm and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEPRECATED! 2 | 3 | This project relied on https://channels.nix.gsc.io/ to get commits to nixos channels. 4 | This website is no longer updated so no new Docker images are built and uploaded to Docker Hub. 5 | If you want to built one image manually, see https://github.com/teamniteo/nix-docker-base/pull/23. 6 | 7 | We are no longer maintaining this project. Reach out if you want to take over. 8 | 9 | # nix-docker-base: Nix Docker base images for fast and minimal builds 10 | 11 | This project automatically generates Docker images for nixpkgs channels. The images come with a prefetched nixpkgs, corresponding to the image tag, which is the nixpkgs commit hash. All basic Nix utilities are preinstalled, including [Cachix](https://cachix.org/). Also included is the `export-profile` script, allowing super minimal images via [multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/). 12 | 13 | 14 | See the [Usage](#usage) section for how to use it in your project. 15 | 16 | ## Features 17 | 18 | ### Prefetched nixpkgs tarballs 19 | 20 | All images come prefetched with the [nixpkgs](https://github.com/NixOS/nixpkgs) version corresponding to the image tag. So the image `niteo/nixpkgs-nixos-20.03:14006b724f3d1f25ecf38238ee723d38b0c2f4ce` contains a prefetched tarball of [14006b724f3d](https://github.com/NixOS/nixpkgs/tree/14006b724f3d1f25ecf38238ee723d38b0c2f4ce). This allows Nix builds that pin nixpkgs to that version to start quickly, without having to first fetch and unpack a tarball. 21 | 22 | ### Preinstalled dependencies 23 | 24 | All images come preinstalled with a basic set of dependencies needed for working with Nix. This currently includes [Cachix](https://cachix.org/) and all dependencies of Nix, but may be expanded in the future as the need arises. Since the intent is to use these images as the first stage in a multi-stage build, they won't influence the final image size, allowing the addition of more tools without a significant cost. 25 | 26 | These dependencies notably come from the very nixpkgs version that is prefetched. If you need these tools or their dependencies in a Nix build, this saves you the cost of having to download them. 27 | 28 | ### Automatic channel updates 29 | 30 | Every hour, [a GitHub Action](https://github.com/niteoweb/nix-docker-base/actions) runs to detect any nixpkgs channel updates, in which case a new Docker image is built and pushed to DockerHub with the corresponding tag. 31 | 32 | Additionally, if this repository changes how images are built, the image tags corresponding to the latest channel versions are updated to incorporate these changes. This is the only way in which tagged images are updated, meaning once a nixpkgs channel commit is outdated, its image won't get updated anymore. So if this repository receives an update, you need to update nixpkgs to the latest version of the channel. 33 | 34 | ### Minimal multi-stage builds 35 | 36 | All images contain the `export-profile` utility, which allows easy creation of a final stage in Docker [multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/). The resulting image then contains only exactly the dependencies needed to run the programs you specify, nothing else. 37 | 38 | ## Usage 39 | 40 | ### Pinning nixpkgs 41 | 42 | To use this for your project, you should ensure that the prefetched nixpkgs tarball can be used, such that builds can start as fast as possible. This requires that you [pin nixpkgs](https://nixos.wiki/wiki/FAQ/Pinning_Nixpkgs) to the nixpkgs commit of the channel that you wish to use. Specifically, the Nix expression that evaluates to the prefetched version is 43 | ```nix 44 | fetchTarball { 45 | name = "nixpkgs-src"; 46 | url = "https://github.com/NixOS/nixpkgs/archive/.tar.gz"; 47 | sha256 = ""; 48 | } 49 | ``` 50 | 51 | Note that choosing the name as `nixpkgs-src` is very important, because Nix can only reuse a prefetched version if the name matches. 52 | 53 | Only Nix channels specified in channel matrix in the [push workflow](https://github.com/niteoweb/nix-docker-base/blob/master/.github/workflows/push.yml) are available, but new ones may be added over time. 54 | 55 | #### Using [Niv](https://github.com/nmattia/niv) 56 | 57 | If you use Niv to manage your nixpkgs source, you need to ensure the following: 58 | - The `nix/sources.nix` file was generated by a Niv version after [this change](https://github.com/nmattia/niv/pull/217) 59 | - The nixpkgs Niv package is named `nixpkgs`. These two points are necessary for Niv to name the tarball `nixpkgs-src` 60 | - The branch of the nixpkgs Niv package points to the nixpkgs channel you wish to use. This ensures that you don't update to unavailable commits 61 | 62 | For a new project wanting to use the `nixos-20.03` channel, this can be done with: 63 | ``` 64 | niv init 65 | niv modify nixpkgs -b nixos-20.03 66 | niv update nixpkgs 67 | ``` 68 | 69 | For regenerating the `nix/sources.nix` in an existing project, you can run 70 | ``` 71 | rm nix/sources.nix 72 | niv init 73 | ``` 74 | 75 | Finally, use the following command to check the tarballs name. It needs to end with `nixpkgs-src` for the prefetched nixpkgs to apply: 76 | ``` 77 | nix-instantiate --eval -E '(import nix/sources.nix).nixpkgs.outPath 78 | => "/nix/store/r07cldfsnr8kvkr1kpsc6jf6bibfc1mg-nixpkgs-src" 79 | ``` 80 | 81 | If it ends with `-source`, make sure to use a more recent Niv version. 82 | 83 | ### Nix expression 84 | 85 | To use this project, you need a Nix expression in your project that ideally exposes a single derivation as an attribute for installation. A convenient helper for this is `pkgs.buildEnv`, which allows you to build a derivation that combines multiple other derivations into one. Here is an example `default.nix`, showing how `pkgs.buildEnv` can be used to create an environment with both `pkgs.curl` and `pkgs.cacert` in it: 86 | ```nix 87 | let 88 | 89 | # Without niv 90 | pkgs = fetchTarball { 91 | name = "nixpkgs-src"; 92 | url = "https://github.com/NixOS/nixpkgs/archive/.tar.gz"; 93 | sha256 = ""; 94 | }; 95 | 96 | # With niv 97 | pkgs = (import nix/sources.nix).nixpkgs; 98 | 99 | in { 100 | myEnv = pkgs.buildEnv { 101 | name = "env"; 102 | paths = with pkgs; [ 103 | curl 104 | cacert 105 | ]; 106 | }; 107 | } 108 | ``` 109 | 110 | ### Dockerfile 111 | 112 | The base images are made available under [Niteo on DockerHub](https://hub.docker.com/u/niteo) as `niteo/nixpkgs-:`. With the Dockerfile being in the same directory as the projects `default.nix` file, you can install any exposed attribute of that file with the following basic Dockerfile structure 113 | ```Dockerfile 114 | FROM niteo/nixpkgs-: AS build 115 | # Import the project source 116 | COPY . src 117 | RUN \ 118 | # Install the program to propagate to the final image 119 | nix-env -f src -iA myEnv \ 120 | # Exports a root directory structure containing all dependencies 121 | # installed with nix-env under /run/profile 122 | && export-profile /dist 123 | 124 | # Second Docker stage, we start with a completely empty image 125 | FROM scratch 126 | # Copy the /dist root folder from the previous stage into this one 127 | COPY --from=build /dist / 128 | # Set PATH so Nix binaries can be found 129 | ENV PATH=/run/profile/bin 130 | ``` 131 | 132 | #### What `export-profile` does 133 | 134 | The main idea of `export-profile ` is to export the default `nix-env` profile with all its dependencies into ``, such that the next build stage only needs to initialize its root directory with `` from the previous stage. In more details, the script currently does: 135 | - Symlink to the default `nix-env` profile from `/run/profile` 136 | - If the profile contains an `etc` directory, it symlinks to it from `/etc`. This behavior mirrors NixOS, and allows for files like `/etc/bashrc` to take effect 137 | - If the profile contains a `bin/env` (usually from `pkgs.coreutils`) or `bin/sh` (usually from `pkgs.bashInteractive`), it symlinks to those from `/usr/bin/env` and `/bin/sh` respectively. These are standard POSIX executable paths. 138 | - All Nix store paths the profile depends on are copied to `/nix/store`. This ensures that any previously established symlinks actually work. 139 | 140 | #### SSL root certificates 141 | 142 | If you require binaries like `curl` in the final image, you need to make sure that they can find SSL root certificates. To do this: 143 | - Install `pkgs.cacert` in the `build` stage, either by adding it to the environment of the attribute you install, or with an additional nix-env command like 144 | ``` 145 | nix-env -f '' -iA cacert 146 | ``` 147 | - Set the `NIX_SSL_CERT_FILE` environment variable as follows in the final stage 148 | ```Dockerfile 149 | ENV NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt 150 | ``` 151 | 152 | #### Updating the Dockerfile 153 | 154 | Since the nixpkgs commit is embedded into the Dockerfile, it should be kept in sync with the nixpkgs of your Nix files to ensure it being as efficient as possible. So if you update your nixpkgs source to a newer channel commit, be sure to update it in the Dockerfile as well. 155 | 156 | If you manage your nixpkgs source with `niv`, this can be achieved automatically with the following commands: 157 | ```bash 158 | niv update nixpkgs 159 | channel=$(jq -r .nixpkgs.branch nix/sources.json) 160 | rev=$(jq -r .nixpkgs.rev nix/sources.json) 161 | sed -i "s#FROM.*AS build#FROM niteo/nixpkgs-$channel:$rev AS build#g" Dockerfile 162 | ``` 163 | 164 | ### Connecting with SSH during CI 165 | 166 | This image has built-in helpers for setting up a tmate connection to the image, useful for debugging when running in CI: 167 | 168 | - `start-tmate [maxIdle]`: Starts a tmate session, which is persisted until `maxIdle` (by default 60) seconds pass without any connection. The command only exits once this has occured. 169 | - `bash-tmate`: A drop-in replacement for bash that runs `start-tmate` when the bash command fails. Useful as a shell for CI scripts, allowing debugging in case of failures. 170 | 171 | ## Development and Contributing 172 | 173 | This section is only intended for developers/contributors of this project. Feel free to contribute by opening a PR or open issues for enquiries. 174 | 175 | ### Adding new nixpkgs channels 176 | 177 | A new channel can be added by editing the channel matrix in [push.yml](.github/workflows/push.yml) workflow to contain the one you want. 178 | 179 | ### Adding new tools to the base image 180 | 181 | New tools for the base image can be added under `Extra tools` in [image.nix](./image.nix). 182 | 183 | ### Out-of-tree requirements for forks 184 | 185 | - A [DockerHub](https://hub.docker.com/) account. Insert your username for `REGISTRY_USER` in the [push.yml](.github/workflows/push.yml) workflow, and set up the password as a `REGISTRY_PASSWORD` secret for the repository. This is of course needed to update images on DockerHub. Other container registries could work too, but the code needs to be adjusted for that. 186 | - A [Cachix](https://cachix.org/) cache for speeding up CI. Set the Cachix name under the `cachix-action`s in the [push.yml](.github/workflows/push.yml) workflow, and add the signing key as the `CACHIX_SIGNING_KEY` secret in the repository. 187 | 188 | ## Related projects 189 | 190 | - This project was originally forked from https://github.com/nix-community/docker-nixpkgs, but almost no code remains unchanged. 191 | - The official Nix docker images at https://github.com/nixos/docker. 192 | - [Nixery](https://nixery.dev/) is a pretty cool service that builds docker images from nixpkgs attributes on the fly. 193 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | {}: 2 | let 3 | inherit (import ./nix) pkgs; 4 | inherit (pkgs) lib; 5 | 6 | in { 7 | inherit pkgs; 8 | 9 | devShell = pkgs.mkShell { 10 | buildInputs = [ 11 | pkgs.skopeo 12 | pkgs.jq 13 | pkgs.gnused 14 | ]; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /image.nix: -------------------------------------------------------------------------------- 1 | { nixpkgsRev, nixpkgsSha, nixHash ? null }: 2 | let 3 | nixpkgs = fetchTarball { 4 | # Rename the derivation to accomodate the standard niv naming of nixpkgs 5 | name = "nixpkgs-src"; 6 | url = "https://github.com/NixOS/nixpkgs/archive/${nixpkgsRev}.tar.gz"; 7 | sha256 = nixpkgsSha; 8 | }; 9 | 10 | 11 | pkgs = import nixpkgs { 12 | config = {}; 13 | overlays = [ (import ./overlay.nix) ]; 14 | }; 15 | inherit (pkgs) lib; 16 | 17 | exportProfile = pkgs.writeShellScriptBin "export-profile" (builtins.readFile ./scripts/export-profile); 18 | startTmate = pkgs.writeShellScriptBin "start-tmate" (builtins.readFile ./scripts/start-tmate); 19 | bashTmate = pkgs.writeShellScriptBin "bash-tmate" (builtins.readFile ./scripts/bash-tmate); 20 | 21 | # All packages available in the base image 22 | env = pkgs.buildEnv { 23 | name = "base-env"; 24 | paths = with pkgs; [ 25 | # Custom things 26 | exportProfile 27 | startTmate 28 | bashTmate 29 | tmate 30 | 31 | # Very basics 32 | coreutils 33 | bashInteractive 34 | 35 | # Nix and runtime dependencies of it 36 | nix 37 | cacert 38 | gitReallyMinimal 39 | gnutar 40 | gzip 41 | openssh 42 | xz 43 | 44 | # Extra tools 45 | cachix 46 | less 47 | gnused 48 | gnugrep 49 | ]; 50 | }; 51 | 52 | # Dynamic files in the filesystem root of the base image 53 | dynamicRootFiles = pkgs.runCommandNoCC "dynamic-root-files" {} '' 54 | mkdir -p $out/run $out/usr/bin $out/bin $out/lib64 55 | cp -R -Ls ${env} $out/run/profile 56 | cp -R -Ls ${env}/etc $out/etc 57 | ln -s ${pkgs.coreutils}/bin/env $out/usr/bin/env 58 | ln -s ${pkgs.bashInteractive}/bin/sh $out/bin/sh 59 | 60 | # So that this image can be used as a GitHub Action container directly 61 | # Needed because it calls its own (non-nix-patched) node binary which uses 62 | # this dynamic linker path. See also the LD_LIBRARY_PATH assignment below, 63 | # which provides the necessary libraries for that binary 64 | ln -s ${pkgs.glibc}/lib/ld-linux-x86-64.so.2 $out/lib64/ld-linux-x86-64.so.2 65 | ''; 66 | 67 | # All contents of the root filesystem 68 | rootContents = [ 69 | ./static-root-files 70 | dynamicRootFiles 71 | ]; 72 | 73 | # The contents of the Nix database in the built container 74 | nixDbContents = [ 75 | # We need to include this such that our environment and stuff doesn't get GC'd 76 | # and for the environments derivations not to be refetched 77 | dynamicRootFiles 78 | # We also need the nixpkgs source to be in the Nix db, 79 | # which allows it to be used by Nix expressions 80 | nixpkgs 81 | ]; 82 | 83 | # fix for: 84 | # `nix-instantiate: /nix/store/ikl21vjfq900ccbqg1xasp83kadw6q8y-glibc-2.32-46/lib/libc.so.6: version `GLIBC_2.33' not found (required by /nix/store/j132k1ncfn6gjfd2f5s1gz37170rch4h-gcc-11.3.0-lib/lib/libstdc++.so.6)` 85 | patchGLIBC = '' 86 | export LD_LIBRARY_PATH=${pkgs.stdenv.cc.cc.lib}/lib/:$LD_LIBRARY_PATH 87 | ''; 88 | 89 | # This section is copied from https://github.com/NixOS/nixpkgs/blob/7a100ad9543687d046cfeeb5156dfaa697e1abbd/pkgs/build-support/docker/default.nix#L39-L57 90 | # but adjusted to support additional contents 91 | extraCommands = '' 92 | echo "Generating the nix database..." 93 | echo "Warning: only the database of the deepest Nix layer is loaded." 94 | echo " If you want to use nix commands in the container, it would" 95 | echo " be better to only have one layer that contains a nix store." 96 | 97 | export NIX_REMOTE=local?root=$PWD 98 | # A user is required by nix 99 | # https://github.com/NixOS/nix/blob/9348f9291e5d9e4ba3c4347ea1b235640f54fd79/src/libutil/util.cc#L478 100 | export USER=nobody 101 | ${pkgs.nix}/bin/nix-store --load-db < ${pkgs.closureInfo { rootPaths = nixDbContents; }}/registration 102 | 103 | mkdir -p nix/var/nix/gcroots/docker/ 104 | for i in ${lib.concatStringsSep " " nixDbContents}; do 105 | ln -s $i nix/var/nix/gcroots/docker/$(basename $i) 106 | done; 107 | 108 | # make sure /tmp exists 109 | mkdir -m 1777 tmp 110 | '' + patchGLIBC; 111 | in pkgs.dockerTools.buildImage { 112 | name = "nixpkgs"; 113 | # Doesn't make images have a creation date of 1970 114 | created = "now"; 115 | 116 | contents = rootContents; 117 | inherit extraCommands; 118 | 119 | config = { 120 | Cmd = [ "bash" ]; 121 | WorkingDir = "/root"; 122 | Env = [ 123 | # So that nix-shell doesn't fetch its own bash 124 | "NIX_BUILD_SHELL=/run/profile/bin/bash" 125 | # The image itself pins nixpkgs, expose this for convenience 126 | "NIX_PATH=nixpkgs=${nixpkgs}" 127 | # Make nix-env installs work 128 | "PATH=/nix/var/nix/profiles/default/bin:/run/profile/bin:/bin" 129 | # Needed for curl and co. 130 | "NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt" 131 | # Docker apparently doesn't set this 132 | "USER=root" 133 | # Needed by some nix commands like nix-store to display output 134 | "PAGER=/run/profile/bin/less" 135 | # By default, the linker added in dynamicRootFiles can only find glibc 136 | # libraries, but the node binary from the GitHub Actions runner also 137 | # depends on libstdc++.so.6, which is glibc/stdenv. Using LD_LIBRARY_PATH 138 | # is the easiest way to inject this dependency 139 | "LD_LIBRARY_PATH=${lib.makeLibraryPath [ pkgs.stdenv.cc.cc ]}" 140 | ]; 141 | } // lib.optionalAttrs (nixHash != null) { 142 | # Embed a nixHash into the image if given, allowing later extraction via skopeo inspect 143 | # By embedding such a hash, we can know whether a commit-specific image on 144 | # DockerHub needs to be updated after changes made to the image builder 145 | # See scripts/image-update for how this hash is generated 146 | Labels.NixHash = nixHash; 147 | }; 148 | } 149 | -------------------------------------------------------------------------------- /nix/default.nix: -------------------------------------------------------------------------------- 1 | let 2 | sources = import ./sources.nix; 3 | pkgs = import sources.nixpkgs { 4 | config = {}; 5 | overlays = [ (import ../overlay.nix) ]; 6 | }; 7 | in { 8 | inherit pkgs; 9 | } 10 | -------------------------------------------------------------------------------- /nix/sources.json: -------------------------------------------------------------------------------- 1 | { 2 | "nixpkgs": { 3 | "branch": "nixos-unstable", 4 | "description": "Nix Packages collection", 5 | "homepage": null, 6 | "owner": "NixOS", 7 | "repo": "nixpkgs", 8 | "rev": "c59ea8b8a0e7f927e7291c14ea6cd1bd3a16ff38", 9 | "sha256": "1ak7jqx94fjhc68xh1lh35kh3w3ndbadprrb762qgvcfb8351x8v", 10 | "type": "tarball", 11 | "url": "https://github.com/NixOS/nixpkgs/archive/c59ea8b8a0e7f927e7291c14ea6cd1bd3a16ff38.tar.gz", 12 | "url_template": "https://github.com///archive/.tar.gz" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /nix/sources.nix: -------------------------------------------------------------------------------- 1 | # This file has been generated by Niv. 2 | 3 | let 4 | 5 | # 6 | # The fetchers. fetch_ fetches specs of type . 7 | # 8 | 9 | fetch_file = pkgs: spec: 10 | if spec.builtin or true then 11 | builtins_fetchurl { inherit (spec) url sha256; } 12 | else 13 | pkgs.fetchurl { inherit (spec) url sha256; }; 14 | 15 | fetch_tarball = pkgs: name: spec: 16 | let 17 | ok = str: ! builtins.isNull (builtins.match "[a-zA-Z0-9+-._?=]" str); 18 | # sanitize the name, though nix will still fail if name starts with period 19 | name' = stringAsChars (x: if ! ok x then "-" else x) "${name}-src"; 20 | in 21 | if spec.builtin or true then 22 | builtins_fetchTarball { name = name'; inherit (spec) url sha256; } 23 | else 24 | pkgs.fetchzip { name = name'; inherit (spec) url sha256; }; 25 | 26 | fetch_git = spec: 27 | builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; }; 28 | 29 | fetch_local = spec: spec.path; 30 | 31 | fetch_builtin-tarball = name: throw 32 | ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. 33 | $ niv modify ${name} -a type=tarball -a builtin=true''; 34 | 35 | fetch_builtin-url = name: throw 36 | ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`. 37 | $ niv modify ${name} -a type=file -a builtin=true''; 38 | 39 | # 40 | # Various helpers 41 | # 42 | 43 | # The set of packages used when specs are fetched using non-builtins. 44 | mkPkgs = sources: 45 | let 46 | sourcesNixpkgs = 47 | import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) {}; 48 | hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; 49 | hasThisAsNixpkgsPath = == ./.; 50 | in 51 | if builtins.hasAttr "nixpkgs" sources 52 | then sourcesNixpkgs 53 | else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then 54 | import {} 55 | else 56 | abort 57 | '' 58 | Please specify either (through -I or NIX_PATH=nixpkgs=...) or 59 | add a package called "nixpkgs" to your sources.json. 60 | ''; 61 | 62 | # The actual fetching function. 63 | fetch = pkgs: name: spec: 64 | 65 | if ! builtins.hasAttr "type" spec then 66 | abort "ERROR: niv spec ${name} does not have a 'type' attribute" 67 | else if spec.type == "file" then fetch_file pkgs spec 68 | else if spec.type == "tarball" then fetch_tarball pkgs name spec 69 | else if spec.type == "git" then fetch_git spec 70 | else if spec.type == "local" then fetch_local spec 71 | else if spec.type == "builtin-tarball" then fetch_builtin-tarball name 72 | else if spec.type == "builtin-url" then fetch_builtin-url name 73 | else 74 | abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; 75 | 76 | # If the environment variable NIV_OVERRIDE_${name} is set, then use 77 | # the path directly as opposed to the fetched source. 78 | replace = name: drv: 79 | let 80 | saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name; 81 | ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; 82 | in 83 | if ersatz == "" then drv else ersatz; 84 | 85 | # Ports of functions for older nix versions 86 | 87 | # a Nix version of mapAttrs if the built-in doesn't exist 88 | mapAttrs = builtins.mapAttrs or ( 89 | f: set: with builtins; 90 | listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) 91 | ); 92 | 93 | # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 94 | range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1); 95 | 96 | # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 97 | stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); 98 | 99 | # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 100 | stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); 101 | concatStrings = builtins.concatStringsSep ""; 102 | 103 | # fetchTarball version that is compatible between all the versions of Nix 104 | builtins_fetchTarball = { url, name, sha256 }@attrs: 105 | let 106 | inherit (builtins) lessThan nixVersion fetchTarball; 107 | in 108 | if lessThan nixVersion "1.12" then 109 | fetchTarball { inherit name url; } 110 | else 111 | fetchTarball attrs; 112 | 113 | # fetchurl version that is compatible between all the versions of Nix 114 | builtins_fetchurl = { url, sha256 }@attrs: 115 | let 116 | inherit (builtins) lessThan nixVersion fetchurl; 117 | in 118 | if lessThan nixVersion "1.12" then 119 | fetchurl { inherit url; } 120 | else 121 | fetchurl attrs; 122 | 123 | # Create the final "sources" from the config 124 | mkSources = config: 125 | mapAttrs ( 126 | name: spec: 127 | if builtins.hasAttr "outPath" spec 128 | then abort 129 | "The values in sources.json should not have an 'outPath' attribute" 130 | else 131 | spec // { outPath = replace name (fetch config.pkgs name spec); } 132 | ) config.sources; 133 | 134 | # The "config" used by the fetchers 135 | mkConfig = 136 | { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null 137 | , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile) 138 | , pkgs ? mkPkgs sources 139 | }: rec { 140 | # The sources, i.e. the attribute set of spec name to spec 141 | inherit sources; 142 | 143 | # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers 144 | inherit pkgs; 145 | }; 146 | 147 | in 148 | mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); } 149 | -------------------------------------------------------------------------------- /overlay.nix: -------------------------------------------------------------------------------- 1 | final: prev: { 2 | 3 | scripts = prev.callPackage ./scripts {}; 4 | 5 | # gitMinimal still ships with perl and python 6 | gitReallyMinimal = ( 7 | prev.git.override { 8 | perlSupport = false; 9 | pythonSupport = false; 10 | withManual = false; 11 | withpcre2 = false; 12 | } 13 | ).overrideAttrs ( 14 | _: { 15 | # installCheck is broken when perl is disabled 16 | doInstallCheck = false; 17 | } 18 | ); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /scripts/bash-tmate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | bash -eo pipefail "$@" 3 | exitCode=$? 4 | if [[ "$exitCode" -ne 0 ]]; then 5 | echo "Command failed ($exitCode): bash ${@@Q}" 6 | start-tmate 7 | exit "$exitCode" 8 | fi 9 | -------------------------------------------------------------------------------- /scripts/export-profile: -------------------------------------------------------------------------------- 1 | set -e 2 | root=$1 3 | # Same default profile as nix-env 4 | profile=$(realpath ''${NIX_PROFILE:-~/.nix-profile}) 5 | 6 | if [[ -z "$1" ]]; then 7 | echo "Usage: export-profile [ROOTDIR]" >&2 8 | echo " exports everything installed with nix-env to the given directory," >&2 9 | echo " suitable as the root of the next stage in a multi-stage build." >&2 10 | exit 1 11 | elif [[ -e "$root" ]]; then 12 | echo "The directory given to export-profile needs to not exist already" >&2 13 | exit 1 14 | fi 15 | 16 | # The standard Nix locations for profiles are either /run/current-system/sw on 17 | # NixOS or /nix/var/nix/profiles/per-user/ for user-level profiles 18 | # But these are both long and don't really fit (we're neither on NixOS nor will 19 | # there be Nix installed). So choose /run/profile to keep this short 20 | targetProfile="$root"/run/profile 21 | 22 | # Link /run/profile to the Nix profile 23 | echo "Linking $targetProfile to $profile" >&2 24 | mkdir -p "$(dirname "$targetProfile")" 25 | # Apparently Docker somehow deduplicates directory symlinks, causing problems 26 | # down the line. So instead of symlinking the directory directly, we symlink all 27 | # the files recursively instead. See below for the -Ls flags 28 | # 29 | # This cp returns 1 if any symlink points to a non-existant destination, so we 30 | # ignore its exit code. This does unfortunately also ignore other errors 31 | # Note that it's not possible to just remove invalid symlinks, as Nix would complain about 32 | # a store path having changed contents in the nix-store --export later 33 | cp -R -Ls "$profile" "$targetProfile" || true 34 | 35 | # If the profile contains an etc directory, link all of its files to the roots /etc 36 | # 37 | # Note that the -Ls flags are used to replicate the directory structure of etc 38 | # with symlinks for all files. This avoids conflicts with other files Docker may 39 | # put in /etc 40 | if [[ -e "$profile"/etc ]]; then 41 | echo "Linking from $root/etc to $profile/etc" >&2 42 | # See in above cp why the error is ignored 43 | cp -R -Ls "$profile"/etc "$root"/etc || true 44 | fi 45 | 46 | # If the profile contains bin/env, link to that from /usr/bin/env for POSIX 47 | if [[ -x "$profile"/bin/env ]]; then 48 | echo "Linking from $root/usr/bin/env to $profile/bin/env" >&2 49 | mkdir -p "$root"/usr/bin 50 | ln -s "$profile"/bin/env "$root"/usr/bin/env 51 | fi 52 | 53 | # If the profile contains bin/sh, link to that from /bin/sh for POSIX 54 | if [[ -x "$profile"/bin/sh ]]; then 55 | echo "Linking from $root/bin/sh to $profile/bin/sh" >&2 56 | mkdir -p "$root"/bin 57 | ln -s "$profile"/bin/sh "$root"/bin/sh 58 | fi 59 | 60 | # We also need the profiles closure in the new root for all symlinks to be valid 61 | echo "Copying all the profiles Nix dependencies to $root" >&2 62 | nix-store --export $(nix-store -qR "$profile") | \ 63 | NIX_REMOTE=local?root="$root" nix-store --import >/dev/null 64 | 65 | # nix-store --import also creates /nix/var, but we don't need this as Nix 66 | # won't be available in the final stage, so we only need the store 67 | rm -rf "$root/nix/var" 68 | 69 | echo "Finished Nix profile export to $root" >&2 70 | -------------------------------------------------------------------------------- /scripts/image-update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | # Arguments: 5 | # - [test|push] 6 | # - root directory 7 | # - Channel name 8 | # - Number of channel updates to ensure 9 | # Env vars: 10 | # - REGISTRY_USER 11 | # - REGISTRY_PASSWORD 12 | case "$1" in 13 | test) 14 | testing=1 15 | ;; 16 | push) 17 | testing= 18 | ;; 19 | *) 20 | echo "Unknown operation: $1" >&2 21 | ;; 22 | esac 23 | root=$2 24 | channel=$3 25 | count=$4 26 | 27 | calcNixpkgsSha() { 28 | commit=$1 29 | nix-prefetch-url --name nixpkgs-src --unpack "https://github.com/NixOS/nixpkgs/archive/$commit.tar.gz" 30 | } 31 | 32 | fetchExistingHash() { 33 | commit=$1 34 | name=$REGISTRY_USER/nixpkgs-$channel:$commit 35 | dest=docker://docker.io/$name 36 | 37 | echo "Inspecting whether the image already exists.." >&2 38 | if inspectionJson=$(skopeo inspect --insecure-policy "$dest"); then 39 | echo "Image does exist already" >&2 40 | jq -r '.Labels.NixHash' <<< "$inspectionJson" 41 | return 0 42 | else 43 | # TODO: Check whether it doesn't exist or if it's another error 44 | echo "Error inspecting the image, assuming it doesn't exist" >&2 45 | return 1 46 | fi 47 | } 48 | 49 | calcWantedHash() { 50 | commit=$1 51 | nixpkgsSha=$2 52 | 53 | echo "Calculating wanted image nix hash by instantiating the image derivation.." >&2 54 | # nix-instantiate hashes all inputs to the build, so if any inputs change, the hash changes too 55 | if ! drv=$(nix-instantiate "$root/image.nix" --argstr nixpkgsRev "$commit" --argstr nixpkgsSha "$nixpkgsSha"); then 56 | echo "Error instantiating the image" >&2 57 | return 1 58 | fi 59 | wantedNixHash=$(echo "$drv" | cut -d/ -f4- | cut -d- -f1) 60 | echo "Successfully calculated wanted image nix hash to be $wantedNixHash" >&2 61 | 62 | echo "$wantedNixHash" 63 | } 64 | 65 | buildTestPushImage() { 66 | commit=$1 67 | nixpkgsSha=$2 68 | nixHash=$3 69 | name=$REGISTRY_USER/nixpkgs-$channel:$commit 70 | dest=docker://docker.io/$name 71 | 72 | echo "Building the image.." >&2 73 | # Here we specifically don't reuse the previously instantiated derivation, 74 | # because now we embed the hash into the derivation itself, which would change 75 | # the hash again. Since this hash however doesn't influence the build, we can 76 | # ignore this hash change 77 | if ! out=$(nix-build "$root/image.nix" --no-out-link --argstr nixpkgsRev "$commit" --argstr nixpkgsSha "$nixpkgsSha" --argstr nixHash "$nixHash"); then 78 | echo "Error building the image" >&2 79 | return 1 80 | fi 81 | echo "Image built successfully" >&2 82 | 83 | echo "Testing image.." >&2 84 | if ! "$root/scripts/run-tests" "$root" "$out" "$commit" "$nixpkgsSha"; then 85 | echo "Image tests failed" >&2 86 | return 1 87 | fi 88 | 89 | if [[ -n "$testing" ]]; then 90 | echo "Not pushing the image because only testing" >&2 91 | return 0 92 | fi 93 | 94 | echo "Pushing the image.." >&2 95 | src=docker-archive://$out 96 | if ! skopeo copy --insecure-policy --dest-creds "$REGISTRY_USER:$REGISTRY_PASSWORD" "$src" "${dest}"; then 97 | echo "Error pushing the image" >&2 98 | return 1 99 | fi 100 | echo "Successfully pushed the image" >&2 101 | } 102 | 103 | isFirst=1 104 | 105 | processEntry() { 106 | if [[ -n "$isFirst" ]]; then 107 | first=1 108 | else 109 | first= 110 | fi 111 | isFirst= 112 | 113 | read commit commitDate advanceDate <<< "$entry" 114 | commit="c7a18f89ef1dc423f57f3de9bd5d9355550a5d15" 115 | echo "Processing commit $commit which $channel advanced to at $(date --date="@$advanceDate")" >&2 116 | 117 | if [[ -n "$testing" && -n "$first" ]]; then 118 | 119 | echo "Only testing first entry" 120 | nixpkgsSha=$(calcNixpkgsSha "$commit") 121 | if buildTestPushImage "$commit" "$nixpkgsSha" ""; then 122 | return 0 123 | else 124 | return 1 125 | fi 126 | 127 | elif [[ -z "$testing" ]]; then 128 | 129 | if existingHash=$(fetchExistingHash "$commit"); then 130 | 131 | if [[ -n "$first" ]]; then 132 | 133 | nixpkgsSha=$(calcNixpkgsSha "$commit") 134 | if wantedHash=$(calcWantedHash "$commit" "$nixpkgsSha"); then 135 | # If an image exists already, we compare the hash it has embedded to the one 136 | # we calculated for the inputs we have. If they are the same, we don't need to 137 | # update the image. If they're not the same, something changed and an update 138 | # is needed 139 | if [[ "$existingHash" != "$wantedHash" ]]; then 140 | buildTestPushImage "$commit" "$nixpkgsSha" "$wantedHash" 141 | else 142 | echo "Image exists already, and it's the latest one, but the hash didn't change, so we don't update it" >&2 143 | fi 144 | fi 145 | else 146 | echo "Image exists already, and it's not the latest one, so we don't update it" >&2 147 | fi 148 | 149 | else 150 | 151 | nixpkgsSha=$(calcNixpkgsSha "$commit") 152 | if wantedHash=$(calcWantedHash "$commit" "$nixpkgsSha"); then 153 | buildTestPushImage "$commit" "$nixpkgsSha" "$wantedHash" 154 | fi 155 | 156 | fi 157 | 158 | echo "" >&2 159 | 160 | fi 161 | 162 | 163 | 164 | } 165 | 166 | 167 | curl -sSf "https://channels.nix.gsc.io/$channel/history-v2" \ 168 | | tail -n"$count" \ 169 | | tac \ 170 | | while read -r entry; do 171 | processEntry 172 | done 173 | 174 | -------------------------------------------------------------------------------- /scripts/run-tests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | # Arguments: 4 | # - root directory 5 | # - attribute to test 6 | 7 | root=$1 8 | out=$2 9 | commit=$3 10 | nixpkgsSha=$4 11 | 12 | echo "Running tests for $out.." >&2 13 | 14 | successCount=0 15 | totalCount=0 16 | 17 | echo "Loading built image into docker.." >&2 18 | if ! image=$(docker load -i "$out" | sed -n 's/^Loaded image: \(.*\)$/\1/p'); then 19 | echo "Failed to load the built image into docker" >&2 20 | exit 1 21 | fi 22 | if ! docker tag "$image" base; then 23 | echo "Failed to tag image" >&2 24 | exit 1 25 | fi 26 | echo "Successfully loaded built image into docker" >&2 27 | 28 | for testcase in "$root"/tests/*; do 29 | echo "Running testcase $testcase.." >&2 30 | totalCount=$(( totalCount + 1 )) 31 | 32 | # Copy all the test cases files into a new directory 33 | tmp=$(mktemp -d) 34 | cp -rT "$testcase" "$tmp" 35 | 36 | echo -n "$commit" > "$tmp"/nixpkgsCommit 37 | echo -n "$nixpkgsSha" > "$tmp"/nixpkgsSha 38 | 39 | echo "Running test.." >&2 40 | if ! "$testcase"/driver "$tmp"; then 41 | echo "Failed to run test" >&2 42 | continue 43 | fi 44 | echo "Successfully ran test" >&2 45 | echo "" >&2 46 | successCount=$(( successCount + 1 )) 47 | 48 | done 49 | 50 | echo "Finished running tests for $out, $successCount/$totalCount succeeded" >&2 51 | if [[ "$successCount" != "$totalCount" ]]; then 52 | exit 1 53 | fi 54 | 55 | echo "" >&2 56 | echo "" >&2 57 | -------------------------------------------------------------------------------- /scripts/start-tmate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | dir=$(mktemp -d) 5 | sock=$dir/sock 6 | log=$dir/log 7 | 8 | interval=5 9 | maxIdle=${1:-60} 10 | 11 | echo "Starting tmate session" 12 | echo "Only stopping once $maxIdle seconds pass without any connections" 13 | 14 | tmate -S "$sock" -F new-session bash > "$log" & 15 | while ! tmate -S "$sock" wait tmate-ready 2>/dev/null; do 16 | sleep 1; 17 | done 18 | 19 | trap '[[ -S "$sock" ]] && tmate -S "$sock" kill-server' EXIT 20 | 21 | idleSeconds=0 22 | while [[ -S "$sock" ]] && [[ "$idleSeconds" -le "$maxIdle" ]]; do 23 | 24 | tmate -S "$sock" display -p '#{tmate_ssh}' 25 | 26 | sleep "$interval" 27 | 28 | clientCount=$(sed -n 's/.* \([0-9]\+\) client currently connected/\1/p' "$log" | tail -n1) 29 | if [[ -z "$clientCount" ]] || [[ "$clientCount" -eq 0 ]]; then 30 | idleSeconds=$(( idleSeconds + interval )) 31 | else 32 | idleSeconds=0 33 | fi 34 | 35 | done 36 | 37 | echo "$maxIdle seconds passed without any connections, stopping tmate session" 38 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | (import ./. {}).devShell 2 | -------------------------------------------------------------------------------- /static-root-files/etc/bashrc: -------------------------------------------------------------------------------- 1 | if [[ $(nproc) > 30 ]]; then 2 | maxjobs=30 3 | else 4 | maxjobs=auto 5 | fi 6 | 7 | echo "max-jobs = $maxjobs" >> /etc/nix/nix.conf 8 | -------------------------------------------------------------------------------- /static-root-files/etc/group: -------------------------------------------------------------------------------- 1 | root:x:0: 2 | wheel:x:1: 3 | tty:x:3: 4 | users:x:100: 5 | nixbld:x:30000:nixbld1,nixbld2,nixbld3,nixbld4,nixbld5,nixbld6,nixbld7,nixbld8,nixbld9,nixbld10,nixbld11,nixbld12,nixbld13,nixbld14,nixbld15,nixbld16,nixbld17,nixbld18,nixbld19,nixbld20,nixbld21,nixbld22,nixbld23,nixbld24,nixbld25,nixbld26,nixbld27,nixbld28,nixbld29,nixbld30 6 | nogroup:x:65534: 7 | -------------------------------------------------------------------------------- /static-root-files/etc/nix/nix.conf: -------------------------------------------------------------------------------- 1 | # max-jobs is set by /etc/bashrc to # of CPU cores or 30, whichever is lower 2 | -------------------------------------------------------------------------------- /static-root-files/etc/nsswitch.conf: -------------------------------------------------------------------------------- 1 | passwd: files mymachines systemd 2 | group: files mymachines systemd 3 | shadow: files 4 | 5 | hosts: files mymachines dns myhostname 6 | networks: files 7 | 8 | ethers: files 9 | services: files 10 | protocols: files 11 | rpc: files 12 | -------------------------------------------------------------------------------- /static-root-files/etc/passwd: -------------------------------------------------------------------------------- 1 | root:x:0:0:root:/root:/nix/var/nix/profiles/default/bin/bash 2 | nixbld1:x:30001:30000:Nix build user 1:/var/empty:/sbin/nologin 3 | nixbld2:x:30002:30000:Nix build user 2:/var/empty:/sbin/nologin 4 | nixbld3:x:30003:30000:Nix build user 3:/var/empty:/sbin/nologin 5 | nixbld4:x:30004:30000:Nix build user 4:/var/empty:/sbin/nologin 6 | nixbld5:x:30005:30000:Nix build user 5:/var/empty:/sbin/nologin 7 | nixbld6:x:30006:30000:Nix build user 6:/var/empty:/sbin/nologin 8 | nixbld7:x:30007:30000:Nix build user 7:/var/empty:/sbin/nologin 9 | nixbld8:x:30008:30000:Nix build user 8:/var/empty:/sbin/nologin 10 | nixbld9:x:30009:30000:Nix build user 9:/var/empty:/sbin/nologin 11 | nixbld10:x:30010:30000:Nix build user 10:/var/empty:/sbin/nologin 12 | nixbld11:x:30011:30000:Nix build user 11:/var/empty:/sbin/nologin 13 | nixbld12:x:30012:30000:Nix build user 12:/var/empty:/sbin/nologin 14 | nixbld13:x:30013:30000:Nix build user 13:/var/empty:/sbin/nologin 15 | nixbld14:x:30014:30000:Nix build user 14:/var/empty:/sbin/nologin 16 | nixbld15:x:30015:30000:Nix build user 15:/var/empty:/sbin/nologin 17 | nixbld16:x:30016:30000:Nix build user 16:/var/empty:/sbin/nologin 18 | nixbld17:x:30017:30000:Nix build user 17:/var/empty:/sbin/nologin 19 | nixbld18:x:30018:30000:Nix build user 18:/var/empty:/sbin/nologin 20 | nixbld19:x:30019:30000:Nix build user 19:/var/empty:/sbin/nologin 21 | nixbld20:x:30020:30000:Nix build user 20:/var/empty:/sbin/nologin 22 | nixbld21:x:30021:30000:Nix build user 21:/var/empty:/sbin/nologin 23 | nixbld22:x:30022:30000:Nix build user 22:/var/empty:/sbin/nologin 24 | nixbld23:x:30023:30000:Nix build user 23:/var/empty:/sbin/nologin 25 | nixbld24:x:30024:30000:Nix build user 24:/var/empty:/sbin/nologin 26 | nixbld25:x:30025:30000:Nix build user 25:/var/empty:/sbin/nologin 27 | nixbld26:x:30026:30000:Nix build user 26:/var/empty:/sbin/nologin 28 | nixbld27:x:30027:30000:Nix build user 27:/var/empty:/sbin/nologin 29 | nixbld28:x:30028:30000:Nix build user 28:/var/empty:/sbin/nologin 30 | nixbld29:x:30029:30000:Nix build user 29:/var/empty:/sbin/nologin 31 | nixbld30:x:30030:30000:Nix build user 30:/var/empty:/sbin/nologin 32 | nobody:x:65534:65534:nobody:/:/sbin/nologin 33 | -------------------------------------------------------------------------------- /static-root-files/etc/shadow: -------------------------------------------------------------------------------- 1 | root:!::0::::: 2 | nixbld1:!:18237:0:99999:7::: 3 | nixbld2:!:18237:0:99999:7::: 4 | nixbld3:!:18237:0:99999:7::: 5 | nixbld4:!:18237:0:99999:7::: 6 | nixbld5:!:18237:0:99999:7::: 7 | nixbld6:!:18237:0:99999:7::: 8 | nixbld7:!:18237:0:99999:7::: 9 | nixbld8:!:18237:0:99999:7::: 10 | nixbld9:!:18237:0:99999:7::: 11 | nixbld10:!:18237:0:99999:7::: 12 | nixbld11:!:18237:0:99999:7::: 13 | nixbld12:!:18237:0:99999:7::: 14 | nixbld13:!:18237:0:99999:7::: 15 | nixbld14:!:18237:0:99999:7::: 16 | nixbld15:!:18237:0:99999:7::: 17 | nixbld16:!:18237:0:99999:7::: 18 | nixbld17:!:18237:0:99999:7::: 19 | nixbld18:!:18237:0:99999:7::: 20 | nixbld19:!:18237:0:99999:7::: 21 | nixbld20:!:18237:0:99999:7::: 22 | nixbld21:!:18237:0:99999:7::: 23 | nixbld22:!:18237:0:99999:7::: 24 | nixbld23:!:18237:0:99999:7::: 25 | nixbld24:!:18237:0:99999:7::: 26 | nixbld25:!:18237:0:99999:7::: 27 | nixbld26:!:18237:0:99999:7::: 28 | nixbld27:!:18237:0:99999:7::: 29 | nixbld28:!:18237:0:99999:7::: 30 | nixbld29:!:18237:0:99999:7::: 31 | nixbld30:!:18237:0:99999:7::: 32 | nobody:!::0::::: 33 | -------------------------------------------------------------------------------- /tests/curl/.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | driver 3 | -------------------------------------------------------------------------------- /tests/curl/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM base AS build 2 | 3 | COPY . src 4 | RUN nix-env -if src -A curl -A cacert \ 5 | && export-profile /dist 6 | 7 | FROM scratch 8 | COPY --from=build /dist / 9 | ENV \ 10 | PATH=/run/profile/bin \ 11 | # To allow curl to find certs 12 | NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt 13 | -------------------------------------------------------------------------------- /tests/curl/default.nix: -------------------------------------------------------------------------------- 1 | let 2 | nixpkgs = fetchTarball { 3 | name = "nixpkgs-src"; 4 | url = "https://github.com/NixOS/nixpkgs/archive/${builtins.readFile ./nixpkgsCommit}.tar.gz"; 5 | sha256 = builtins.readFile ./nixpkgsSha; 6 | }; 7 | in import nixpkgs { 8 | overlays = []; 9 | config = {}; 10 | } 11 | -------------------------------------------------------------------------------- /tests/curl/driver: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eu 3 | 4 | # This tests that a final image can be used to run a binary, 5 | # and that the NIX_SSL_CERT_FILE env var works 6 | 7 | docker build "$1" -t final 8 | docker run final curl https://example.com 9 | -------------------------------------------------------------------------------- /tests/minimal/.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | driver 3 | -------------------------------------------------------------------------------- /tests/minimal/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM base AS build 2 | 3 | COPY . src 4 | RUN nix-env -if src -A hello \ 5 | && export-profile /dist 6 | 7 | FROM scratch 8 | COPY --from=build /dist / 9 | -------------------------------------------------------------------------------- /tests/minimal/default.nix: -------------------------------------------------------------------------------- 1 | let 2 | nixpkgs = fetchTarball { 3 | name = "nixpkgs-src"; 4 | url = "https://github.com/NixOS/nixpkgs/archive/${builtins.readFile ./nixpkgsCommit}.tar.gz"; 5 | sha256 = builtins.readFile ./nixpkgsSha; 6 | }; 7 | in import nixpkgs { 8 | overlays = []; 9 | config = {}; 10 | } 11 | -------------------------------------------------------------------------------- /tests/minimal/driver: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This tests that the final image isn't much bigger than the closure of the Nix dependencies it should contain 4 | 5 | set -eu 6 | docker build "$1" -t final 7 | imagesize=$(docker image inspect final --format='{{.Size}}') 8 | closuresize=$(nix path-info --closure-size $(nix-build "$1" --no-out-link -A hello) | cut -d' ' -f 4) 9 | 10 | # Allow 10% extra space for whathaveyounot. Not only because there's some overhead, but also because how Docker and Nix measure sizes isn't the same 11 | maxsize=$(( closuresize * 11 / 10 )) 12 | if [[ "$imagesize" -gt "$maxsize" ]]; then 13 | echo "Final image too big, we expect no more than $maxsize bytes, but it's $imagesize bytes" >&2 14 | exit 1 15 | fi 16 | -------------------------------------------------------------------------------- /tests/prefetching/.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | driver 3 | -------------------------------------------------------------------------------- /tests/prefetching/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM base AS build 2 | 3 | COPY . src 4 | RUN nix-env -v -if src -A hello \ 5 | && export-profile /dist 6 | 7 | FROM scratch 8 | COPY --from=build /dist / 9 | -------------------------------------------------------------------------------- /tests/prefetching/default.nix: -------------------------------------------------------------------------------- 1 | let 2 | nixpkgs = fetchTarball { 3 | name = "nixpkgs-src"; 4 | url = "https://github.com/NixOS/nixpkgs/archive/${builtins.readFile ./nixpkgsCommit}.tar.gz"; 5 | sha256 = builtins.readFile ./nixpkgsSha; 6 | }; 7 | in import nixpkgs { 8 | overlays = []; 9 | config = {}; 10 | } 11 | -------------------------------------------------------------------------------- /tests/prefetching/driver: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This tests that the nixpkgs tarball for the required nixpkgs version is downloaded 4 | 5 | set -eu 6 | echo "$1" 7 | string="downloading 'https://github.com/NixOS/nixpkgs/archive" 8 | output=$(mktemp) 9 | docker build "$1" | tee "$output" 10 | if grep "$string" "$output" >/dev/null; then 11 | echo "Image build didn't use the prefetched nixpkgs" 12 | exit 1 13 | fi 14 | --------------------------------------------------------------------------------