nixpkgs/nixos/tests/angrr.nix
2026-06-21 01:09:25 +08:00

240 lines
12 KiB
Nix

{ pkgs, ... }:
let
drvForTest =
name:
pkgs.runCommand "angrr-test-${name}" { } ''
mkdir --parents "$out"
echo "${name}" >"$out/${name}"
'';
in
{
name = "angrr";
nodes = {
machine = {
services.angrr = {
enable = true;
settings = {
temporary-root-policies = {
result = {
path-regex = "/result[^/]*$";
period = "7d";
};
direnv = {
path-regex = "/\\.direnv/";
period = "14d";
};
};
profile-policies = {
system = {
profile-paths = [ "/nix/var/nix/profiles/system" ];
keep-since = "7d"; # do not keep based on time
keep-latest-n = 2; # keep latest
keep-current-system = true;
keep-booted-system = true;
};
user = {
profile-paths = [
"~/.local/state/nix/profiles/profile"
"/nix/var/nix/profiles/per-user/root/profile"
];
# keep-since = "0d"; # do not keep based on time
keep-latest-n = 2;
};
};
touch = {
project-globs = [
"!result-glob-ignored"
];
};
};
};
# `angrr.service` integrates to `nix-gc.service` by default
nix.gc.automatic = true;
# Create a normal nix user for test
users.users.normal.isNormalUser = true;
# For `nix build /run/current-system --out-link`,
# `nix-build` does not support this use case.
nix.settings.experimental-features = [ "nix-command" ];
# Test direnv integration
programs.direnv.enable = true;
# Verbose logging for angrr in direnv
environment.variables.ANGRR_DIRENV_LOG = "debug";
# Add some store paths to machine for test
environment.etc."drvs-for-test".text = ''
${drvForTest "drv1"}
${drvForTest "drv2"}
${drvForTest "drv3"}
${drvForTest "drv4"}
${drvForTest "drv5"}
${drvForTest "drv6"}
${drvForTest "drv7"}
${drvForTest "drv8"}
${drvForTest "fake-booted-system"}
'';
# Unit start limit workaround
systemd.services.angrr.unitConfig.StartLimitBurst = 10;
};
};
testScript = ''
start_all()
machine.wait_for_unit("default.target")
machine.systemctl("stop nix-gc.timer")
# Creates some auto gc roots
# Use /run/current-system so that we do not need to build anything new
machine.succeed("nix build /run/current-system --out-link /tmp/result-root-auto-gc-root-1")
machine.succeed("nix build /run/current-system --out-link /tmp/result-root-auto-gc-root-2")
machine.succeed("su normal --command 'nix build /run/current-system --out-link /tmp/result-user-auto-gc-root-1'")
machine.succeed("su normal --command 'nix build /run/current-system --out-link /tmp/result-user-auto-gc-root-2'")
machine.systemctl("start nix-gc.service")
# No auto gc root will be removed
machine.succeed("readlink /tmp/result-root-auto-gc-root-1")
machine.succeed("readlink /tmp/result-root-auto-gc-root-2")
machine.succeed("readlink /tmp/result-user-auto-gc-root-1")
machine.succeed("readlink /tmp/result-user-auto-gc-root-2")
# Change time to 8 days after (greater than 7d)
machine.succeed("date -s '8 days'")
# Touch GC roots `-2`
machine.succeed("touch /tmp/result-root-auto-gc-root-2 --no-dereference")
machine.succeed("touch /tmp/result-user-auto-gc-root-2 --no-dereference")
machine.systemctl("start angrr.service")
# Only GC roots `-1` are removed
machine.succeed("test ! -e /tmp/result-root-auto-gc-root-1")
machine.succeed("readlink /tmp/result-root-auto-gc-root-2")
machine.succeed("test ! -e /tmp/result-user-auto-gc-root-1")
machine.succeed("readlink /tmp/result-user-auto-gc-root-2")
# Change time again
machine.succeed("date -s '8 days'")
machine.systemctl("start angrr.service")
# All auto GC roots are removed
machine.succeed("test ! -e /tmp/result-root-auto-gc-root-2")
machine.succeed("test ! -e /tmp/result-user-auto-gc-root-2")
# Direnv integration test
machine.succeed("mkdir /tmp/test-direnv")
machine.succeed("echo >/tmp/test-direnv/.envrc") # Simply create an empty .envrc
machine.succeed("nix build /run/current-system --out-link /tmp/test-direnv/.direnv/gc-root")
machine.succeed("nix build /run/current-system --out-link /tmp/test-direnv/result")
machine.succeed("cd /tmp/test-direnv; direnv allow; direnv exec . true")
# The root will be removed if we does not use the direnv recently
machine.succeed("date -s '15 days'")
machine.systemctl("start angrr.service")
machine.succeed("test ! -e /tmp/test-direnv/.direnv/gc-root")
machine.succeed("test ! -e /tmp/test-direnv/result")
# Recreate the root
machine.succeed("nix build /run/current-system --out-link /tmp/test-direnv/.direnv/gc-root")
machine.succeed("nix build /run/current-system --out-link /tmp/test-direnv/result")
machine.succeed("nix build /run/current-system --out-link /tmp/test-direnv/result-glob-ignored")
machine.succeed("nix build /run/current-system --out-link /tmp/test-outside-direnv/result")
# The root will not be remove if we use the direnv recently
machine.succeed("date -s '15 days'")
# test the case that $PWD is different from project root
machine.succeed("cd /tmp; direnv exec /tmp/test-direnv true")
machine.systemctl("start angrr.service")
machine.succeed("readlink /tmp/test-direnv/.direnv/gc-root")
machine.succeed("readlink /tmp/test-direnv/result")
machine.succeed("test ! -e /tmp/test-direnv/result-glob-ignored")
machine.succeed("test ! -e /tmp/test-outside-direnv/result")
# System profile policy test
# Create a profile for test
machine.succeed("mkdir /tmp/profile-test")
machine.succeed("nix-env --profile /nix/var/nix/profiles/system --set ${drvForTest "drv1"}") # generation 1
machine.succeed("nix-env --profile /nix/var/nix/profiles/system --set ${drvForTest "drv2"}") # generation 2
machine.succeed("nix-env --profile /nix/var/nix/profiles/system --set ${drvForTest "drv3"}") # generation 3
machine.succeed("ln --symbolic --force --no-dereference ${drvForTest "fake-booted-system"} /run/booted-system")
machine.succeed("nix-env --profile /nix/var/nix/profiles/system --set /run/booted-system") # generation 4
machine.succeed("nix-env --profile /nix/var/nix/profiles/system --set /run/current-system") # generation 5
machine.succeed("date -s '8 days'")
machine.succeed("nix-env --profile /nix/var/nix/profiles/system --set ${drvForTest "drv4"}") # generation 6
machine.succeed("nix-env --profile /nix/var/nix/profiles/system --set ${drvForTest "drv5"}") # generation 7
machine.succeed("nix-env --profile /nix/var/nix/profiles/system --set ${drvForTest "drv6"}") # generation 8
machine.succeed("nix-env --profile /nix/var/nix/profiles/system --set ${drvForTest "drv7"}") # generation 9
machine.succeed("nix-env --profile /nix/var/nix/profiles/system --set ${drvForTest "drv8"}") # generation 10
# Rollback to generation 2 to simulate current system
for _ in range(0, 10 - 2):
machine.succeed("nix-env --rollback --profile /nix/var/nix/profiles/system")
# Run policy
machine.systemctl("start angrr.service")
# Test
machine.succeed("sh -c 'test $(readlink /nix/var/nix/profiles/system) = system-2-link'")
machine.succeed("test ! -e /nix/var/nix/profiles/system-1-link")
machine.succeed("readlink /nix/var/nix/profiles/system-2-link") # Keep since it is current generation
machine.succeed("test ! -e /nix/var/nix/profiles/system-3-link")
machine.succeed("readlink /nix/var/nix/profiles/system-4-link") # Keep by keep-booted-system
machine.succeed("readlink /nix/var/nix/profiles/system-5-link") # Keep by keep-current-system
machine.succeed("readlink /nix/var/nix/profiles/system-6-link") # Keep by keep-since
machine.succeed("readlink /nix/var/nix/profiles/system-7-link") # Keep by keep-since
machine.succeed("readlink /nix/var/nix/profiles/system-8-link") # Keep by keep-since
machine.succeed("readlink /nix/var/nix/profiles/system-9-link") # Keep by keep-latest-n
machine.succeed("readlink /nix/var/nix/profiles/system-10-link") # Keep by keep-latest-n
# User profile policy test 1
# Normal user
machine.succeed("su normal --command 'nix profile add ${drvForTest "drv1"}'")
machine.succeed("su normal --command 'nix profile add ${drvForTest "drv2"}'")
machine.succeed("su normal --command 'nix profile add ${drvForTest "drv3"}'")
# Root user
machine.succeed("nix profile add ${drvForTest "drv1"}")
machine.succeed("nix profile add ${drvForTest "drv2"}")
machine.succeed("nix profile add ${drvForTest "drv3"}")
# Run policy
machine.systemctl("start angrr.service")
# Test
machine.succeed("sh -c 'test $(readlink ~normal/.local/state/nix/profiles/profile) = profile-3-link'")
machine.succeed("test ! -e ~normal/.local/state/nix/profiles/profile-1-link")
machine.succeed("readlink ~normal/.local/state/nix/profiles/profile-2-link") # Keep by keep-latest-n
machine.succeed("readlink ~normal/.local/state/nix/profiles/profile-3-link") # Keep since it is current generation
machine.succeed("sh -c 'test $(readlink /nix/var/nix/profiles/per-user/root/profile) = profile-3-link'")
machine.succeed("test ! -e /nix/var/nix/profiles/per-user/root/profile-1-link")
machine.succeed("readlink /nix/var/nix/profiles/per-user/root/profile-2-link") # Keep by keep-latest-n
machine.succeed("readlink /nix/var/nix/profiles/per-user/root/profile-3-link") # Keep since it is current generation
# User profile policy test 2
# Create GC roots again
machine.succeed("su normal --command 'nix profile add ${drvForTest "drv1"}'")
machine.succeed("su normal --command 'nix profile add ${drvForTest "drv2"}'")
machine.succeed("su normal --command 'nix profile add ${drvForTest "drv3"}'")
machine.succeed("nix profile add ${drvForTest "drv1"}")
machine.succeed("nix profile add ${drvForTest "drv2"}")
machine.succeed("nix profile add ${drvForTest "drv3"}")
# Run policy in owned-only mode as normal user
machine.succeed("su normal --command 'angrr run --no-prompt'")
# Test
machine.succeed("sh -c 'test $(readlink ~normal/.local/state/nix/profiles/profile) = profile-6-link'")
machine.succeed("test ! -e ~normal/.local/state/nix/profiles/profile-1-link")
machine.succeed("test ! -e ~normal/.local/state/nix/profiles/profile-2-link")
machine.succeed("test ! -e ~normal/.local/state/nix/profiles/profile-3-link")
machine.succeed("test ! -e ~normal/.local/state/nix/profiles/profile-4-link")
machine.succeed("readlink ~normal/.local/state/nix/profiles/profile-5-link") # Keep by keep-latest-n
machine.succeed("readlink ~normal/.local/state/nix/profiles/profile-6-link") # Keep since it is current generation
machine.succeed("sh -c 'test $(readlink /nix/var/nix/profiles/per-user/root/profile) = profile-6-link'")
machine.succeed("test ! -e /nix/var/nix/profiles/per-user/root/profile-1-link")
machine.succeed("readlink /nix/var/nix/profiles/per-user/root/profile-2-link")
machine.succeed("readlink /nix/var/nix/profiles/per-user/root/profile-3-link")
machine.succeed("readlink /nix/var/nix/profiles/per-user/root/profile-4-link") # Not monitored
machine.succeed("readlink /nix/var/nix/profiles/per-user/root/profile-5-link") # Not monitored
machine.succeed("readlink /nix/var/nix/profiles/per-user/root/profile-6-link") # Not monitored
'';
}