{ description = "alertmanager-gotify-bridge — pure-stdlib Python forwarder, containerized with Nix (nix2container), multi-arch via the shared parity-lib OCI builder."; # ────────────────────────────────────────────────────────────────────────── # LOCAL-PIPELINE PARITY (cluster #192, emmett#44). Archetype: nix2container OCI # image (NOT a buildkit/escape-hatch repo — the whole payload is Nix- # expressible). The payload is pure-stdlib `bridge.py` next to a stock CPython # closure, so BOTH arches build on emmett with no buildkit / qemu / docker: # amd64 = native, arm64 = pkgsCross of stock python3 from the binary cache. # The per-arch image derivations are kept verbatim; the stage/publish/ # publish-index/publish/push-staged apps come from parity-lib's # mkNix2ContainerPublish so CI and local invoke the SAME code and cannot drift. # ci/MIGRATION.md is the design history. # ────────────────────────────────────────────────────────────────────────── inputs = { fleet.url = "git+https://git.oleks.space/oleks/fleet-pins"; nixpkgs.follows = "fleet/nixpkgs-projects"; nix2container.url = "github:nlewo/nix2container"; nix2container.inputs.nixpkgs.follows = "nixpkgs"; parity.url = "git+https://git.oleks.space/oleks/parity-lib"; flake-utils.url = "github:numtide/flake-utils"; }; outputs = { nixpkgs, nix2container, parity, flake-utils, ... }: flake-utils.lib.eachDefaultSystem ( system: let pkgs = import nixpkgs { inherit system; }; n2c = nix2container.packages.${system}.nix2container; registry = "git.oleks.space/oleks/alertmanager-gotify-bridge"; # TAG is derived in shared code: CI exports CI_COMMIT_TAG (parity-lib # strips the leading v / trailing -N), local dev may override $VERSION. # No version.nix side-channel — the app is a static asset with no # version-baked source build, so the tag lives purely in $VERSION/tag. version = "0.0.0-dev"; # The whole payload: bridge.py + a python3 interpreter symlink under /app. # The symlink keeps the (arch-correct) python3 Nix closure tracked while # contributing no extra files. Parameterised over a pkg set so the SAME # expression builds natively (amd64) and cross (arm64). appRoot = targetPkgs: arch: pkgs.runCommand "app-root-${arch}" { } '' mkdir -p $out/app cp ${./bridge.py} $out/app/bridge.py ln -s ${targetPkgs.python3}/bin/python3 $out/app/python3 ''; mkImage = targetPkgs: arch: n2c.buildImage { name = registry; tag = "${version}-${arch}"; inherit arch; # reproducible = false materializes the layer tar so the image streams # verbatim from any host (remote-builder + binary-cache safe). For a # pure-stdlib interpreter closure the determinism risk is low, but the # standard's caveat still applies: emmett+CI must resolve the identical # python3 store path from the shared cache (fleet pin + flake.lock). layers = [ (n2c.buildLayer { copyToRoot = [ (appRoot targetPkgs arch) pkgs.cacert ]; maxLayers = 25; reproducible = false; }) ]; config = { Cmd = [ "/app/python3" "/app/bridge.py" ]; WorkingDir = "/app"; ExposedPorts = { "8080/tcp" = { }; }; Env = [ "PORT=8080" # urllib → Gotify over HTTPS needs an explicit CA bundle (the old # Alpine base provided one via the distro; the Nix image ships it). "SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt" ]; }; }; # amd64 = native; arm64 = cross-compiled (stock python3 closure from the # binary cache, no qemu). Both are buildable on emmett (amd64). imageAmd64 = mkImage pkgs "amd64"; imageArm64 = mkImage pkgs.pkgsCross.aarch64-multiplatform "arm64"; # ── Publish apps: shared parity-lib nix2container builder (cluster #192). # Yields stage- / publish- / publish-index / publish / # push-staged. copy-to (skopeo) pushes per-arch, regctl assembles the # index; no buildkit / docker daemon. Dry-run by default (--publish to # push); token from $REGISTRY_TOKEN (CI from_secret) → pass fallback, # never echoed. builders = parity.lib.mkParityBuilders pkgs; publishApps = builders.mkNix2ContainerPublish { imageName = registry; inherit version; images = { amd64.copyTo = imageAmd64.copyTo; arm64.copyTo = imageArm64.copyTo; }; }; in { packages = { image-amd64 = imageAmd64; image-arm64 = imageArm64; default = imageAmd64; }; apps = publishApps; formatter = pkgs.nixfmt-rfc-style; } ); }