php: assert the security floor via config.assertions, not a module-level assert

The previous commit moved the CVE-2026-109618/109619 floor into a bare
`assert ... ; { ... }` above the module body.  That breaks evaluation:

  error: infinite recursion encountered
  ... while evaluating the module argument `pkgs` in
      /nix/store/...-source/modules/php.nix
  ... noting that argument `pkgs` is not externally provided, so querying
      `_module.args` instead, requiring `config`

A module-level assert is checked as soon as the module's attrset is forced
to WHNF, which the module system does while merging definitions (it is the
`checkUnmatched` branch in lib/modules.nix that was on the stack).  At that
point `pkgs` is not an externally supplied argument — there are no
specialArgs here — so it resolves through `config._module.args.pkgs`
(lib/modules.nix:745), and that option lives in the same fixpoint that is
still being computed.  Hence the loop.  The old code never hit this because
`phpBase` was only forced from inside `options`/`config`, i.e. after the
fixpoint existed.

Move the check to `config.assertions`, which is evaluated inside the
fixpoint once `pkgs` is available.  Behaviour is unchanged: a rolled-back
nixpkgs pin still fails the build with the floor message instead of
silently building a vulnerable PHP.
This commit is contained in:
naturallaw777 committed 2026-10-26 21:27:00 -05:00
1 parent 6151c78dc5
commit 9a4a4ee51a
1 file changed
+23 -6
+23 -6
View File
@@ -103,12 +103,6 @@ let
}; };
in in
assert lib.assertMsg (lib.versionAtLeast phpBase.version phpSecurityFloor) ''
sovran_systemsOS: the pinned nixpkgs ships PHP ${phpBase.version}, below the
security floor ${phpSecurityFloor} (CVE-2026-109618 / CVE-2026-109619).
Update the nixpkgs input in flake.lock instead of pinning a version here.
'';
{ {
options.sovran_systemsOS.phpPackage = lib.mkOption { options.sovran_systemsOS.phpPackage = lib.mkOption {
type = lib.types.package; type = lib.types.package;
@@ -117,6 +111,29 @@ assert lib.assertMsg (lib.versionAtLeast phpBase.version phpSecurityFloor) ''
}; };
config = { config = {
# Security floor. This has to live in `config.assertions`, NOT in a
# module-level `assert` above the module body: a bare
# `assert <cond>; { ... }` forces `phpBase` (and therefore `pkgs`) as
# soon as the module's attrset is forced to WHNF, which happens while
# the module system is still merging `_module.args`. `pkgs` is not an
# externally supplied argument here, so it resolves through
# `config._module.args.pkgs` (lib/modules.nix:745) — which requires
# `config`, the very fixpoint being computed — giving
# "error: infinite recursion encountered" pointing at modules/php.nix.
# `config.assertions` is evaluated inside the fixpoint, once `pkgs`
# exists, which is the supported way to assert on package versions.
assertions = [
{
assertion = lib.versionAtLeast phpBase.version phpSecurityFloor;
message = ''
sovran_systemsOS: the pinned nixpkgs ships PHP ${phpBase.version},
below the security floor ${phpSecurityFloor} (CVE-2026-109618 /
CVE-2026-109619). Update the nixpkgs input in flake.lock instead
of pinning a version in modules/php.nix.
'';
}
];
users.users = { users.users = {
php = { php = {