Files
angie-arm64/flake.nix
T
Oleks 68f56637e9
ci/woodpecker/push/woodpecker Pipeline was successful
ci: add publish-arm64 flake app for local parity (emmett#44)
Introduce a shared publish-arm64 flake app (archetype oci-image-skopeo)
that builds the arm64 docker-archive via Nix and skopeo-copies it to the
Gitea OCI registry as :<ver>-arm64, mirroring to :latest-arm64. Both
.woodpecker.yaml and `nix run .#publish-arm64` invoke the same app so CI
and local cannot drift.

- dry-run by default; PUBLISH=1 to actually push (safe to run locally)
- token via $REGISTRY_TOKEN, fallback pass infra/gitea/personal_access_token_packages_rw
- token never printed; no set -x on token-bearing paths
- rename CI secret env CI_REGISTRY_TOKEN -> REGISTRY_TOKEN
- thin .woodpecker.yaml: one PUBLISH=1 nix run line
- --help/--dry-run honored; meta.description set
2026-06-02 03:35:13 +03:00

206 lines
7.8 KiB
Nix

{
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 :<ver>-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=<ver> override the tag (default: angie.version)" \
" REGISTRY_TOKEN=<tok> 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;
};
}