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.
This commit is contained in:
WilliButz 2023-12-09 16:01:26 +01:00
parent d12bdcc87d
commit 6df56466f9
No known key found for this signature in database
GPG key ID: FB0513677AB15BEA
8 changed files with 191 additions and 118 deletions

13
components/celery.nix Normal file
View file

@ -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}
''

21
components/docs.nix Normal file
View file

@ -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
'';
}

24
components/frontend.nix Normal file
View file

@ -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
'';
}

50
components/gopkgs.nix Normal file
View file

@ -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}
'';
}

21
components/migrate.nix Normal file
View file

@ -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}
''

24
components/pythonEnv.nix Normal file
View file

@ -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")
);
}

View file

@ -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; }
]

142
flake.nix
View file

@ -62,134 +62,40 @@
)); ));
}; };
}; };
perSystem = { pkgs, system, ... }: let perSystem = { pkgs, system, self', ... }: let
inherit (import inputs.poetry2nix { inherit pkgs; }) inherit (import inputs.poetry2nix { inherit pkgs; })
mkPoetryEnv mkPoetryEnv
defaultPoetryOverrides; defaultPoetryOverrides;
authentikComponents = {
inherit (self'.packages) celery staticWorkdirDeps migrate pythonEnv frontend gopkgs docs; };
authentikPoetryOverrides = import ./poetry2nix-python-overrides.nix pkgs;
in { in {
packages = rec { packages = {
docs = napalm.legacyPackages.${system}.buildPackage "${authentik-src}/website" { docs = pkgs.callPackage components/docs.nix {
version = authentik-version; # 0.0.0 specified upstream in package.json buildNapalmPackage = napalm.legacyPackages.${system}.buildPackage;
NODE_ENV = "production"; inherit authentik-src authentik-version;
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
'';
}; };
frontend = napalm.legacyPackages.${system}.buildPackage "${authentik-src}/web" rec { frontend = pkgs.callPackage components/frontend.nix {
version = authentik-version; # 0.0.0 specified upstream in package.json buildNapalmPackage = napalm.legacyPackages.${system}.buildPackage;
NODE_ENV = "production"; inherit authentik-src authentik-version authentikComponents;
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
'';
}; };
pythonEnv = mkPoetryEnv { pythonEnv = pkgs.callPackage components/pythonEnv.nix {
projectDir = authentik-src; inherit authentik-src mkPoetryEnv defaultPoetryOverrides authentikPoetryOverrides;
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")
);
}; };
# server + outposts # server + outposts
gopkgs = pkgs.buildGo121Module { gopkgs = pkgs.callPackage components/gopkgs.nix {
pname = "authentik-gopkgs"; inherit authentik-src authentik-version authentikComponents;
version = authentik-version; };
prePatch = '' staticWorkdirDeps = pkgs.callPackage components/staticWorkdirDeps.nix {
sed -i"" -e 's,./web/dist/,${frontend}/dist/,' web/static.go inherit authentik-src authentikComponents;
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 migrate = pkgs.callPackage components/migrate.nix {
''; inherit authentik-src authentikComponents;
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}
'';
}; };
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 # worker
celery = pkgs.runCommandLocal "authentik-celery" { celery = pkgs.callPackage components/celery.nix {
nativeBuildInputs = [ pkgs.makeWrapper ]; inherit authentikComponents;
} '' };
mkdir -vp $out/bin
ln -sv ${pythonEnv}/bin/celery $out/bin/celery
wrapProgram $out/bin/celery \
--prefix PYTHONPATH : ${staticWorkdirDeps}
'';
# terraform provider # terraform provider
terraform-provider-authentik = inputs.nixpkgs-23-05.legacyPackages.${system}.buildGo118Module rec { terraform-provider-authentik = inputs.nixpkgs-23-05.legacyPackages.${system}.buildGo118Module rec {
pname = "terraform-provider-authentik"; pname = "terraform-provider-authentik";