From 6df56466f94c36c28ba55d05555f3b7ebc2e8f1c Mon Sep 17 00:00:00 2001 From: WilliButz Date: Sat, 9 Dec 2023 16:01:26 +0100 Subject: [PATCH] factor out components with callPackage to allow for easier overrides Before this change it was very inconvenient to override specific dependencies, e.g. patching something in pythonEnv and having its dependents use that patched version. This is just a step towards better overridability for the individual authentik components, because patched versions of components still need to be manually passed to their dependents. An overlay-like approach would be even better. --- components/celery.nix | 13 +++ components/docs.nix | 21 +++++ components/frontend.nix | 24 ++++++ components/gopkgs.nix | 50 +++++++++++ components/migrate.nix | 21 +++++ components/pythonEnv.nix | 24 ++++++ components/staticWorkdirDeps.nix | 14 +++ flake.nix | 142 ++++++------------------------- 8 files changed, 191 insertions(+), 118 deletions(-) create mode 100644 components/celery.nix create mode 100644 components/docs.nix create mode 100644 components/frontend.nix create mode 100644 components/gopkgs.nix create mode 100644 components/migrate.nix create mode 100644 components/pythonEnv.nix create mode 100644 components/staticWorkdirDeps.nix diff --git a/components/celery.nix b/components/celery.nix new file mode 100644 index 0000000..2e7422c --- /dev/null +++ b/components/celery.nix @@ -0,0 +1,13 @@ +{ authentikComponents +, makeWrapper +, runCommandLocal +}: + +runCommandLocal "authentik-celery" { + nativeBuildInputs = [ makeWrapper ]; +} '' + mkdir -vp $out/bin + ln -sv ${authentikComponents.pythonEnv}/bin/celery $out/bin/celery + wrapProgram $out/bin/celery \ + --prefix PYTHONPATH : ${authentikComponents.staticWorkdirDeps} +'' diff --git a/components/docs.nix b/components/docs.nix new file mode 100644 index 0000000..09ab35a --- /dev/null +++ b/components/docs.nix @@ -0,0 +1,21 @@ +{ authentik-src +, authentik-version +, buildNapalmPackage +, nodejs_20 +}: + +buildNapalmPackage "${authentik-src}/website" { + version = authentik-version; # 0.0.0 specified upstream in package.json + NODE_ENV = "production"; + nodejs = nodejs_20; + npmCommands = [ + "cp -v ${authentik-src}/SECURITY.md ../SECURITY.md" + "cp -vr ${authentik-src}/blueprints ../blueprints" + "npm install --include=dev" + "npm run build-docs-only" + ]; + installPhase = '' + rm -r ../website/node_modules/.cache + mv -v ../website $out + ''; +} diff --git a/components/frontend.nix b/components/frontend.nix new file mode 100644 index 0000000..d8c3263 --- /dev/null +++ b/components/frontend.nix @@ -0,0 +1,24 @@ +{ authentik-src +, authentik-version +, authentikComponents +, buildNapalmPackage +, nodejs_21 +}: + +buildNapalmPackage "${authentik-src}/web" rec { + version = authentik-version; # 0.0.0 specified upstream in package.json + NODE_ENV = "production"; + nodejs = nodejs_21; + preBuild = '' + ln -sv ${authentikComponents.docs} ../website + ''; + npmCommands = [ + "npm install --include=dev --nodedir=${nodejs}/include/node --loglevel verbose --ignore-scripts" + "npm run build" + ]; + installPhase = '' + mkdir $out + mv dist $out/dist + cp -r authentik icons $out + ''; +} diff --git a/components/gopkgs.nix b/components/gopkgs.nix new file mode 100644 index 0000000..974e8f0 --- /dev/null +++ b/components/gopkgs.nix @@ -0,0 +1,50 @@ +{ authentik-src +, authentik-version +, authentikComponents +, buildGo121Module +, lib +, makeWrapper +}: + +buildGo121Module { + pname = "authentik-gopkgs"; + version = authentik-version; + prePatch = '' + sed -i"" -e 's,./web/dist/,${authentikComponents.frontend}/dist/,' web/static.go + sed -i"" -e 's,./web/dist/,${authentikComponents.frontend}/dist/,' internal/web/static.go + sed -i"" -e 's,./lifecycle/gunicorn.conf.py,${authentikComponents.staticWorkdirDeps}/lifecycle/gunicorn.conf.py,' internal/gounicorn/gounicorn.go + ''; + src = lib.cleanSourceWith { + src = authentik-src; + filter = (path: _: + (builtins.any (x: x) ( + (map (infix: lib.hasInfix infix path) [ + "/authentik" + "/cmd" + "/internal" + ]) + ++ + (map (suffix: lib.hasSuffix suffix path) [ + "/web" + "/web/static.go" + "/web/robots.txt" + "/web/security.txt" + "go.mod" + "go.sum" + ]) + )) + ); + }; + subPackages = [ + "cmd/ldap" + "cmd/server" + "cmd/proxy" + "cmd/radius" + ]; + vendorHash = "sha256-8F9emmQmbe7R+xtGrjV5ht0adGasU6WAvLa8Wxr+j8M="; + nativeBuildInputs = [ makeWrapper ]; + postInstall = '' + wrapProgram $out/bin/server --prefix PATH : ${authentikComponents.pythonEnv}/bin + wrapProgram $out/bin/server --prefix PYTHONPATH : ${authentikComponents.staticWorkdirDeps} + ''; +} diff --git a/components/migrate.nix b/components/migrate.nix new file mode 100644 index 0000000..de94174 --- /dev/null +++ b/components/migrate.nix @@ -0,0 +1,21 @@ +{ authentik-src +, authentikComponents +, makeWrapper +, runCommandLocal +}: + +runCommandLocal "authentik-migrate.py" { + nativeBuildInputs = [ makeWrapper ]; +} '' + mkdir -vp $out/bin + cp ${authentik-src}/lifecycle/migrate.py $out/bin/migrate.py + chmod +w $out/bin/migrate.py + patchShebangs $out/bin/migrate.py + substituteInPlace $out/bin/migrate.py \ + --replace \ + 'migration_path in Path(__file__).parent.absolute().glob("system_migrations/*.py")' \ + 'migration_path in Path("${authentikComponents.staticWorkdirDeps}/lifecycle").glob("system_migrations/*.py")' + wrapProgram $out/bin/migrate.py \ + --prefix PATH : ${authentikComponents.pythonEnv}/bin \ + --prefix PYTHONPATH : ${authentikComponents.staticWorkdirDeps} +'' diff --git a/components/pythonEnv.nix b/components/pythonEnv.nix new file mode 100644 index 0000000..33d9420 --- /dev/null +++ b/components/pythonEnv.nix @@ -0,0 +1,24 @@ +{ authentik-src +, authentikPoetryOverrides +, defaultPoetryOverrides +, lib +, mkPoetryEnv +, python311 +}: + +mkPoetryEnv { + projectDir = authentik-src; + python = python311; + overrides = [ + defaultPoetryOverrides + ] ++ authentikPoetryOverrides; + groups = []; + checkGroups = []; + # workaround to remove dev-dependencies for the current combination of legacy + # used by authentik and poetry2nix's behavior + pyproject = builtins.toFile "patched-pyproject.toml" (lib.replaceStrings + ["tool.poetry.dev-dependencies"] + ["tool.poetry.group.dev.dependencies"] + (builtins.readFile "${authentik-src}/pyproject.toml") + ); +} diff --git a/components/staticWorkdirDeps.nix b/components/staticWorkdirDeps.nix new file mode 100644 index 0000000..6fd890a --- /dev/null +++ b/components/staticWorkdirDeps.nix @@ -0,0 +1,14 @@ +{ authentik-src +, authentikComponents +, linkFarm +}: + +linkFarm "authentik-static-workdir-deps" [ + { name = "authentik"; path = "${authentik-src}/authentik"; } + { name = "locale"; path = "${authentik-src}/locale"; } + { name = "blueprints"; path = "${authentik-src}/blueprints"; } + { name = "internal"; path = "${authentik-src}/internal"; } + { name = "lifecycle"; path = "${authentik-src}/lifecycle"; } + { name = "schemas"; path = "${authentik-src}/schemas"; } + { name = "web"; path = authentikComponents.frontend; } +] diff --git a/flake.nix b/flake.nix index 3f232c7..bcff90b 100644 --- a/flake.nix +++ b/flake.nix @@ -62,134 +62,40 @@ )); }; }; - perSystem = { pkgs, system, ... }: let + perSystem = { pkgs, system, self', ... }: let inherit (import inputs.poetry2nix { inherit pkgs; }) mkPoetryEnv defaultPoetryOverrides; + authentikComponents = { + inherit (self'.packages) celery staticWorkdirDeps migrate pythonEnv frontend gopkgs docs; }; + authentikPoetryOverrides = import ./poetry2nix-python-overrides.nix pkgs; in { - packages = rec { - docs = napalm.legacyPackages.${system}.buildPackage "${authentik-src}/website" { - version = authentik-version; # 0.0.0 specified upstream in package.json - NODE_ENV = "production"; - nodejs = pkgs.nodejs_20; - npmCommands = [ - "cp -v ${authentik-src}/SECURITY.md ../SECURITY.md" - "cp -vr ${authentik-src}/blueprints ../blueprints" - "npm install --include=dev" - "npm run build-docs-only" - ]; - installPhase = '' - rm -r ../website/node_modules/.cache - mv -v ../website $out - ''; + packages = { + docs = pkgs.callPackage components/docs.nix { + buildNapalmPackage = napalm.legacyPackages.${system}.buildPackage; + inherit authentik-src authentik-version; }; - frontend = napalm.legacyPackages.${system}.buildPackage "${authentik-src}/web" rec { - version = authentik-version; # 0.0.0 specified upstream in package.json - NODE_ENV = "production"; - nodejs = pkgs.nodejs_21; - preBuild = '' - ln -sv ${docs} ../website - ''; - npmCommands = [ - "npm install --include=dev --nodedir=${nodejs}/include/node --loglevel verbose --ignore-scripts" - "npm run build" - ]; - installPhase = '' - mkdir $out - mv dist $out/dist - cp -r authentik icons $out - ''; + frontend = pkgs.callPackage components/frontend.nix { + buildNapalmPackage = napalm.legacyPackages.${system}.buildPackage; + inherit authentik-src authentik-version authentikComponents; }; - pythonEnv = mkPoetryEnv { - projectDir = authentik-src; - python = pkgs.python311; - overrides = [ defaultPoetryOverrides ] ++ (import ./poetry2nix-python-overrides.nix pkgs); - groups = []; - checkGroups = []; - # workaround to remove dev-dependencies for the current combination of legacy pyproject.toml format - # used by authentik and poetry2nix's behavior - pyproject = builtins.toFile "patched-pyproject.toml" (lib.replaceStrings - ["tool.poetry.dev-dependencies"] - ["tool.poetry.group.dev.dependencies"] - (builtins.readFile "${authentik-src}/pyproject.toml") - ); + pythonEnv = pkgs.callPackage components/pythonEnv.nix { + inherit authentik-src mkPoetryEnv defaultPoetryOverrides authentikPoetryOverrides; }; # server + outposts - gopkgs = pkgs.buildGo121Module { - pname = "authentik-gopkgs"; - version = authentik-version; - prePatch = '' - sed -i"" -e 's,./web/dist/,${frontend}/dist/,' web/static.go - sed -i"" -e 's,./web/dist/,${frontend}/dist/,' internal/web/static.go - sed -i"" -e 's,./lifecycle/gunicorn.conf.py,${staticWorkdirDeps}/lifecycle/gunicorn.conf.py,' internal/gounicorn/gounicorn.go - ''; - src = pkgs.lib.cleanSourceWith { - src = authentik-src; - filter = (path: _: - (builtins.any (x: x) ( - (map (infix: pkgs.lib.hasInfix infix path) [ - "/authentik" - "/cmd" - "/internal" - ]) - ++ - (map (suffix: pkgs.lib.hasSuffix suffix path) [ - "/web" - "/web/static.go" - "/web/robots.txt" - "/web/security.txt" - "go.mod" - "go.sum" - ]) - )) - ); - }; - subPackages = [ - "cmd/ldap" - "cmd/server" - "cmd/proxy" - "cmd/radius" - ]; - vendorSha256 = "sha256-8F9emmQmbe7R+xtGrjV5ht0adGasU6WAvLa8Wxr+j8M="; - nativeBuildInputs = [ pkgs.makeWrapper ]; - postInstall = '' - wrapProgram $out/bin/server --prefix PATH : ${pythonEnv}/bin - wrapProgram $out/bin/server --prefix PYTHONPATH : ${staticWorkdirDeps} - ''; + gopkgs = pkgs.callPackage components/gopkgs.nix { + inherit authentik-src authentik-version authentikComponents; + }; + staticWorkdirDeps = pkgs.callPackage components/staticWorkdirDeps.nix { + inherit authentik-src authentikComponents; + }; + migrate = pkgs.callPackage components/migrate.nix { + inherit authentik-src authentikComponents; }; - staticWorkdirDeps = pkgs.linkFarm "authentik-static-workdir-deps" [ - { name = "authentik"; path = "${authentik-src}/authentik"; } - { name = "locale"; path = "${authentik-src}/locale"; } - { name = "blueprints"; path = "${authentik-src}/blueprints"; } - { name = "internal"; path = "${authentik-src}/internal"; } - { name = "lifecycle"; path = "${authentik-src}/lifecycle"; } - { name = "schemas"; path = "${authentik-src}/schemas"; } - { name = "web"; path = frontend; } - ]; - migrate = pkgs.runCommandLocal "authentik-migrate.py" { - nativeBuildInputs = [ pkgs.makeWrapper ]; - } '' - mkdir -vp $out/bin - cp ${authentik-src}/lifecycle/migrate.py $out/bin/migrate.py - chmod +w $out/bin/migrate.py - patchShebangs $out/bin/migrate.py - substituteInPlace $out/bin/migrate.py \ - --replace \ - 'migration_path in Path(__file__).parent.absolute().glob("system_migrations/*.py")' \ - 'migration_path in Path("${staticWorkdirDeps}/lifecycle").glob("system_migrations/*.py")' - wrapProgram $out/bin/migrate.py \ - --prefix PATH : ${pythonEnv}/bin \ - --prefix PYTHONPATH : ${staticWorkdirDeps} - ''; # worker - celery = pkgs.runCommandLocal "authentik-celery" { - nativeBuildInputs = [ pkgs.makeWrapper ]; - } '' - mkdir -vp $out/bin - ln -sv ${pythonEnv}/bin/celery $out/bin/celery - wrapProgram $out/bin/celery \ - --prefix PYTHONPATH : ${staticWorkdirDeps} - ''; + celery = pkgs.callPackage components/celery.nix { + inherit authentikComponents; + }; # terraform provider terraform-provider-authentik = inputs.nixpkgs-23-05.legacyPackages.${system}.buildGo118Module rec { pname = "terraform-provider-authentik";