# Fixed-output derivation (FOD): download and install all external Python # dependencies into a venv using uv sync. # # FODs get network access because the output hash is declared upfront. # However, FODs must not reference other Nix store paths in their output. # Compiled .so files (from sdist builds) contain RPATHs to system libraries # (libxml2, krb5, etc.) which are Nix store paths. We strip these references # here; authentik-django.nix restores them via autoPatchelfHook. # # The venv's bin/ and pyvenv.cfg also reference the python store path, so we # replace them with placeholders that the main derivation restores. # # When uv.lock changes, reset outputHash to pkgs.lib.fakeHash, build to # get the correct hash from the error message, then update. { pkgs ? import { }, sources ? import ./sources.nix { inherit pkgs; } }: let # All store paths that may end up referenced in the venv output. # remove-references-to will replace each hash with 'eeee...' bytes. refTargets = with pkgs; [ python314 stdenv.cc.cc.lib libxml2.out libxml2.dev libxslt.out libxslt.dev xmlsec.out openssl.out openssl.dev libpq.out libpq.dev krb5.out krb5.dev krb5.lib libtool.out libtool.lib libffi.out libffi.dev zlib.out zlib.dev readline.out ncurses.out glibc.out ]; removeRefsArgs = builtins.concatStringsSep " " (map (t: "-t ${t}") refTargets); in pkgs.stdenv.mkDerivation { pname = "authentik-python-deps"; version = sources.version; src = sources.src; nativeBuildInputs = with pkgs; [ python314 uv git # opencontainers is a git dependency in uv.lock cacert # HTTPS verification for PyPI + GitHub pkg-config removeReferencesTo # Build tools on PATH for sdist compilation postgresql.pg_config # pg_config for psycopg-c krb5 # krb5-config for gssapi ]; # System libraries for packages that must build from sdist: # lxml, xmlsec — pyproject.toml [tool.uv] no-binary-package # psycopg-c — sdist only on PyPI # gssapi — no Linux wheels on PyPI buildInputs = with pkgs; [ libxml2 libxslt xmlsec openssl libpq # psycopg-c links against libpq libtool # libltdl for xmlsec dynamic crypto backend loading libffi zlib ]; buildPhase = '' runHook preBuild export HOME=$TMPDIR export SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt export GIT_SSL_CAINFO=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt export UV_PYTHON=${pkgs.python314}/bin/python3.14 export UV_LINK_MODE=copy # gssapi's pre-generated C code uses S4U functions declared in gssapi_ext.h # but doesn't include it — force-include via compiler flag export NIX_CFLAGS_COMPILE="''${NIX_CFLAGS_COMPILE:-} -include gssapi/gssapi_ext.h" uv sync \ --frozen \ --no-install-project \ --no-install-workspace \ --no-dev runHook postBuild ''; installPhase = '' runHook preInstall mv .venv $out # --- Strip Nix store references (FODs must be self-contained) --- # autoPatchelfHook in authentik-django.nix restores correct RPATHs. # Replace python store path in pyvenv.cfg with placeholder sed -i "s|${pkgs.python314}|@python@|g" $out/pyvenv.cfg # Remove bin/ entirely — main derivation recreates it rm -rf $out/bin # Strip store path references from shared objects find $out -type f \( -name '*.so' -o -name '*.so.*' \) \ -exec remove-references-to ${removeRefsArgs} {} + 2>/dev/null || true # Strip store refs from .pyc files (contain embedded paths) find $out -type f -name '*.pyc' -delete runHook postInstall ''; outputHashMode = "recursive"; outputHashAlgo = "sha256"; outputHash = pkgs.lib.fakeHash; dontFixup = true; }