{ description = "Angie web server (aarch64) — OCI image for Gitea registry"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; outputs = { self, nixpkgs }: let system = "aarch64-linux"; pkgs = import nixpkgs { inherit system; }; # nixpkgs ships angie compiled against `--prefix=/etc/angie` and # `--http-log-path=/var/log/angie/access.log`; the package's `bin/angie` # already knows where to look for its main config (/etc/angie/angie.conf). inherit (pkgs) angie; # Stock main config: turns on http and includes whatever drop-ins the # chart mounts at /etc/angie/http.d/*.conf — same idiom as the alpine # nginx image's /etc/nginx/conf.d/. mainConf = pkgs.writeText "angie.conf" '' # Run as root in the container — fakeNss doesn't ship a "nogroup" # group, which is the compiled-in default group for this angie build, # and the worker would refuse to start otherwise. user root; worker_processes auto; error_log /var/log/nginx/error.log notice; pid /run/angie.pid; events { worker_connections 1024; } http { include ${angie}/conf/mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; access_log /var/log/nginx/access.log; include /etc/angie/http.d/*.conf; } ''; image = pkgs.dockerTools.streamLayeredImage { name = "angie"; tag = angie.version; contents = with pkgs; [ angie cacert dockerTools.fakeNss coreutils bash ]; # Writable runtime dirs. /var/log/nginx is the compiled-in path for # angie (matches nixpkgs' nginx build flags); the chart's main config # also writes pid to /run. extraCommands = '' mkdir -p var/log/nginx var/cache/angie var/lib/angie run tmp etc/angie/http.d chmod 1777 tmp run # Ship the conf-dir bundled with angie (mime.types, fastcgi_params, # scgi_params, uwsgi_params, koi-utf, koi-win, etc.) — chart configs # `include fastcgi_params;` and similar resolve relative to /etc/angie. cp ${angie}/conf/* etc/angie/ chmod -R u+w etc/angie cp -f ${mainConf} etc/angie/angie.conf ''; config = { Entrypoint = [ "${angie}/bin/angie" ]; Cmd = [ "-c" "/etc/angie/angie.conf" "-g" "daemon off;" ]; ExposedPorts = { "80/tcp" = { }; }; WorkingDir = "/etc/angie"; }; }; # Shared build+publish logic for the arm64 OCI leg. This script IS the # parity code (emmett#44, archetype: oci-image-skopeo): both # `.woodpecker.yaml` and a local `nix run .#publish-arm64` invoke the # exact same entrypoint, so CI and local cannot drift. # # Safety: DRY-RUN by default. It builds the image stream and prints the # refs it WOULD push, but performs no registry contact unless PUBLISH=1 # is set. The token is never printed and this script never runs under # `set -x` (which would leak the auth header). publish-arm64 = pkgs.writeShellApplication { name = "publish-arm64"; runtimeInputs = with pkgs; [ skopeo coreutils gnused gitMinimal ]; # `pass` is optional (only the local fallback path needs it) and may # live outside this closure, so it is resolved from PATH at runtime. text = '' set -euo pipefail # --- usage ------------------------------------------------------- if [ "''${1:-}" = "--help" ] || [ "''${1:-}" = "-h" ]; then printf '%s\n' \ "publish-arm64 — build the angie arm64 OCI image and (optionally) push it." \ "" \ "Builds the arm64 docker-archive via Nix and uses skopeo to copy it to" \ "the Gitea OCI registry as :-arm64, then mirrors that digest to" \ ":latest-arm64." \ "" \ "DRY-RUN by default: prints the refs it would push and exits without" \ "contacting the registry. Set PUBLISH=1 to actually push." \ "" \ "Env:" \ " PUBLISH=1 actually push (default: dry-run)" \ " VERSION= override the tag (default: angie.version)" \ " REGISTRY_TOKEN= registry RW token; if empty, falls back to" \ " pass infra/gitea/personal_access_token_packages_rw" \ "" \ "Flags:" \ " --help, -h this help" \ " --dry-run force dry-run even if PUBLISH=1" exit 0 fi DRY_RUN=0 if [ "''${PUBLISH:-0}" != "1" ]; then DRY_RUN=1; fi if [ "''${1:-}" = "--dry-run" ]; then DRY_RUN=1; fi REGISTRY="git.oleks.space" IMAGE="oleks/angie" # --- version / tag (identical for CI + local) -------------------- VERSION="''${VERSION:-$(nix eval --raw .#angieVersion)}" echo "angie version: $VERSION" echo "target refs: docker://$REGISTRY/$IMAGE:$VERSION-arm64" echo " docker://$REGISTRY/$IMAGE:latest-arm64" # --- build (cluster-independent) --------------------------------- echo "building arm64 image stream..." STREAM="$(nix build .#default --print-out-paths --no-link)" if [ "$DRY_RUN" = "1" ]; then echo "DRY-RUN: built $STREAM" echo "DRY-RUN: would skopeo-copy docker-archive -> docker://$REGISTRY/$IMAGE:$VERSION-arm64" echo "DRY-RUN: would mirror :$VERSION-arm64 -> :latest-arm64" echo "DRY-RUN: set PUBLISH=1 to actually push." exit 0 fi # --- token resolution (never printed) ---------------------------- TOKEN="''${REGISTRY_TOKEN:-}" if [ -z "$TOKEN" ]; then if command -v pass >/dev/null 2>&1; then TOKEN="$(pass infra/gitea/personal_access_token_packages_rw)" fi fi if [ -z "$TOKEN" ]; then echo "ERROR: no registry token. Set REGISTRY_TOKEN or store it at" >&2 echo " pass infra/gitea/personal_access_token_packages_rw" >&2 exit 1 fi # skopeo's containers/image library stages under /var/tmp (not TMPDIR). mkdir -p /var/tmp && chmod 1777 /var/tmp || true AUTHFILE="$(mktemp -d)/auth.json" # shellcheck disable=SC2064 trap "rm -rf '$(dirname "$AUTHFILE")'" EXIT printf '{"auths":{"%s":{"auth":"%s"}}}\n' \ "$REGISTRY" "$(printf 'oleks:%s' "$TOKEN" | base64 -w0)" \ > "$AUTHFILE" echo "pushing :$VERSION-arm64 ..." skopeo copy --insecure-policy --authfile "$AUTHFILE" \ docker-archive:<("$STREAM") \ "docker://$REGISTRY/$IMAGE:$VERSION-arm64" echo "mirroring :$VERSION-arm64 -> :latest-arm64 ..." skopeo copy --insecure-policy --authfile "$AUTHFILE" \ "docker://$REGISTRY/$IMAGE:$VERSION-arm64" \ "docker://$REGISTRY/$IMAGE:latest-arm64" echo "done." ''; }; in { packages.${system} = { default = image; }; apps.${system} = { publish-arm64 = { type = "app"; program = "${publish-arm64}/bin/publish-arm64"; meta.description = "Build and publish the angie arm64 OCI image to git.oleks.space (dry-run by default; PUBLISH=1 to push)."; }; }; # Plain string — read by CI via `nix eval --raw .#angieVersion`. angieVersion = angie.version; }; }