diff --git a/.gitea/workflows/build-image.yml b/.gitea/workflows/build-image.yml index 9f8727b..a6c8822 100644 --- a/.gitea/workflows/build-image.yml +++ b/.gitea/workflows/build-image.yml @@ -1,5 +1,9 @@ # Build the Crucible image. PR-first (D7): PRs build only; push to main also # publishes registry.westgate.pw/sow/crucible:. Never a mutable tag. +# +# Daemonless: the host-mode runner has no container runtime, so the image is +# built by Nix (`nix build .#image`, see flake.nix) and pushed with skopeo +# straight from the OCI tarball. No `docker build`/`docker login` involved. name: build-image on: @@ -22,12 +26,8 @@ jobs: id: tag run: echo "sha=$(git rev-parse --short=12 HEAD)" >> "$GITHUB_OUTPUT" - - name: Build image - run: | - docker build \ - --build-arg GIT_SHA=${{ steps.tag.outputs.sha }} \ - -f docker/Dockerfile \ - -t ${REGISTRY}/${IMAGE}:${{ steps.tag.outputs.sha }} . + - name: Build OCI image (daemonless) + run: nix build .#image # Publish only on main (post-merge). PRs verify the build but never push. - name: Publish image @@ -36,8 +36,10 @@ jobs: REGISTRY_USER: ${{ secrets.REGISTRY_USER }} REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} run: | - echo "${REGISTRY_PASSWORD}" | docker login "${REGISTRY}" -u "${REGISTRY_USER}" --password-stdin - docker push ${REGISTRY}/${IMAGE}:${{ steps.tag.outputs.sha }} + nix shell nixpkgs#skopeo -c skopeo copy \ + --dest-creds "${REGISTRY_USER}:${REGISTRY_PASSWORD}" \ + docker-archive:result \ + "docker://${REGISTRY}/${IMAGE}:${{ steps.tag.outputs.sha }}" - name: Emit release fragment run: | @@ -46,6 +48,6 @@ jobs: FRAG_ARTIFACT="${REGISTRY}/${IMAGE}:${{ steps.tag.outputs.sha }}" \ FRAG_URL="${REGISTRY}/${IMAGE}" \ FRAG_RUN_ID=${{ gitea.run_id }} \ - ./scripts/emit-release-fragment.sh + bash scripts/emit-release-fragment.sh - uses: actions/upload-artifact@v3 with: { name: release-fragment, path: release-fragment.json } diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 8076e7a..bf558e8 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -23,7 +23,7 @@ jobs: run: | nix develop --command bash -c ' set -euo pipefail - GOOS=linux GOARCH=amd64 scripts/build-binaries.sh + GOOS=linux GOARCH=amd64 bash scripts/build-binaries.sh mkdir -p dist tar -C bin -czf "dist/crucible-linux-amd64-${GITHUB_REF_NAME}.tar.gz" . ' diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index d3549b7..17870d8 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -9,8 +9,6 @@ on: jobs: test: runs-on: nix-docker - container: - image: nixos/nix:latest steps: - uses: actions/checkout@v4 with: { fetch-depth: 0 } diff --git a/flake.nix b/flake.nix index 3d77951..1ac7007 100644 --- a/flake.nix +++ b/flake.nix @@ -12,6 +12,56 @@ # Self-contained (D8): a host with ONLY nix can enter this shell and run # `make check`. ffmpeg is present because the migrated music pipeline needs # it; the scaffold itself is pure stdlib Go. + # Daemonless image build (D8): `nix build .#image` produces an OCI tarball + # with no docker/podman daemon. CI loads/pushes it with skopeo. This is the + # Nix-native replacement for `docker build` on the host-mode runner, which + # has no container runtime. ffmpeg-headless ships the BMU codec path. + packages = forAllSystems (pkgs: + let + version = self.shortRev or self.dirtyShortRev or "unknown"; + crucible = pkgs.buildGoModule { + pname = "crucible"; + inherit version; + src = ./.; + vendorHash = "sha256-hm6mrNAtXv0LidzHUfz4eukTFZouizGtxkZ8gKJFUVI="; + subPackages = [ + "cmd/crucible" + "cmd/crucible-depot" + "cmd/crucible-hak" + "cmd/crucible-module" + "cmd/crucible-topdata" + "cmd/crucible-wiki" + ]; + env.CGO_ENABLED = 0; + ldflags = [ + "-s" + "-w" + "-X git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/buildinfo.Version=${version}" + ]; + # Unit tests run in the `test` workflow / `make check`, not here. + doCheck = false; + }; + in + { + inherit crucible; + default = crucible; + + image = pkgs.dockerTools.buildLayeredImage { + name = "registry.westgate.pw/sow/crucible"; + tag = version; + contents = [ crucible pkgs.cacert pkgs.ffmpeg-headless pkgs.fakeNss ]; + config = { + Entrypoint = [ "/bin/crucible" ]; + Cmd = [ "help" ]; + User = "65532:65532"; + Env = [ + "PATH=/bin" + "SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt" + ]; + }; + }; + }); + devShells = forAllSystems (pkgs: { default = pkgs.mkShell { name = "sow-tools";