Merge pull request #323613 from CyberShadow/fix-nix-path-without-channels-v2

nix-channel: do not set empty nix-path when disabling channels
This commit is contained in:
Robert Hensing 2024-07-28 13:31:10 +02:00 committed by GitHub
commit 4ca52fdf5f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 291 additions and 7 deletions

View File

@ -116,6 +116,55 @@ It has two modes:
: The `lychee` package to use.
## `shellcheck` {#tester-shellcheck}
Runs files through `shellcheck`, a static analysis tool for shell scripts.
:::{.example #ex-shellcheck}
# Run `testers.shellcheck`
A single script
```nix
testers.shellcheck {
name = "shellcheck";
src = ./script.sh;
}
```
Multiple files
```nix
let
inherit (lib) fileset;
in
testers.shellcheck {
name = "shellcheck";
src = fileset.toSource {
root = ./.;
fileset = fileset.unions [
./lib.sh
./nixbsd-activate
];
};
}
```
:::
### Inputs {#tester-shellcheck-inputs}
[`src` (path or string)]{#tester-shellcheck-param-src}
: The path to the shell script(s) to check.
This can be a single file or a directory containing shell files.
All files in `src` will be checked, so you may want to provide `fileset`-based source instead of a whole directory.
### Return value {#tester-shellcheck-return}
A derivation that runs `shellcheck` on the given script(s).
The build will fail if `shellcheck` finds any issues.
## `testVersion` {#tester-testVersion}
Checks that the output from running a command contains the specified version string in it as a whole word.

View File

@ -12,6 +12,7 @@ let
mkDefault
mkIf
mkOption
stringAfter
types
;
@ -97,5 +98,8 @@ in
systemd.tmpfiles.rules = lib.mkIf cfg.channel.enable [
''f /root/.nix-channels - - - - ${config.system.defaultChannel} nixos\n''
];
system.activationScripts.no-nix-channel = mkIf (!cfg.channel.enable)
(stringAfter [ "etc" "users" ] (builtins.readFile ./nix-channel/activation-check.sh));
};
}

View File

@ -0,0 +1,21 @@
# shellcheck shell=bash
explainChannelWarning=0
if [[ -e "/root/.nix-defexpr/channels" ]]; then
warn '/root/.nix-defexpr/channels exists, but channels have been disabled.'
explainChannelWarning=1
fi
if [[ -e "/nix/var/nix/profiles/per-user/root/channels" ]]; then
warn "/nix/var/nix/profiles/per-user/root/channels exists, but channels have been disabled."
explainChannelWarning=1
fi
while IFS=: read -r _ _ _ _ _ home _ ; do
if [[ -n "$home" && -e "$home/.nix-defexpr/channels" ]]; then
warn "$home/.nix-defexpr/channels exists, but channels have been disabled." 1>&2
explainChannelWarning=1
fi
done < <(getent passwd)
if [[ $explainChannelWarning -eq 1 ]]; then
echo "Due to https://github.com/NixOS/nix/issues/9574, Nix may still use these channels when NIX_PATH is unset." 1>&2
echo "Delete the above directory or directories to prevent this." 1>&2
fi

View File

@ -0,0 +1,19 @@
# Run:
# nix-build -A nixosTests.nix-channel
{ lib, testers }:
let
inherit (lib) fileset;
runShellcheck = testers.shellcheck {
src = fileset.toSource {
root = ./.;
fileset = fileset.unions [
./activation-check.sh
];
};
};
in
lib.recurseIntoAttrs {
inherit runShellcheck;
}

View File

@ -33,6 +33,8 @@ let
''
#!${pkgs.runtimeShell}
source ${./lib/lib.sh}
systemConfig='@out@'
export PATH=/empty

View File

@ -0,0 +1,5 @@
# shellcheck shell=bash
warn() {
printf "\033[1;35mwarning:\033[0m %s\n" "$*" >&2
}

View File

@ -0,0 +1,36 @@
# Run:
# nix-build -A nixosTests.activation-lib
{ lib, stdenv, testers }:
let
inherit (lib) fileset;
runTests = stdenv.mkDerivation {
name = "tests-activation-lib";
src = fileset.toSource {
root = ./.;
fileset = fileset.unions [
./lib.sh
./test.sh
];
};
buildPhase = ":";
doCheck = true;
postUnpack = ''
patchShebangs --build .
'';
checkPhase = ''
./test.sh
'';
installPhase = ''
touch $out
'';
};
runShellcheck = testers.shellcheck {
src = runTests.src;
};
in
lib.recurseIntoAttrs {
inherit runTests runShellcheck;
}

View File

@ -0,0 +1,34 @@
#!/usr/bin/env bash
# Run:
# ./test.sh
# or:
# nix-build -A nixosTests.activation-lib
cd "$(dirname "${BASH_SOURCE[0]}")"
set -euo pipefail
# report failure
onerr() {
set +e
# find failed statement
echo "call trace:"
local i=0
while t="$(caller $i)"; do
line="${t%% *}"
file="${t##* }"
echo " $file:$line" >&2
((i++))
done
# red
printf "\033[1;31mtest failed\033[0m\n" >&2
exit 1
}
trap onerr ERR
source ./lib.sh
(warn hi, this works >/dev/null) 2>&1 | grep -E $'.*warning:.* hi, this works' >/dev/null
# green
printf "\033[1;32mok\033[0m\n"

View File

@ -301,6 +301,7 @@ in {
esphome = handleTest ./esphome.nix {};
etc = pkgs.callPackage ../modules/system/etc/test.nix { inherit evalMinimalConfig; };
activation = pkgs.callPackage ../modules/system/activation/test.nix { };
activation-lib = pkgs.callPackage ../modules/system/activation/lib/test.nix { };
activation-var = runTest ./activation/var.nix;
activation-nix-channel = runTest ./activation/nix-channel.nix;
activation-etc-overlay-mutable = runTest ./activation/etc-overlay-mutable.nix;
@ -624,6 +625,7 @@ in {
nbd = handleTest ./nbd.nix {};
ncdns = handleTest ./ncdns.nix {};
ndppd = handleTest ./ndppd.nix {};
nix-channel = pkgs.callPackage ../modules/config/nix-channel/test.nix { };
nebula = handleTest ./nebula.nix {};
netbird = handleTest ./netbird.nix {};
nimdow = handleTest ./nimdow.nix {};

View File

@ -463,7 +463,32 @@ let
""")
with subtest("Switch to flake based config"):
target.succeed("nixos-rebuild switch --flake /root/my-config#xyz")
target.succeed("nixos-rebuild switch --flake /root/my-config#xyz 2>&1 | tee activation-log >&2")
target.succeed("""
cat -n activation-log >&2
""")
target.succeed("""
grep -F '/root/.nix-defexpr/channels exists, but channels have been disabled.' activation-log
""")
target.succeed("""
grep -F '/nix/var/nix/profiles/per-user/root/channels exists, but channels have been disabled.' activation-log
""")
target.succeed("""
grep -F '/root/.nix-defexpr/channels exists, but channels have been disabled.' activation-log
""")
target.succeed("""
grep -F 'Due to https://github.com/NixOS/nix/issues/9574, Nix may still use these channels when NIX_PATH is unset.' activation-log
""")
target.succeed("rm activation-log")
# Perform the suggested cleanups we've just seen in the log
# TODO after https://github.com/NixOS/nix/issues/9574: don't remove them yet
target.succeed("""
rm -rf /root/.nix-defexpr/channels /nix/var/nix/profiles/per-user/root/channels /root/.nix-defexpr/channels
""")
target.shutdown()
@ -474,10 +499,20 @@ let
# Note that the channel profile is still present on disk, but configured
# not to be used.
with subtest("builtins.nixPath is now empty"):
target.succeed("""
[[ "[ ]" == "$(nix-instantiate builtins.nixPath --eval --expr)" ]]
""")
# TODO after issue https://github.com/NixOS/nix/issues/9574: re-enable this assertion
# I believe what happens is
# - because of the issue, we've removed the `nix-path =` line from nix.conf
# - the "backdoor" shell is not a proper session and does not have `NIX_PATH=""` set
# - seeing no nix path settings at all, Nix loads its hardcoded default value,
# which is unfortunately non-empty
# Or maybe it's the new default NIX_PATH?? :(
# with subtest("builtins.nixPath is now empty"):
# target.succeed("""
# (
# set -x;
# [[ "[ ]" == "$(nix-instantiate builtins.nixPath --eval --expr)" ]];
# )
# """)
with subtest("<nixpkgs> does not resolve"):
target.succeed("""
@ -491,12 +526,16 @@ let
target.succeed("""
(
exec 1>&2
rm -v /root/.nix-channels
rm -vf /root/.nix-channels
rm -vrf ~/.nix-defexpr
rm -vrf /nix/var/nix/profiles/per-user/root/channels*
)
""")
target.succeed("nixos-rebuild switch --flake /root/my-config#xyz")
target.succeed("nixos-rebuild switch --flake /root/my-config#xyz | tee activation-log >&2")
target.succeed("cat -n activation-log >&2")
target.succeed("! grep -F '/root/.nix-defexpr/channels' activation-log")
target.succeed("! grep -F 'but channels have been disabled' activation-log")
target.succeed("! grep -F 'https://github.com/NixOS/nix/issues/9574' activation-log")
target.shutdown()
'';

View File

@ -140,4 +140,6 @@
hasPkgConfigModules = callPackage ./hasPkgConfigModules/tester.nix { };
testMetaPkgConfig = callPackage ./testMetaPkgConfig/tester.nix { };
shellcheck = callPackage ./shellcheck/tester.nix { };
}

View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
echo $@

View File

@ -0,0 +1,28 @@
# Dependencies (callPackage)
{ lib, stdenv, shellcheck }:
# testers.shellcheck function
# Docs: doc/build-helpers/testers.chapter.md
# Tests: ./tests.nix
{ src }:
let
inherit (lib) fileset pathType isPath;
in
stdenv.mkDerivation {
name = "run-shellcheck";
src =
if isPath src && pathType src == "regular" # note that for strings this would have been IFD, which we prefer to avoid
then fileset.toSource { root = dirOf src; fileset = src; }
else src;
nativeBuildInputs = [ shellcheck ];
doCheck = true;
dontConfigure = true;
dontBuild = true;
checkPhase = ''
find . -type f -print0 \
| xargs -0 shellcheck
'';
installPhase = ''
touch $out
'';
}

View File

@ -0,0 +1,38 @@
# Run:
# nix-build -A tests.testers.shellcheck
{ lib, testers, runCommand }:
let
inherit (lib) fileset;
in
lib.recurseIntoAttrs {
example-dir = runCommand "test-testers-shellcheck-example-dir" {
failure = testers.testBuildFailure
(testers.shellcheck {
src = fileset.toSource {
root = ./.;
fileset = fileset.unions [
./example.sh
];
};
});
} ''
log="$failure/testBuildFailure.log"
echo "Checking $log"
grep SC2068 "$log"
touch $out
'';
example-file = runCommand "test-testers-shellcheck-example-file" {
failure = testers.testBuildFailure
(testers.shellcheck {
src = ./example.sh;
});
} ''
log="$failure/testBuildFailure.log"
echo "Checking $log"
grep SC2068 "$log"
touch $out
'';
}

View File

@ -16,6 +16,8 @@ lib.recurseIntoAttrs {
hasPkgConfigModules = pkgs.callPackage ../hasPkgConfigModules/tests.nix { };
shellcheck = pkgs.callPackage ../shellcheck/tests.nix { };
runNixOSTest-example = pkgs-with-overlay.testers.runNixOSTest ({ lib, ... }: {
name = "runNixOSTest-test";
nodes.machine = { pkgs, ... }: {