main
  1{
  2  lib,
  3  pkgs,
  4  nix2container,
  5  name,
  6  # Skopeo cannot assemble a multi-arch index, so a tag names one architecture.
  7  tag ? "nixos-${lib.version}-${pkgs.stdenv.system}",
  8}: let
  9  fakeNss = pkgs.dockerTools.fakeNss.override {
 10    extraPasswdLines = [
 11      "podman:x:1000:1000:Podman user:/home/podman:/bin/bash"
 12      "nixbld1:!:999:999:Nix build user 1:/var/empty:/sbin/nologin"
 13      "nixbld2:!:999:999:Nix build user 1:/var/empty:/sbin/nologin"
 14      "nixbld3:!:999:999:Nix build user 1:/var/empty:/sbin/nologin"
 15      "nixbld4:!:999:999:Nix build user 1:/var/empty:/sbin/nologin"
 16      "nixbld5:!:999:999:Nix build user 1:/var/empty:/sbin/nologin"
 17      "nixbld6:!:999:999:Nix build user 1:/var/empty:/sbin/nologin"
 18      "nixbld7:!:999:999:Nix build user 1:/var/empty:/sbin/nologin"
 19      "nixbld8:!:999:999:Nix build user 1:/var/empty:/sbin/nologin"
 20      "nixbld9:!:999:999:Nix build user 1:/var/empty:/sbin/nologin"
 21      "nixbld10:!:999:999:Nix build user 1:/var/empty:/sbin/nologin"
 22    ];
 23    extraGroupLines = [
 24      "podman:x:1000:podman"
 25      "nixbld:x:999:nixbld1,nixbld2,nixbld3,nixbld4,nixbld5,nixbld6,nixbld7,nixbld8,nixbld9,nixbld10"
 26    ];
 27  };
 28
 29  mkNixConf = pkgs.runCommand "nix-act-image-etc" {} ''
 30    mkdir -p $out/etc/nix
 31    echo "experimental-features = nix-command flakes" > $out/etc/nix/nix.conf
 32  '';
 33
 34  mkTmp = pkgs.runCommand "nix-act-image-tmp" {} ''
 35    mkdir -p $out/tmp
 36    mkdir -p $out/var/tmp
 37  '';
 38
 39  mkPodmanConfig = pkgs.runCommand "podman-config" {} ''
 40    mkdir -p $out/etc/containers
 41    mkdir -p $out/home/podman
 42    mkdir -p $out/var/lib/containers
 43    mkdir -p $out/var/lib/shared/overlay-images
 44    mkdir -p $out/var/lib/shared/overlay-layers
 45    mkdir -p $out/var/lib/shared/vfs-images
 46    mkdir -p $out/var/lib/shared/vfs-layers
 47    mkdir -p $out/run
 48
 49    touch $out/var/lib/shared/overlay-images/images.lock
 50    touch $out/var/lib/shared/overlay-layers/layers.lock
 51    touch $out/var/lib/shared/vfs-images/images.lock
 52    touch $out/var/lib/shared/vfs-layers/layers.lock
 53
 54    cat > $out/etc/containers/containers.conf << 'EOF'
 55    [containers]
 56    netns="host"
 57    userns="host"
 58    ipcns="host"
 59    utsns="host"
 60    cgroupns="host"
 61    cgroups="disabled"
 62    log_driver = "k8s-file"
 63    [engine]
 64    cgroup_manager = "cgroupfs"
 65    events_logger="file"
 66    runtime="crun"
 67    EOF
 68
 69    cat > $out/etc/containers/containers.conf.rootless << 'EOF'
 70    [containers]
 71    volumes = [
 72      "/proc:/proc",
 73    ]
 74    default_sysctls = []
 75    EOF
 76
 77    cat > $out/etc/containers/storage.conf << 'EOF'
 78    [storage]
 79    driver = "overlay"
 80    runroot = "/run/containers/storage"
 81    graphroot = "/var/lib/containers/storage"
 82    [storage.options]
 83    mount_program = "${pkgs.fuse-overlayfs}/bin/fuse-overlayfs"
 84    mountopt = "nodev,fsync=0"
 85    additionalimagestores = [
 86      "/var/lib/shared",
 87    ]
 88    [storage.options.overlay]
 89    ignore_chown_errors = "true"
 90    EOF
 91
 92    cat > $out/etc/containers/mounts.conf << 'EOF'
 93    /run/secrets/etc-pki-entitlement:/run/secrets/etc-pki-entitlement
 94    /run/secrets/rhsm:/run/secrets/rhsm
 95    EOF
 96
 97    cat > $out/etc/containers/policy.json << 'EOF'
 98    {"default":[{"type":"insecureAcceptAnything"}]}
 99    EOF
100  '';
101
102  mkSubugid = pkgs.runCommand "subugid" {} ''
103    mkdir -p $out/etc
104    cat > $out/etc/subuid << 'EOF'
105    root:1:999
106    root:1001:64535
107    podman:1:999
108    podman:1001:64535
109    EOF
110    cat > $out/etc/subgid << 'EOF'
111    root:1:999
112    root:1001:64535
113    podman:1:999
114    podman:1001:64535
115    EOF
116  '';
117
118  podmanDockerCompat =
119    pkgs.runCommand "${pkgs.podman.pname}-docker-compat-${pkgs.podman.version}"
120    {
121      nativeBuildInputs = [pkgs.installShellFiles];
122      outputs = [
123        "out"
124        "man"
125      ];
126      inherit (pkgs.podman) meta;
127      preferLocalBuild = true;
128    }
129    ''
130      mkdir -p $out/bin
131      ln -s ${pkgs.podman}/bin/podman $out/bin/docker
132
133      mkdir -p $man/share/man/man1
134      for f in ${pkgs.podman.man}/share/man/man1/*; do
135        basename=$(basename $f | sed s/podman/docker/g)
136        ln -s $f $man/share/man/man1/$basename
137      done
138
139      export HOME=$(mktemp -d) # work around `docker <cmd>`
140      installShellCompletion --cmd docker \
141        --bash <($out/bin/docker completion bash) \
142        --zsh <($out/bin/docker completion zsh) \
143        --fish <($out/bin/docker completion fish)
144    '';
145in
146  nix2container.buildImage {
147    inherit name tag;
148
149    initializeNixDatabase = true;
150    maxLayers = 100;
151
152    copyToRoot = [
153      (pkgs.buildEnv {
154        name = "root";
155        paths = with pkgs; [
156          bash
157          coreutils
158          dockerTools.caCertificates
159          dockerTools.usrBinEnv
160          fakeNss
161          mkTmp
162          nix
163          nodejs_24
164
165          aria2
166          cacert
167          curl
168          dnsutils
169          openssh
170          wget
171
172          gitMinimal
173          git-lfs
174
175          gnutar
176          gzip
177          p7zip
178          unzip
179          xz
180          zip
181          zstd
182
183          autoconf
184          automake
185          gcc
186          gnumake
187          m4
188          patchelf
189
190          binutils
191          file
192          findutils
193          gawk
194          gnugrep
195          gnupg
196          gnused
197          jq
198          parallel
199          python3
200          rsync
201          sqlite
202          sudo
203          tree
204          yq
205
206          fuse-overlayfs
207          mkPodmanConfig
208          podman
209          podmanDockerCompat
210          shadow
211        ];
212      })
213      mkNixConf
214      mkSubugid
215    ];
216    perms = [
217      {
218        path = mkTmp;
219        regex = ".*";
220        mode = "1777";
221      }
222      {
223        path = mkPodmanConfig;
224        regex = "home/podman";
225        mode = "0777";
226      }
227      {
228        path = pkgs.shadow;
229        regex = "bin/new[ug]idmap";
230        mode = "4555";
231      }
232    ];
233    config = {
234      Entrypoint = ["/bin/bash"];
235      Env = [
236        "USER=root"
237        "HOME=/"
238        "PATH=/nix/profile/bin:/nix/var/nix/profiles/default/bin:/bin"
239        "NIX_PAGER=cat"
240        "NIX_PATH=nixpkgs=${pkgs.path}"
241        "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
242        "DOCKER_HOST=unix:///run/user/1000/podman/podman.sock"
243        "CONTAINERS_STORAGE=/var/lib/containers/storage"
244        "_CONTAINERS_USERNS_CONFIGURED="
245        "BUILDAH_ISOLATION=chroot"
246      ];
247      Labels = {
248        "org.opencontainers.image.source" = "https://git.trin.one/GOI/nix-act-image";
249        "org.opencontainers.image.description" = "A Nix based container for Forgejo Actions";
250        "org.opencontainers.image.licenses" = lib.licenses.mit.spdxId;
251      };
252    };
253  }