Merge staging-nixos into master (nix security update) (#516623)
This commit is contained in:
@@ -160,6 +160,8 @@
|
||||
|
||||
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
|
||||
|
||||
- `systemd.coredump.extraConfig` has been removed in favor of the structured [](#opt-systemd.coredump.settings.Coredump) option. Use `systemd.coredump.settings.Coredump` to set any `coredump.conf(5)` option directly. For example, replace `systemd.coredump.extraConfig = "Storage=journal";` with `systemd.coredump.settings.Coredump.Storage = "journal";`.
|
||||
|
||||
- `opentrack`, `slushload`, `synthesia`, `vtfedit`, `winbox`, `wineasio`, and `yabridge` use wineWow64Packages instead of wineWowPackages as wine versions >= 11.0 have deprecated wineWowPackages. As such, the prefixes for these packages are NOT backwards compatible and need to be regenerated with potential for data loss.
|
||||
|
||||
- []{#sec-release-26.05-incompatibilities-profiles-hardened-removed} `profiles/hardened` has been removed, because:
|
||||
|
||||
@@ -8,7 +8,6 @@ version = "0.0.0"
|
||||
|
||||
[project.scripts]
|
||||
nixos-test-driver = "test_driver:main"
|
||||
generate-driver-symbols = "test_driver:generate_driver_symbols"
|
||||
|
||||
[tool.setuptools.packages]
|
||||
find = {}
|
||||
|
||||
@@ -6,9 +6,10 @@ import warnings
|
||||
from pathlib import Path
|
||||
|
||||
import ptpython.ipython
|
||||
from colorama import Fore, Style
|
||||
|
||||
from test_driver.debug import Debug, DebugAbstract, DebugNop
|
||||
from test_driver.driver import Driver, DriverConfiguration, load_driver_configuration
|
||||
from test_driver.driver import Driver, load_driver_configuration
|
||||
from test_driver.logger import (
|
||||
CompositeLogger,
|
||||
JunitXMLLogger,
|
||||
@@ -55,6 +56,29 @@ def writeable_dir(arg: str) -> Path:
|
||||
return path
|
||||
|
||||
|
||||
def formatwarning(
|
||||
message: Warning | str,
|
||||
category: type[Warning],
|
||||
filename: str,
|
||||
lineno: int,
|
||||
line: str | None = None,
|
||||
) -> str:
|
||||
return (
|
||||
Style.BRIGHT
|
||||
+ Fore.YELLOW
|
||||
+ f"??? Warning ({category.__name__}): " # ty: ignore[unsupported-operator]
|
||||
+ Style.NORMAL
|
||||
+ str(message)
|
||||
+ "\n"
|
||||
+ f' File "{filename}", line {lineno}\n'
|
||||
+ (f" {line}\n" if line is not None else "")
|
||||
+ Style.RESET_ALL
|
||||
)
|
||||
|
||||
|
||||
warnings.formatwarning = formatwarning # ty:ignore[invalid-assignment]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
arg_parser = argparse.ArgumentParser(prog="nixos-test-driver")
|
||||
arg_parser.add_argument(
|
||||
@@ -159,30 +183,3 @@ def main() -> None:
|
||||
driver.run_tests()
|
||||
toc = time.time()
|
||||
logger.info(f"test script finished in {(toc - tic):.2f}s")
|
||||
|
||||
|
||||
def generate_driver_symbols() -> None:
|
||||
"""
|
||||
This generates a file with symbols of the test-driver code that can be used
|
||||
in user's test scripts. That list is then used by pyflakes to lint those
|
||||
scripts.
|
||||
"""
|
||||
d = Driver(
|
||||
config=DriverConfiguration(
|
||||
vms=dict(),
|
||||
containers=dict(),
|
||||
vlans=[],
|
||||
global_timeout=0,
|
||||
enable_ssh_backdoor=False,
|
||||
test_script=(
|
||||
Path("testScriptWithTypes")
|
||||
if (Path("testScriptWithTypes").is_file())
|
||||
else Path("testScriptFile")
|
||||
),
|
||||
),
|
||||
out_dir=Path(),
|
||||
logger=CompositeLogger([]),
|
||||
)
|
||||
test_symbols = d.test_symbols()
|
||||
with open("driver-symbols", "w") as fp:
|
||||
fp.write(",".join(test_symbols.keys()))
|
||||
|
||||
@@ -7,7 +7,7 @@ import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import traceback
|
||||
from collections.abc import Callable, Iterator
|
||||
from collections.abc import Callable, Generator, Iterator
|
||||
from contextlib import AbstractContextManager, contextmanager
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
@@ -22,6 +22,7 @@ from test_driver.errors import MachineError, RequestedAssertionFailed
|
||||
from test_driver.logger import AbstractLogger
|
||||
from test_driver.machine import (
|
||||
BaseMachine,
|
||||
MachineDeprecationWrapper,
|
||||
NspawnMachine,
|
||||
QemuMachine,
|
||||
retry,
|
||||
@@ -299,7 +300,7 @@ class Driver:
|
||||
f"Error during cleanup of vhost-device-vsock process: {e}"
|
||||
)
|
||||
|
||||
def subtest(self, name: str) -> Iterator[None]:
|
||||
def subtest(self, name: str) -> Generator[None]:
|
||||
"""Group logs under a given test name"""
|
||||
with self.logger.subtest(name):
|
||||
try:
|
||||
@@ -338,11 +339,17 @@ class Driver:
|
||||
debug=self.debug,
|
||||
dump_machine_ssh=self.dump_machine_ssh,
|
||||
)
|
||||
machine_symbols = {pythonize_name(m.name): m for m in self.machines}
|
||||
machine_symbols: dict[
|
||||
str, QemuMachine | NspawnMachine | MachineDeprecationWrapper
|
||||
] = {pythonize_name(m.name): m for m in self.machines}
|
||||
# If there's exactly one machine, make it available under the name
|
||||
# "machine", even if it's not called that.
|
||||
if len(self.machines) == 1:
|
||||
(machine_symbols["machine"],) = self.machines
|
||||
if len(self.machines) == 1 and "machine" not in machine_symbols:
|
||||
only_machine_name = next(iter(machine_symbols))
|
||||
machine_symbols["machine"] = MachineDeprecationWrapper(
|
||||
f"It's deprecated to use the `machine` variable when the only machine is called {only_machine_name}. This behavior will no longer work in NixOS 27.05.",
|
||||
self.machines[0],
|
||||
)
|
||||
vlan_symbols = {
|
||||
f"vlan{v.nr}": self.vlans[idx] for idx, v in enumerate(self.vlans)
|
||||
}
|
||||
|
||||
@@ -1710,3 +1710,18 @@ class NspawnMachine(BaseMachine):
|
||||
with self.nested("waiting for the container to power off"):
|
||||
self.process.wait()
|
||||
self.process = None
|
||||
|
||||
|
||||
class MachineDeprecationWrapper:
|
||||
def __init__(self, msg: str, machine: QemuMachine | NspawnMachine):
|
||||
self.msg = msg
|
||||
self.machine = machine
|
||||
|
||||
def __getattribute__(self, name: str):
|
||||
if name in ("msg", "machine"):
|
||||
return object.__getattribute__(self, name)
|
||||
typename = self.machine.__class__.__name__
|
||||
warnings.warn(
|
||||
f"invoking '{typename}.{name}' is deprecated: {self.msg}",
|
||||
)
|
||||
return self.machine.__getattribute__(name)
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
# This file contains type hints that can be prepended to Nix test scripts so they can be type
|
||||
# checked.
|
||||
|
||||
from test_driver.debug import DebugAbstract
|
||||
from test_driver.driver import Driver
|
||||
from test_driver.vlan import VLan
|
||||
from test_driver.machine import BaseMachine, NspawnMachine, QemuMachine
|
||||
from test_driver.logger import AbstractLogger
|
||||
from typing import Callable, Iterator, ContextManager, Optional, List, Dict, Any, Union
|
||||
from typing_extensions import Protocol
|
||||
from pathlib import Path
|
||||
from contextlib import contextmanager
|
||||
from typing import Any, Callable, ContextManager, Generator, List, Optional, Union
|
||||
from unittest import TestCase
|
||||
|
||||
from test_driver.debug import DebugAbstract, DebugNop
|
||||
from test_driver.driver import Driver
|
||||
from test_driver.logger import AbstractLogger, CompositeLogger
|
||||
from typing_extensions import Protocol
|
||||
|
||||
class RetryProtocol(Protocol):
|
||||
def __call__(self, fn: Callable, timeout_seconds: int = 900) -> None:
|
||||
from test_driver.machine import BaseMachine, NspawnMachine, QemuMachine
|
||||
from test_driver.vlan import VLan
|
||||
|
||||
|
||||
# Protocols
|
||||
|
||||
|
||||
class CreateMachineProtocol(Protocol):
|
||||
def __call__(
|
||||
self,
|
||||
start_command: str | dict,
|
||||
*,
|
||||
name: Optional[str] = None,
|
||||
keep_machine_state: bool = False,
|
||||
**kwargs: Any, # to allow usage of deprecated keep_vm_state
|
||||
) -> QemuMachine:
|
||||
raise Exception("This is just type information for the Nix test driver")
|
||||
|
||||
|
||||
@@ -28,34 +40,93 @@ class PollingConditionProtocol(Protocol):
|
||||
raise Exception("This is just type information for the Nix test driver")
|
||||
|
||||
|
||||
class CreateMachineProtocol(Protocol):
|
||||
def __call__(
|
||||
self,
|
||||
start_command: str | dict,
|
||||
*,
|
||||
name: Optional[str] = None,
|
||||
keep_machine_state: bool = False,
|
||||
**kwargs: Any, # to allow usage of deprecated keep_vm_state
|
||||
) -> QemuMachine:
|
||||
raise Exception("This is just type information for the Nix test driver")
|
||||
# Classes
|
||||
|
||||
|
||||
start_all: Callable[[], None]
|
||||
subtest: Callable[[str], ContextManager[None]]
|
||||
retry: RetryProtocol
|
||||
test_script: Callable[[], None]
|
||||
machines: List[BaseMachine]
|
||||
machines_qemu: List[QemuMachine]
|
||||
machines_nspawn: List[NspawnMachine]
|
||||
vlans: List[VLan]
|
||||
driver: Driver
|
||||
log: AbstractLogger
|
||||
create_machine: CreateMachineProtocol
|
||||
run_tests: Callable[[], None]
|
||||
join_all: Callable[[], None]
|
||||
serial_stdout_off: Callable[[], None]
|
||||
serial_stdout_on: Callable[[], None]
|
||||
polling_condition: PollingConditionProtocol
|
||||
debug: DebugAbstract
|
||||
t: TestCase
|
||||
dump_machine_ssh: Callable[[], None]
|
||||
class AssertionTester(TestCase):
|
||||
pass
|
||||
|
||||
|
||||
# Global Variables
|
||||
|
||||
debug: DebugAbstract = DebugNop()
|
||||
machines: List[BaseMachine] = []
|
||||
machines_nspawn: List[NspawnMachine] = []
|
||||
machines_qemu: List[QemuMachine] = []
|
||||
t = AssertionTester()
|
||||
vlans: List[VLan] = []
|
||||
|
||||
|
||||
def create_fake_driver() -> Driver:
|
||||
raise Exception("fake driver")
|
||||
|
||||
|
||||
driver = create_fake_driver()
|
||||
|
||||
|
||||
# Functions
|
||||
|
||||
|
||||
# these are going to be called by the testScriptWithTypes in driver.nix
|
||||
def create_fake_qemu_machine() -> QemuMachine:
|
||||
raise Exception("fake qemu machine")
|
||||
|
||||
|
||||
def create_fake_nspawn_machine() -> NspawnMachine:
|
||||
raise Exception("fake nspawn machine")
|
||||
|
||||
|
||||
def create_fake_vlan() -> VLan:
|
||||
raise Exception("fake vlan")
|
||||
|
||||
|
||||
def create_machine(
|
||||
start_command: str, name: str | None = None, keep_machine_state: bool = False
|
||||
) -> QemuMachine:
|
||||
raise Exception("fake machine")
|
||||
|
||||
|
||||
def dump_machine_ssh() -> None:
|
||||
return None
|
||||
|
||||
|
||||
def join_all() -> None:
|
||||
return None
|
||||
|
||||
|
||||
log: AbstractLogger = CompositeLogger([])
|
||||
|
||||
|
||||
def polling_condition(
|
||||
fun: Callable | None, seconds_interval: float = 0.0, description: str | None = None
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
def retry(fn: Callable, timeout_seconds: int = 900) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def run_tests() -> None:
|
||||
return
|
||||
|
||||
|
||||
def serial_stdout_off() -> None:
|
||||
return None
|
||||
|
||||
|
||||
def serial_stdout_on() -> None:
|
||||
return None
|
||||
|
||||
|
||||
def start_all() -> None:
|
||||
return
|
||||
|
||||
|
||||
def test_script() -> None:
|
||||
return
|
||||
|
||||
|
||||
@contextmanager
|
||||
def subtest(str: str) -> Generator[None, None, None]:
|
||||
yield
|
||||
|
||||
@@ -19,34 +19,38 @@ let
|
||||
enableNspawn = config.containers != { };
|
||||
};
|
||||
|
||||
pythonizeName =
|
||||
name:
|
||||
typeHints =
|
||||
let
|
||||
head = lib.substring 0 1 name;
|
||||
tail = lib.substring 1 (-1) name;
|
||||
pythonizeName =
|
||||
name:
|
||||
let
|
||||
head = lib.substring 0 1 name;
|
||||
tail = lib.substring 1 (-1) name;
|
||||
in
|
||||
(if builtins.match "[A-z_]" head == null then "_" else head)
|
||||
+ lib.stringAsChars (c: if builtins.match "[A-z0-9_]" c == null then "_" else c) tail;
|
||||
|
||||
vmMachineNames = lib.attrNames config.driverConfiguration.vms;
|
||||
containerMachineNames = lib.attrNames config.driverConfiguration.containers;
|
||||
|
||||
theOnlyMachine =
|
||||
let
|
||||
exactlyOneMachine = lib.length (lib.attrValues config.nodes) == 1;
|
||||
allMachineNames = lib.attrNames config.allMachines;
|
||||
in
|
||||
lib.optional (exactlyOneMachine && !lib.elem "machine" allMachineNames) "machine";
|
||||
|
||||
vmMachineTypeHints = map (name: "${pythonizeName name} = create_fake_qemu_machine()") (
|
||||
vmMachineNames ++ theOnlyMachine
|
||||
);
|
||||
containerMachineTypeHints = map (
|
||||
name: "${pythonizeName name} = create_fake_nspawn_machine()"
|
||||
) containerMachineNames;
|
||||
vlanTypeHints = map (i: "vlan${toString i} = create_fake_vlan()") config.driverConfiguration.vlans;
|
||||
in
|
||||
(if builtins.match "[A-z_]" head == null then "_" else head)
|
||||
+ lib.stringAsChars (c: if builtins.match "[A-z0-9_]" c == null then "_" else c) tail;
|
||||
|
||||
vlanTypeHints = lib.strings.concatMapStringsSep "\n" (
|
||||
i: "vlan${toString i}: VLan"
|
||||
) config.driverConfiguration.vlans;
|
||||
|
||||
vmMachineNames = lib.attrNames config.driverConfiguration.vms;
|
||||
containerMachineNames = lib.attrNames config.driverConfiguration.containers;
|
||||
|
||||
theOnlyMachine =
|
||||
let
|
||||
exactlyOneMachine = lib.length (lib.attrValues config.nodes) == 1;
|
||||
allMachineNames = map (c: c.system.name) (lib.attrValues config.allMachines);
|
||||
in
|
||||
lib.optional (exactlyOneMachine && !lib.elem "machine" allMachineNames) "machine";
|
||||
|
||||
pythonizedVmNames = map pythonizeName (vmMachineNames ++ theOnlyMachine);
|
||||
vmMachineTypeHints = map (name: "${name}: QemuMachine;") pythonizedVmNames;
|
||||
|
||||
pythonizedContainerNames = map pythonizeName containerMachineNames;
|
||||
containerMachineTypeHints = map (name: "${name}: NspawnMachine;") pythonizedContainerNames;
|
||||
lib.strings.concatStringsSep "\n" (
|
||||
vlanTypeHints ++ vmMachineTypeHints ++ containerMachineTypeHints
|
||||
);
|
||||
|
||||
withChecks = lib.warnIf config.skipLint "Linting is disabled";
|
||||
|
||||
@@ -57,7 +61,8 @@ let
|
||||
nativeBuildInputs = [
|
||||
hostPkgs.makeWrapper
|
||||
]
|
||||
++ lib.optionals (!config.skipTypeCheck) [ hostPkgs.mypy ];
|
||||
++ lib.optionals (!config.skipTypeCheck) [ hostPkgs.ty ]
|
||||
++ lib.optionals (!config.skipLint) [ hostPkgs.ruff ];
|
||||
buildInputs = [ testDriver ];
|
||||
testScript = config.testScriptString;
|
||||
preferLocalBuild = true;
|
||||
@@ -69,43 +74,34 @@ let
|
||||
''
|
||||
mkdir -p $out/bin
|
||||
|
||||
${lib.optionalString (!config.skipTypeCheck) ''
|
||||
# prepend type hints so the test script can be type checked with mypy
|
||||
|
||||
${lib.optionalString (!config.skipTypeCheck || !config.skipLint) ''
|
||||
# prepend type hints so the test script can be type checked with ty
|
||||
cat "${../test-script-prepend.py}" >> testScriptWithTypes
|
||||
echo "${toString vmMachineTypeHints}" >> testScriptWithTypes
|
||||
echo "${toString containerMachineTypeHints}" >> testScriptWithTypes
|
||||
echo "${toString vlanTypeHints}" >> testScriptWithTypes
|
||||
echo "${toString typeHints}" >> testScriptWithTypes
|
||||
echo -n "$testScript" >> testScriptWithTypes
|
||||
''}
|
||||
|
||||
${lib.optionalString (!config.skipTypeCheck) ''
|
||||
echo "Running type check (enable/disable: config.skipTypeCheck)"
|
||||
echo "See https://nixos.org/manual/nixos/stable/#test-opt-skipTypeCheck"
|
||||
|
||||
mypy --no-implicit-optional \
|
||||
--pretty \
|
||||
--no-color-output \
|
||||
testScriptWithTypes
|
||||
ty check testScriptWithTypes
|
||||
''}
|
||||
|
||||
echo -n "$testScript" > testScriptFile
|
||||
|
||||
cp "${config.driverConfiguration.test_script}" $out/test-script
|
||||
|
||||
ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-test-driver
|
||||
|
||||
${testDriver}/bin/generate-driver-symbols
|
||||
${lib.optionalString (!config.skipLint) ''
|
||||
echo "Linting test script (enable/disable: config.skipLint)"
|
||||
echo "See https://nixos.org/manual/nixos/stable/#test-opt-skipLint"
|
||||
|
||||
PYFLAKES_BUILTINS="$(
|
||||
echo -n ${
|
||||
lib.escapeShellArg (lib.concatStringsSep "," (pythonizedVmNames ++ pythonizedContainerNames))
|
||||
},
|
||||
cat ${lib.escapeShellArg "driver-symbols"}
|
||||
)" ${hostPkgs.python3Packages.pyflakes}/bin/pyflakes $out/test-script
|
||||
# F are the "(py)flakes" checks.
|
||||
# we can't go with the defaults because these include
|
||||
# code style/formatting
|
||||
ruff check --select F testScriptWithTypes
|
||||
''}
|
||||
|
||||
cp "${config.driverConfiguration.test_script}" $out/test-script
|
||||
|
||||
ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-test-driver
|
||||
|
||||
wrapProgram $out/bin/nixos-test-driver \
|
||||
--add-flags "--config ${config.driverConfigurationFile}" \
|
||||
--add-flags "--log-level ${config.logLevel}" \
|
||||
|
||||
@@ -72,20 +72,25 @@ in
|
||||
{
|
||||
inherit (config.boot.kernelPackages.kernel) configfile;
|
||||
}
|
||||
''
|
||||
mmap_rnd_bits_max=$(grep "^CONFIG_ARCH_MMAP_RND_BITS_MAX=" $configfile | grep --only-matching "[0-9]*$")
|
||||
if [[ -z "$mmap_rnd_bits_max" ]]; then
|
||||
echo "Unable to determine mmap_rnd_bits_max. Check your kernel configfile is valid."
|
||||
exit 1
|
||||
fi
|
||||
mmap_rnd_compat_bits_max=$(grep "^CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=" $configfile | grep --only-matching "[0-9]*$")
|
||||
if [[ -z "$mmap_rnd_compat_bits_max" ]]; then
|
||||
echo "Unable to determine mmap_rnd_compat_bits_max. Check your kernel configfile is valid."
|
||||
exit 1
|
||||
fi
|
||||
echo "vm.mmap_rnd_bits=$mmap_rnd_bits_max" >> $out
|
||||
echo "vm.mmap_rnd_compat_bits=$mmap_rnd_compat_bits_max" >> $out
|
||||
'';
|
||||
(
|
||||
''
|
||||
mmap_rnd_bits_max=$(grep "^CONFIG_ARCH_MMAP_RND_BITS_MAX=" $configfile | grep --only-matching "[0-9]*$")
|
||||
if [[ -z "$mmap_rnd_bits_max" ]]; then
|
||||
echo "Unable to determine mmap_rnd_bits_max. Check your kernel configfile is valid."
|
||||
exit 1
|
||||
fi
|
||||
echo "vm.mmap_rnd_bits=$mmap_rnd_bits_max" >> $out
|
||||
''
|
||||
# HAVE_ARCH_MMAP_RND_COMPAT_BITS is not defined for LoongArch64
|
||||
+ lib.optionalString (!pkgs.stdenv.hostPlatform.isLoongArch64) ''
|
||||
mmap_rnd_compat_bits_max=$(grep "^CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=" $configfile | grep --only-matching "[0-9]*$")
|
||||
if [[ -z "$mmap_rnd_compat_bits_max" ]]; then
|
||||
echo "Unable to determine mmap_rnd_compat_bits_max. Check your kernel configfile is valid."
|
||||
exit 1
|
||||
fi
|
||||
echo "vm.mmap_rnd_compat_bits=$mmap_rnd_compat_bits_max" >> $out
|
||||
''
|
||||
);
|
||||
"sysctl.d/60-nixos.conf".text = lib.concatStrings (
|
||||
lib.mapAttrsToList (
|
||||
n: v: lib.optionalString (v != null) "${n}=${if v == false then "0" else toString v}\n"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
x86_64-linux = "/nix/store/q7f0d4m54yj98fcjmbkscw83j82fypnd-nix-2.34.6";
|
||||
i686-linux = "/nix/store/mlv349bmjjx34p50idp54rg0wsm44hws-nix-2.34.6";
|
||||
aarch64-linux = "/nix/store/wlcv2ymswfgwv1cj1q29p26rh26xj3nd-nix-2.34.6";
|
||||
riscv64-linux = "/nix/store/000b0vjlhw359rl82p8pld00g6363c78-nix-riscv64-unknown-linux-gnu-2.34.6";
|
||||
x86_64-darwin = "/nix/store/mqvv503c5l9kgjvc7vyxj3rdx5a71c11-nix-2.34.6";
|
||||
aarch64-darwin = "/nix/store/hcgga2smfm8lqirshrbfpk5j1my1wh4j-nix-2.34.6";
|
||||
x86_64-linux = "/nix/store/6qpfa1c19q4idpjij6s6yywkfvhp820s-nix-2.34.7";
|
||||
i686-linux = "/nix/store/npdbf892fhicd1pw8flpywzbvhcdx469-nix-2.34.7";
|
||||
aarch64-linux = "/nix/store/5i60qiqjx9bjkcy31fwvnx28ijljlbs3-nix-2.34.7";
|
||||
riscv64-linux = "/nix/store/xvl2f539v978jwflp2d9r7znk35br00i-nix-riscv64-unknown-linux-gnu-2.34.7";
|
||||
x86_64-darwin = "/nix/store/j9rh0z3zy9rq00lz9ckcsa1g1hn35cyw-nix-2.34.7";
|
||||
aarch64-darwin = "/nix/store/yxgyagiaffxkbrff4d7mrg718wdj3llj-nix-2.34.7";
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"virtio_scsi"
|
||||
"9p"
|
||||
"9pnet_virtio"
|
||||
"virtiofs"
|
||||
];
|
||||
boot.initrd.kernelModules = [
|
||||
"virtio_balloon"
|
||||
|
||||
@@ -6,17 +6,23 @@
|
||||
...
|
||||
}:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.systemd.coredump;
|
||||
systemd = config.systemd.package;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(lib.mkRemovedOptionModule [
|
||||
"systemd"
|
||||
"coredump"
|
||||
"extraConfig"
|
||||
] "Use systemd.coredump.settings.Coredump instead.")
|
||||
];
|
||||
|
||||
options = {
|
||||
systemd.coredump.enable = mkOption {
|
||||
systemd.coredump.enable = lib.mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
type = lib.types.bool;
|
||||
description = ''
|
||||
Whether core dumps should be processed by
|
||||
{command}`systemd-coredump`. If disabled, core dumps
|
||||
@@ -24,30 +30,31 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.coredump.extraConfig = mkOption {
|
||||
default = "";
|
||||
type = types.lines;
|
||||
example = "Storage=journal";
|
||||
systemd.coredump.settings.Coredump = lib.mkOption {
|
||||
default = { };
|
||||
type = lib.types.submodule {
|
||||
freeformType = lib.types.attrsOf utils.systemdUtils.unitOptions.unitOption;
|
||||
};
|
||||
example = {
|
||||
Storage = "journal";
|
||||
};
|
||||
description = ''
|
||||
Extra config options for systemd-coredump. See {manpage}`coredump.conf(5)` man page
|
||||
for available options.
|
||||
Settings for systemd-coredump. See {manpage}`coredump.conf(5)` for
|
||||
available options.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
config = lib.mkMerge [
|
||||
|
||||
(mkIf cfg.enable {
|
||||
(lib.mkIf cfg.enable {
|
||||
systemd.additionalUpstreamSystemUnits = [
|
||||
"systemd-coredump.socket"
|
||||
"systemd-coredump@.service"
|
||||
];
|
||||
|
||||
environment.etc = {
|
||||
"systemd/coredump.conf".text = ''
|
||||
[Coredump]
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
"systemd/coredump.conf".text = utils.systemdUtils.lib.settingsToSections cfg.settings;
|
||||
|
||||
# install provided sysctl snippets
|
||||
"sysctl.d/50-coredump.conf".source =
|
||||
@@ -76,8 +83,8 @@ in
|
||||
users.groups.systemd-coredump = { };
|
||||
})
|
||||
|
||||
(mkIf (!cfg.enable) {
|
||||
boot.kernel.sysctl."kernel.core_pattern" = mkDefault "core";
|
||||
(lib.mkIf (!cfg.enable) {
|
||||
boot.kernel.sysctl."kernel.core_pattern" = lib.mkDefault "core";
|
||||
})
|
||||
|
||||
];
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
meta = with lib.maintainers; {
|
||||
maintainers = [ urbas ];
|
||||
};
|
||||
nodes.machine = {
|
||||
nodes.unnamed = {
|
||||
imports = [
|
||||
../modules/profiles/headless.nix
|
||||
../modules/virtualisation/amazon-init.nix
|
||||
|
||||
@@ -32,7 +32,7 @@ in
|
||||
in
|
||||
''
|
||||
start_all()
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
benchexec.wait_for_unit("multi-user.target")
|
||||
benchexec.succeed(''''\
|
||||
systemd-run \
|
||||
--property='StandardOutput=file:${stdout}' \
|
||||
|
||||
@@ -27,7 +27,7 @@ in
|
||||
illustris
|
||||
];
|
||||
|
||||
nodes.machine2 =
|
||||
nodes.unnamed =
|
||||
{ ... }:
|
||||
{
|
||||
virtualisation.qemu.options = [
|
||||
|
||||
@@ -60,7 +60,7 @@ in
|
||||
lewo
|
||||
illustris
|
||||
];
|
||||
nodes.machine = {
|
||||
nodes.unnamed = {
|
||||
virtualisation.qemu.options = [
|
||||
"-cdrom"
|
||||
"${metadataDrive}/metadata.iso"
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
machine.succeed(f"pkill {gui_app}", timeout=5)
|
||||
|
||||
machine.succeed("echo 'test completed succeessfully' > /${testName}", timeout=5)
|
||||
machine.copy_from_vm('/${testName}')
|
||||
machine.copy_from_machine('/${testName}')
|
||||
|
||||
machine.shutdown()
|
||||
'';
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
# wait until the pdf files are completely produced and readable by alice
|
||||
machine.wait_until_succeeds(f"su - alice -c 'pdfinfo /var/spool/cups-pdf-{name}/users/alice/*.pdf'")
|
||||
machine.succeed(f"cp /var/spool/cups-pdf-{name}/users/alice/*.pdf /tmp/{name}.pdf")
|
||||
machine.copy_from_vm(f"/tmp/{name}.pdf", "")
|
||||
machine.copy_from_machine(f"/tmp/{name}.pdf", "")
|
||||
run(f"${lib.getExe hostPkgs.imagemagickBig} -density 300 $out/{name}.pdf $out/{name}.jpeg", shell=True, check=True)
|
||||
assert text.encode() in run(f"${lib.getExe hostPkgs.tesseract} $out/{name}.jpeg stdout", shell=True, check=True, capture_output=True).stdout
|
||||
'';
|
||||
|
||||
@@ -49,6 +49,8 @@ let
|
||||
enableOCR = true;
|
||||
|
||||
testScript = ''
|
||||
machine = ${name}
|
||||
|
||||
@polling_condition
|
||||
def drawterm_running():
|
||||
machine.succeed("pgrep drawterm")
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
"${exe} file://${pkgs.sound-theme-freedesktop}/share/sounds/freedesktop/stereo/phone-incoming-call.oga >&2 &"
|
||||
)
|
||||
wait_for_sound(machine)
|
||||
machine.copy_from_vm("/tmp/record.wav")
|
||||
machine.copy_from_machine("/tmp/record.wav")
|
||||
|
||||
with subtest("Close sound test tab"):
|
||||
machine.execute("xdotool key ctrl+w")
|
||||
|
||||
@@ -270,7 +270,7 @@ let
|
||||
server.succeed("${serverSystem}/specialisation/dump/bin/switch-to-configuration test")
|
||||
server.systemctl("start forgejo-dump")
|
||||
assert "Zstandard compressed data" in server.succeed("file ${dumpFile}")
|
||||
server.copy_from_vm("${dumpFile}")
|
||||
server.copy_from_machine("${dumpFile}")
|
||||
'';
|
||||
};
|
||||
in
|
||||
|
||||
@@ -41,6 +41,7 @@ let
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
machine = ${name}
|
||||
machine.wait_for_unit('graphical.target')
|
||||
machine.wait_for_text('Your Subscription list is currently empty')
|
||||
machine.send_key("ctrl-r")
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
import os
|
||||
|
||||
# prepare certificates
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
import os
|
||||
|
||||
# prepare certificates
|
||||
|
||||
|
||||
@@ -69,6 +69,8 @@
|
||||
};
|
||||
};
|
||||
testScript = ''
|
||||
import os
|
||||
|
||||
# Helpers
|
||||
def cmd(command):
|
||||
print(f"+{command}")
|
||||
|
||||
@@ -43,8 +43,6 @@ let
|
||||
''
|
||||
start_all()
|
||||
|
||||
machine = ${hostName}
|
||||
|
||||
machine.systemctl("start network-online.target")
|
||||
machine.wait_for_unit("network-online.target")
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
lib.pipe nodes [
|
||||
builtins.attrNames
|
||||
(map (node: ''
|
||||
${node}.copy_from_vm(
|
||||
${node}.copy_from_machine(
|
||||
${node}.succeed("readlink -f /etc/locale.conf").strip(),
|
||||
"${node}"
|
||||
)
|
||||
|
||||
@@ -81,7 +81,11 @@
|
||||
|
||||
machine.wait_until_succeeds(f"[ `{cmd} | wc -l` -eq 1 ]")
|
||||
output = machine.succeed(cmd)
|
||||
ip = re.search(r"inet6 ([0-9a-f:]{2,})/", output).group(1)
|
||||
matches: re.Match | None = re.search(r"inet6 ([0-9a-f:]{2,})/", output)
|
||||
if matches is None:
|
||||
raise Exception(f"Can't match IP out of output: {output}")
|
||||
|
||||
ip = matches.group(1)
|
||||
|
||||
if temporary:
|
||||
scope = scope + " temporary"
|
||||
|
||||
@@ -80,6 +80,6 @@ in
|
||||
'LOCALE': 'en_US',
|
||||
})
|
||||
machine.succeed(f"curl 'localhost:${toString port}/process?{query}' -o ./audio.wav")
|
||||
machine.copy_from_vm("./audio.wav")
|
||||
machine.copy_from_machine("./audio.wav")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ in
|
||||
appservice.wait_for_open_port(11111)
|
||||
|
||||
with subtest("copy the registration file"):
|
||||
appservice.copy_from_vm("/var/lib/matrix-appservice-irc/registration.yml")
|
||||
appservice.copy_from_machine("/var/lib/matrix-appservice-irc/registration.yml")
|
||||
homeserver.copy_from_host(
|
||||
str(pathlib.Path(os.environ.get("out", os.getcwd())) / "registration.yml"), "/"
|
||||
)
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
machine.wait_for_text("alice@machine")
|
||||
machine.send_chars("test-wayland\n")
|
||||
machine.wait_for_file("/tmp/test-wayland-exit-ok")
|
||||
machine.copy_from_vm("/tmp/test-wayland.out")
|
||||
machine.copy_from_machine("/tmp/test-wayland.out")
|
||||
machine.screenshot("foot_wayland_info")
|
||||
|
||||
# please actually register that we want to close the window
|
||||
@@ -135,7 +135,7 @@
|
||||
machine.wait_for_text("alice@machine")
|
||||
machine.send_chars("test-x11\n")
|
||||
machine.wait_for_file("/tmp/test-x11-exit-ok")
|
||||
machine.copy_from_vm("/tmp/test-x11.out")
|
||||
machine.copy_from_machine("/tmp/test-x11.out")
|
||||
machine.screenshot("alacritty_glinfo")
|
||||
|
||||
# please actually register that we want to close the window
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
machine.wait_for_text(r"(alice|machine)")
|
||||
machine.send_chars("test-wayland\n")
|
||||
machine.wait_for_file("/tmp/test-wayland-exit-ok")
|
||||
machine.copy_from_vm("/tmp/test-wayland.out")
|
||||
machine.copy_from_machine("/tmp/test-wayland.out")
|
||||
machine.screenshot("foot_wayland_info")
|
||||
|
||||
# please actually register that we want to close the window
|
||||
@@ -128,7 +128,7 @@
|
||||
machine.wait_for_text(r"(alice|machine)")
|
||||
machine.send_chars("test-x11\n")
|
||||
machine.wait_for_file("/tmp/test-x11-exit-ok")
|
||||
machine.copy_from_vm("/tmp/test-x11.out")
|
||||
machine.copy_from_machine("/tmp/test-x11.out")
|
||||
machine.screenshot("alacritty_glinfo")
|
||||
|
||||
# please actually register that we want to close the window
|
||||
|
||||
+2
-2
@@ -140,7 +140,7 @@ in
|
||||
# to perform the following test:
|
||||
client.fail(f"{mpc} -h serverPulseAudio status")
|
||||
# For inspecting these files
|
||||
serverALSA.copy_from_vm("/run/mpd/mpd.conf", "ALSA")
|
||||
serverPulseAudio.copy_from_vm("/run/mpd/mpd.conf", "PulseAudio")
|
||||
serverALSA.copy_from_machine("/run/mpd/mpd.conf", "ALSA")
|
||||
serverPulseAudio.copy_from_machine("/run/mpd/mpd.conf", "PulseAudio")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -95,6 +95,6 @@ in
|
||||
|
||||
## Check that it contains the title of the score
|
||||
machine.succeed('pdfgrep "Untitled score" "/root/Untitled score.pdf"')
|
||||
machine.copy_from_vm("/root/Untitled score.pdf")
|
||||
machine.copy_from_machine("/root/Untitled score.pdf")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
|
||||
testScript = ''
|
||||
start_all();
|
||||
machine.wait_for_unit("mympd.service");
|
||||
mympd.wait_for_unit("mympd.service");
|
||||
|
||||
# Ensure that mympd can connect to mpd
|
||||
machine.wait_until_succeeds(
|
||||
mympd.wait_until_succeeds(
|
||||
"journalctl -eu mympd -o cat | grep 'Connected to MPD'"
|
||||
)
|
||||
|
||||
# Ensure that the web server is working
|
||||
machine.succeed("curl http://localhost:8081 --compressed | grep -o myMPD")
|
||||
mympd.succeed("curl http://localhost:8081 --compressed | grep -o myMPD")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ in
|
||||
webserver.succeed("mkdir -p /var/web")
|
||||
webserver.succeed("chown nginx:nginx /var/web")
|
||||
webserver.succeed("$(curl -vvv http://sandbox.test/test2-write)")
|
||||
assert "404 Not Found" in machine.succeed(
|
||||
assert "404 Not Found" in webserver.succeed(
|
||||
"curl -vvv -s http://sandbox.test/test2-read/bar.txt"
|
||||
)
|
||||
'';
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
machine.systemctl("start network-online.target")
|
||||
machine.wait_for_unit("network-online.target")
|
||||
serviceEmptyConf.systemctl("start network-online.target")
|
||||
serviceEmptyConf.wait_for_unit("network-online.target")
|
||||
|
||||
with subtest("empty/default config test"):
|
||||
serviceEmptyConf.wait_for_unit("paisa.service")
|
||||
|
||||
@@ -83,6 +83,7 @@ import ../make-test-python.nix (
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
import os
|
||||
import shlex
|
||||
|
||||
|
||||
|
||||
@@ -75,18 +75,18 @@ in
|
||||
)
|
||||
|
||||
with subtest("verify UI installed"):
|
||||
machine.succeed("curl -sSf http://127.0.0.1:7280/ui/")
|
||||
server.succeed("curl -sSf http://127.0.0.1:7280/ui/")
|
||||
|
||||
with subtest("injest and query data"):
|
||||
import json
|
||||
|
||||
# Test CLI ingestion
|
||||
print(machine.succeed('${pkgs.quickwit}/bin/quickwit index create --index-config ${pkgs.writeText "index.yaml" index_yaml}'))
|
||||
print(server.succeed('${pkgs.quickwit}/bin/quickwit index create --index-config ${pkgs.writeText "index.yaml" index_yaml}'))
|
||||
# Important to use `--wait`, otherwise the queries below race with index processing.
|
||||
print(machine.succeed('${pkgs.quickwit}/bin/quickwit index ingest --index example_server_logs --input-path ${pkgs.writeText "exampleDocs.json" exampleDocs} --wait'))
|
||||
print(server.succeed('${pkgs.quickwit}/bin/quickwit index ingest --index example_server_logs --input-path ${pkgs.writeText "exampleDocs.json" exampleDocs} --wait'))
|
||||
|
||||
# Test CLI query
|
||||
cli_query_output = machine.succeed('${pkgs.quickwit}/bin/quickwit index search --index example_server_logs --query "exception"')
|
||||
cli_query_output = server.succeed('${pkgs.quickwit}/bin/quickwit index search --index example_server_logs --query "exception"')
|
||||
print(cli_query_output)
|
||||
|
||||
# Assert query result is as expected.
|
||||
@@ -94,7 +94,7 @@ in
|
||||
assert num_hits == 3, f"cli_query_output contains unexpected number of results: {num_hits}"
|
||||
|
||||
# Test API query
|
||||
api_query_output = machine.succeed('curl --fail http://127.0.0.1:7280/api/v1/example_server_logs/search?query=exception')
|
||||
api_query_output = server.succeed('curl --fail http://127.0.0.1:7280/api/v1/example_server_logs/search?query=exception')
|
||||
print(api_query_output)
|
||||
|
||||
quickwit.log(quickwit.succeed(
|
||||
|
||||
@@ -78,11 +78,11 @@ in
|
||||
with subtest("debugging: /dev/video0 works"):
|
||||
machine.succeed("v4l2-ctl --all >&2")
|
||||
machine.succeed("fswebcam --no-banner /tmp/webcam.jpg")
|
||||
machine.copy_from_vm("/tmp/webcam.jpg", "webcam")
|
||||
machine.copy_from_machine("/tmp/webcam.jpg", "webcam")
|
||||
|
||||
# scan with the webcam
|
||||
machine.succeed("scanimage -o /tmp/scan.png >&2")
|
||||
machine.copy_from_vm("/tmp/scan.png", "scan")
|
||||
machine.copy_from_machine("/tmp/scan.png", "scan")
|
||||
|
||||
# the image should contain "${text}"
|
||||
output = machine.succeed("tesseract /tmp/scan.png -")
|
||||
|
||||
@@ -140,28 +140,27 @@ in
|
||||
in
|
||||
# python
|
||||
''
|
||||
# List of AS instances
|
||||
machines = [scion01, scion02, scion03, scion04, scion05]
|
||||
vms = [scion01, scion02, scion03, scion04, scion05]
|
||||
|
||||
# Functions to avoid many for loops
|
||||
def start(allow_reboot=False):
|
||||
for i in machines:
|
||||
for i in vms:
|
||||
i.start(allow_reboot=allow_reboot)
|
||||
|
||||
def wait_for_unit(service_name):
|
||||
for i in machines:
|
||||
for i in vms:
|
||||
i.wait_for_unit(service_name)
|
||||
|
||||
def succeed(command):
|
||||
for i in machines:
|
||||
for i in vms:
|
||||
i.succeed(command)
|
||||
|
||||
def reboot():
|
||||
for i in machines:
|
||||
for i in vms:
|
||||
i.reboot()
|
||||
|
||||
def crash():
|
||||
for i in machines:
|
||||
for i in vms:
|
||||
i.crash()
|
||||
|
||||
# Start all machines, allowing reboot for later
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
with subtest("Environment variables have been substituted"):
|
||||
base.succeed("grep -q somesecret /run/searx/settings.yml")
|
||||
base.copy_from_vm("/run/searx/settings.yml")
|
||||
base.copy_from_machine("/run/searx/settings.yml")
|
||||
|
||||
with subtest("Basic setup is working"):
|
||||
base.wait_for_open_port(8080)
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
testScript = ''
|
||||
start_all();
|
||||
machine.wait_for_unit("snmpd.service")
|
||||
machine.succeed("snmpwalk -v 2c -c public localhost | grep SNMPv2-MIB::sysName.0");
|
||||
snmpd.wait_for_unit("snmpd.service")
|
||||
snmpd.succeed("snmpwalk -v 2c -c public localhost | grep SNMPv2-MIB::sysName.0");
|
||||
'';
|
||||
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
machine.send_chars("test-x11\n")
|
||||
machine.wait_for_file("/tmp/test-x11-exit-ok")
|
||||
print(machine.succeed("cat /tmp/test-x11.out"))
|
||||
machine.copy_from_vm("/tmp/test-x11.out")
|
||||
machine.copy_from_machine("/tmp/test-x11.out")
|
||||
machine.screenshot("alacritty_glinfo")
|
||||
machine.succeed("pkill alacritty")
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
machine.send_chars("test-wayland\n")
|
||||
machine.wait_for_file("/tmp/test-wayland-exit-ok")
|
||||
print(machine.succeed("cat /tmp/test-wayland.out"))
|
||||
machine.copy_from_vm("/tmp/test-wayland.out")
|
||||
machine.copy_from_machine("/tmp/test-wayland.out")
|
||||
machine.screenshot("foot_wayland_info")
|
||||
machine.send_key("alt-shift-q")
|
||||
machine.wait_until_fails("pgrep foot")
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
machine.send_chars("test-x11\n")
|
||||
machine.wait_for_file("/tmp/test-x11-exit-ok")
|
||||
print(machine.succeed("cat /tmp/test-x11.out"))
|
||||
machine.copy_from_vm("/tmp/test-x11.out")
|
||||
machine.copy_from_machine("/tmp/test-x11.out")
|
||||
machine.screenshot("alacritty_glinfo")
|
||||
machine.succeed("pkill alacritty")
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
machine.send_chars("test-wayland\n")
|
||||
machine.wait_for_file("/tmp/test-wayland-exit-ok")
|
||||
print(machine.succeed("cat /tmp/test-wayland.out"))
|
||||
machine.copy_from_vm("/tmp/test-wayland.out")
|
||||
machine.copy_from_machine("/tmp/test-wayland.out")
|
||||
machine.screenshot("foot_wayland_info")
|
||||
machine.send_key("alt-shift-q")
|
||||
machine.wait_until_fails("pgrep foot")
|
||||
|
||||
@@ -227,7 +227,7 @@ in
|
||||
})
|
||||
+ ''
|
||||
# Useful for debugging later
|
||||
machine.copy_from_vm("${configPath}", "before")
|
||||
machine.copy_from_machine("${configPath}", "before")
|
||||
|
||||
machine.systemctl("restart syncthing-init.service")
|
||||
machine.wait_for_unit("syncthing-init.service")
|
||||
@@ -237,13 +237,13 @@ in
|
||||
})
|
||||
+ ''
|
||||
# Useful for debugging later
|
||||
machine.copy_from_vm("${configPath}", "after")
|
||||
machine.copy_from_machine("${configPath}", "after")
|
||||
|
||||
# Copy the systemd unit's bash script, to inspect it for debugging.
|
||||
mergeScript = machine.succeed(
|
||||
"systemctl cat syncthing-init.service | "
|
||||
"${pkgs.initool}/bin/initool g - Service ExecStart --value-only"
|
||||
).strip() # strip from new lines
|
||||
machine.copy_from_vm(mergeScript, "")
|
||||
machine.copy_from_machine(mergeScript, "")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
# We copy the main graph into the $out (toplevel), and we also copy
|
||||
# the entire output directory with additional data
|
||||
with subtest("Copying the resulting data into $out"):
|
||||
machine.copy_from_vm("systemd-analyze/", "")
|
||||
machine.copy_from_vm("systemd-analyze/systemd-analyze.svg", "")
|
||||
machine.copy_from_machine("systemd-analyze/", "")
|
||||
machine.copy_from_machine("systemd-analyze/systemd-analyze.svg", "")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
with subtest("interactive shell with terminal in capsule"):
|
||||
hello_output = machine.succeed("systemd-run -t --capsule=alice /run/current-system/sw/bin/bash -i -c 'hello | tee ~/hello'")
|
||||
assert hello_output == "Hello, world!\r\n"
|
||||
machine.copy_from_vm("/var/lib/capsules/alice/hello")
|
||||
machine.copy_from_machine("/var/lib/capsules/alice/hello")
|
||||
|
||||
with subtest("capsule cleanup"):
|
||||
machine.succeed("systemctl --capsule=alice stop sleeptest.service")
|
||||
|
||||
@@ -21,10 +21,19 @@ in
|
||||
maintainers = [ ];
|
||||
};
|
||||
|
||||
nodes.machine1 = { pkgs, lib, ... }: commonConfig;
|
||||
nodes.machine1 =
|
||||
{ pkgs, lib, ... }:
|
||||
{
|
||||
imports = [ commonConfig ];
|
||||
systemd.coredump.settings.Coredump = {
|
||||
Storage = "journal";
|
||||
ProcessSizeMax = "0";
|
||||
};
|
||||
};
|
||||
nodes.machine2 =
|
||||
{ pkgs, lib, ... }:
|
||||
lib.recursiveUpdate commonConfig {
|
||||
{
|
||||
imports = [ commonConfig ];
|
||||
systemd.coredump.enable = false;
|
||||
systemd.package = pkgs.systemd.override {
|
||||
withCoredump = false;
|
||||
@@ -39,6 +48,11 @@ in
|
||||
machine1.wait_until_succeeds("coredumpctl list | grep crasher", timeout=10)
|
||||
machine1.fail("stat /var/lib/crasher/core*")
|
||||
|
||||
with subtest("settings.Coredump renders coredump.conf"):
|
||||
machine1.succeed("grep -F '[Coredump]' /etc/systemd/coredump.conf")
|
||||
machine1.succeed("grep -F 'Storage=journal' /etc/systemd/coredump.conf")
|
||||
machine1.succeed("grep -F 'ProcessSizeMax=0' /etc/systemd/coredump.conf")
|
||||
|
||||
with subtest("systemd-coredump disabled"):
|
||||
machine2.systemctl("start crasher");
|
||||
machine2.wait_until_succeeds("stat /var/lib/crasher/core*", timeout=10)
|
||||
|
||||
@@ -45,11 +45,11 @@
|
||||
client.wait_for_unit("multi-user.target")
|
||||
|
||||
def copy_pem(file: str):
|
||||
machine.copy_from_host(source=f"{tmpdir}/{file}", target=f"/run/secrets/{file}")
|
||||
machine.succeed(f"chmod 600 /run/secrets/{file} && chown systemd-journal-gateway /run/secrets/{file}")
|
||||
client.copy_from_host(source=f"{tmpdir}/{file}", target=f"/run/secrets/{file}")
|
||||
client.succeed(f"chmod 600 /run/secrets/{file} && chown systemd-journal-gateway /run/secrets/{file}")
|
||||
|
||||
with subtest("Copying keys and certificates"):
|
||||
machine.succeed("mkdir -p /run/secrets/{client,server}")
|
||||
client.succeed("mkdir -p /run/secrets/{client,server}")
|
||||
copy_pem("server/cert.pem")
|
||||
copy_pem("server/key.pem")
|
||||
copy_pem("client/cert.pem")
|
||||
|
||||
@@ -75,10 +75,6 @@ let
|
||||
# improvement: move following profile to ../modules/profiles/vmspawn-guest.nix
|
||||
profile-guest-vmspawn = {
|
||||
imports = [ ../modules/profiles/qemu-guest.nix ];
|
||||
# improvement: move following configuration to qemu-guest.nix
|
||||
boot.initrd.availableKernelModules = [
|
||||
"virtiofs"
|
||||
];
|
||||
|
||||
boot.initrd.systemd.enable = true;
|
||||
# root is defined by systemd-vmspawn
|
||||
|
||||
+23
-23
@@ -48,44 +48,44 @@
|
||||
};
|
||||
testScript = ''
|
||||
start_all()
|
||||
machine.wait_for_unit("sockets.target")
|
||||
server.wait_for_unit("sockets.target")
|
||||
|
||||
with subtest("Check keys are generated"):
|
||||
machine.wait_until_succeeds("curl -v http://127.0.0.1:7654/adv")
|
||||
key = machine.wait_until_succeeds("tang-show-keys 7654")
|
||||
server.wait_until_succeeds("curl -v http://127.0.0.1:7654/adv")
|
||||
key = server.wait_until_succeeds("tang-show-keys 7654")
|
||||
|
||||
with subtest("Check systemd access list"):
|
||||
machine.succeed("ping -c 3 192.168.0.1")
|
||||
machine.fail("curl -v --connect-timeout 3 http://192.168.0.1:7654/adv")
|
||||
server.succeed("ping -c 3 192.168.0.1")
|
||||
server.fail("curl -v --connect-timeout 3 http://192.168.0.1:7654/adv")
|
||||
|
||||
with subtest("Check basic encrypt and decrypt message"):
|
||||
machine.wait_until_succeeds(f"""echo 'Hello World' | clevis encrypt tang '{{ "url": "http://127.0.0.1:7654", "thp":"{key}"}}' > /tmp/encrypted""")
|
||||
decrypted = machine.wait_until_succeeds("clevis decrypt < /tmp/encrypted")
|
||||
server.wait_until_succeeds(f"""echo 'Hello World' | clevis encrypt tang '{{ "url": "http://127.0.0.1:7654", "thp":"{key}"}}' > /tmp/encrypted""")
|
||||
decrypted = server.wait_until_succeeds("clevis decrypt < /tmp/encrypted")
|
||||
assert decrypted.strip() == "Hello World"
|
||||
machine.wait_until_succeeds("tang-show-keys 7654")
|
||||
server.wait_until_succeeds("tang-show-keys 7654")
|
||||
|
||||
with subtest("Check encrypt and decrypt disk"):
|
||||
machine.succeed("cryptsetup luksFormat --force-password --batch-mode /dev/vdb <<<'password'")
|
||||
machine.succeed(f"""clevis luks bind -s1 -y -f -d /dev/vdb tang '{{ "url": "http://127.0.0.1:7654", "thp":"{key}" }}' <<< 'password' """)
|
||||
clevis_luks = machine.succeed("clevis luks list -d /dev/vdb")
|
||||
server.succeed("cryptsetup luksFormat --force-password --batch-mode /dev/vdb <<<'password'")
|
||||
server.succeed(f"""clevis luks bind -s1 -y -f -d /dev/vdb tang '{{ "url": "http://127.0.0.1:7654", "thp":"{key}" }}' <<< 'password' """)
|
||||
clevis_luks = server.succeed("clevis luks list -d /dev/vdb")
|
||||
assert clevis_luks.strip() == """1: tang '{"url":"http://127.0.0.1:7654"}'"""
|
||||
machine.succeed("clevis luks unlock -d /dev/vdb")
|
||||
machine.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")
|
||||
machine.succeed("clevis luks unlock -d /dev/vdb")
|
||||
machine.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")
|
||||
server.succeed("clevis luks unlock -d /dev/vdb")
|
||||
server.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")
|
||||
server.succeed("clevis luks unlock -d /dev/vdb")
|
||||
server.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")
|
||||
# without tang available, unlock should fail
|
||||
machine.succeed("systemctl stop tangd.socket")
|
||||
machine.fail("clevis luks unlock -d /dev/vdb")
|
||||
machine.succeed("systemctl start tangd.socket")
|
||||
server.succeed("systemctl stop tangd.socket")
|
||||
server.fail("clevis luks unlock -d /dev/vdb")
|
||||
server.succeed("systemctl start tangd.socket")
|
||||
|
||||
with subtest("Rotate server keys"):
|
||||
machine.succeed("${pkgs.tang}/libexec/tangd-rotate-keys -d /var/lib/tang")
|
||||
machine.succeed("clevis luks unlock -d /dev/vdb")
|
||||
machine.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")
|
||||
server.succeed("${pkgs.tang}/libexec/tangd-rotate-keys -d /var/lib/tang")
|
||||
server.succeed("clevis luks unlock -d /dev/vdb")
|
||||
server.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")
|
||||
|
||||
with subtest("Test systemd service security"):
|
||||
output = machine.succeed("systemd-analyze security tangd@.service")
|
||||
machine.log(output)
|
||||
output = server.succeed("systemd-analyze security tangd@.service")
|
||||
server.log(output)
|
||||
assert output[-9:-1] == "SAFE :-}"
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
client.succeed("task sync")
|
||||
|
||||
# Useful for debugging
|
||||
client.copy_from_vm("/root/.task", "client")
|
||||
server.copy_from_vm("${cfg.dataDir}", "server")
|
||||
client.copy_from_machine("/root/.task", "client")
|
||||
server.copy_from_machine("${cfg.dataDir}", "server")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -55,13 +55,13 @@
|
||||
# Make a screenshot and save the result:
|
||||
machine.screenshot("tinywl_foot")
|
||||
print(machine.succeed("cat /tmp/test-wayland.out"))
|
||||
machine.copy_from_vm("/tmp/test-wayland.out")
|
||||
machine.copy_from_machine("/tmp/test-wayland.out")
|
||||
|
||||
# Terminate cleanly:
|
||||
machine.send_key("alt-esc")
|
||||
machine.wait_until_fails("pgrep foot")
|
||||
machine.wait_until_fails("pgrep tinywl")
|
||||
machine.wait_for_file("/tmp/tinywl-exit-ok")
|
||||
machine.copy_from_vm("/tmp/tinywl.log")
|
||||
machine.copy_from_machine("/tmp/tinywl.log")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -146,10 +146,10 @@
|
||||
machine.succeed("scrot --display :0 /tmp/glxgears.png")
|
||||
|
||||
# Copy files down.
|
||||
machine.copy_from_vm("/tmp/glxgears.png")
|
||||
machine.copy_from_vm("/tmp/glxgears.stdout")
|
||||
machine.copy_from_vm("/tmp/Xvnc.stdout")
|
||||
machine.copy_from_vm("/tmp/Xvnc.stderr")
|
||||
machine.copy_from_machine("/tmp/glxgears.png")
|
||||
machine.copy_from_machine("/tmp/glxgears.stdout")
|
||||
machine.copy_from_machine("/tmp/Xvnc.stdout")
|
||||
machine.copy_from_machine("/tmp/Xvnc.stderr")
|
||||
'';
|
||||
|
||||
}
|
||||
|
||||
@@ -51,6 +51,8 @@ let
|
||||
enableOCR = true;
|
||||
|
||||
testScript = ''
|
||||
machine = ${name}
|
||||
|
||||
@polling_condition
|
||||
def codium_running():
|
||||
machine.succeed('pgrep -x codium')
|
||||
|
||||
@@ -113,7 +113,7 @@ in
|
||||
|
||||
machine.succeed("run-goupile-test")
|
||||
out_dir = os.environ.get("out", os.getcwd())
|
||||
machine.copy_from_vm("/tmp/videos", out_dir)
|
||||
machine.copy_from_machine("/tmp/videos", out_dir)
|
||||
'';
|
||||
|
||||
# Debug interactively with:
|
||||
|
||||
@@ -52,12 +52,12 @@
|
||||
start_all()
|
||||
|
||||
def get_users():
|
||||
response = machine.succeed("http --check-status http://strichliste.local/api/user")
|
||||
response = server.succeed("http --check-status http://strichliste.local/api/user")
|
||||
users = json.loads(response)["users"]
|
||||
return users
|
||||
|
||||
def get_user(uid: int):
|
||||
response = machine.succeed(f"http --check-status http://strichliste.local/api/user/{uid}")
|
||||
response = server.succeed(f"http --check-status http://strichliste.local/api/user/{uid}")
|
||||
user = json.loads(response)["user"]
|
||||
return user
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
t.assertEqual(len(users), 0, "Strichliste must not have users.")
|
||||
|
||||
with subtest("Create user"):
|
||||
machine.succeed("http --check-status post http://strichliste.local/api/user name=Alice")
|
||||
server.succeed("http --check-status post http://strichliste.local/api/user name=Alice")
|
||||
users = get_users()
|
||||
t.assertEqual(len(users), 1, "Strichliste must have exactly one user.")
|
||||
|
||||
@@ -77,19 +77,19 @@
|
||||
t.assertEqual(user["balance"], 0, "New users should have a balance of 0")
|
||||
|
||||
with subtest("Deposit money"):
|
||||
machine.succeed("http --check-status post http://strichliste.local/api/user/1/transaction amount=500")
|
||||
server.succeed("http --check-status post http://strichliste.local/api/user/1/transaction amount=500")
|
||||
user = get_user(1)
|
||||
t.assertEqual(user["balance"], 500, "Balance must be 500 after depositing 500")
|
||||
|
||||
with subtest("Dispense money"):
|
||||
machine.succeed("http --check-status post http://strichliste.local/api/user/1/transaction amount=-1000")
|
||||
server.succeed("http --check-status post http://strichliste.local/api/user/1/transaction amount=-1000")
|
||||
user = get_user(1)
|
||||
t.assertEqual(user["balance"], -500, "Balance must be -500 after dispensing 1000")
|
||||
|
||||
with subtest("Undo transaction"):
|
||||
response = machine.succeed("http --check-status post http://strichliste.local/api/user/1/transaction amount=7500")
|
||||
response = server.succeed("http --check-status post http://strichliste.local/api/user/1/transaction amount=7500")
|
||||
transaction = json.loads(response)["transaction"]
|
||||
machine.succeed(f"http --check-status delete http://strichliste.local/api/user/1/transaction/{transaction['id']}")
|
||||
server.succeed(f"http --check-status delete http://strichliste.local/api/user/1/transaction/{transaction['id']}")
|
||||
|
||||
server.wait_for_unit("phpfpm-strichliste.service")
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
# NOTE; Wait a couple of seconds for all windmill components to finalise their database migration flow. This prevents race conditions on schema constraints.
|
||||
time.sleep(10) # seconds
|
||||
windmill.succeed("curl --silent --fail http://windmill:8001")
|
||||
t.assertIn("v${pkgs.windmill.version}", machine.succeed("curl --silent --fail http://windmill:8001/api/version"), "Mismatched version response")
|
||||
t.assertIn("v${pkgs.windmill.version}", windmill.succeed("curl --silent --fail http://windmill:8001/api/version"), "Mismatched version response")
|
||||
|
||||
with subtest("Validation"):
|
||||
windmill.succeed("integration-test --language python3 --script ${./python3.script} --input ${./python3.input}")
|
||||
|
||||
@@ -137,7 +137,7 @@ let
|
||||
testScript = ''
|
||||
# save hostapd config file for manual inspection
|
||||
machine.wait_for_unit("hostapd.service")
|
||||
machine.copy_from_vm("/run/hostapd/wlan0.hostapd.conf")
|
||||
machine.copy_from_machine("/run/hostapd/wlan0.hostapd.conf")
|
||||
|
||||
${extraTestScript}
|
||||
'';
|
||||
@@ -257,7 +257,7 @@ in
|
||||
machine.succeed("wpa_cli -i wlan0 list_networks | grep -q test2")
|
||||
|
||||
# save file for manual inspection
|
||||
machine.copy_from_vm(config_file)
|
||||
machine.copy_from_machine(config_file)
|
||||
|
||||
# check hardening options
|
||||
machine.succeed("systemd-analyze security wpa_supplicant >&2")
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
|
||||
rustPlatform.buildRustPackage (finalAttrs: {
|
||||
pname = "ty";
|
||||
version = "0.0.33";
|
||||
version = "0.0.34";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "astral-sh";
|
||||
repo = "ty";
|
||||
tag = finalAttrs.version;
|
||||
fetchSubmodules = true;
|
||||
hash = "sha256-cc/1piasUlv3wwYsXdJaKc8Ck9KF1/FjAjHv6XL6E7o=";
|
||||
hash = "sha256-pLe25JRy6xrFVuNCQKwp9k3Mvc4pfYKF6Xi17yMgSzw=";
|
||||
};
|
||||
|
||||
# For Darwin platforms, remove the integration test for file notifications,
|
||||
@@ -35,7 +35,7 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
|
||||
cargoBuildFlags = [ "--package=ty" ];
|
||||
|
||||
cargoHash = "sha256-8DaJWHFBoVzpbkd9QmJ72a5NeKuX99lfDq3uUp+wd5I=";
|
||||
cargoHash = "sha256-A/oJeFIY/+Pu9jYp3hwGwkSAXfF0VLTHKGP48wsnheo=";
|
||||
|
||||
nativeBuildInputs = [ installShellFiles ];
|
||||
|
||||
|
||||
@@ -90,6 +90,12 @@ stdenv.mkDerivation rec {
|
||||
excludes = [ "networking/httpd_ratelimit_cgi.c" ]; # New since release.
|
||||
hash = "sha256-Msm9sDZrVx7ofunnvnTS73SPKUUpR3Tv5xZ/wBd+rts=";
|
||||
})
|
||||
# syslogd: fix writing to local log file
|
||||
# https://lists.busybox.net/pipermail/busybox/2024-October/090969.html
|
||||
(fetchpatch {
|
||||
url = "https://hg.slitaz.org/wok/raw-file/1cba565dc2a9/busybox/stuff/busybox-1.37-fix-syslogd.patch";
|
||||
hash = "sha256-NZRctLv1CpTfnR6+CA890YY8ljBQLGkkselyP5/TnsQ=";
|
||||
})
|
||||
# https://lists.busybox.net/pipermail/busybox/2026-March/092010.html
|
||||
./build-system-buffer-overflow.patch
|
||||
]
|
||||
|
||||
@@ -155,8 +155,8 @@ lib.makeExtensible (
|
||||
(
|
||||
{
|
||||
nix_2_28 = commonMeson {
|
||||
version = "2.28.6";
|
||||
hash = "sha256-jg2YDTFt8CY4kMg4ha3UK5C+mQY+Zg67nwNy+CmTk5w=";
|
||||
version = "2.28.7";
|
||||
hash = "sha256-Fq4+7uYz6bdE1HvPqn+qZcYX1rNilVKT7YAAPLA8170=";
|
||||
self_attribute_name = "nix_2_28";
|
||||
patches = patches_common ++ [
|
||||
lowdown30PatchOld
|
||||
@@ -165,14 +165,14 @@ lib.makeExtensible (
|
||||
|
||||
nixComponents_2_30 =
|
||||
(nixDependencies.callPackage ./modular/packages.nix rec {
|
||||
version = "2.30.4";
|
||||
version = "2.30.5";
|
||||
inherit teams;
|
||||
otherSplices = generateSplicesForNixComponents "nixComponents_2_30";
|
||||
src = fetchFromGitHub {
|
||||
owner = "NixOS";
|
||||
repo = "nix";
|
||||
tag = version;
|
||||
hash = "sha256-cJ96IBZCYoX0Tdlo5Q7qDSAKfL6QcUq/4Kr1UplH50E=";
|
||||
hash = "sha256-tGiV71RxtCNcUNX86ZwmOIghG4pLwm5nlRKd89er7Gk=";
|
||||
};
|
||||
}).appendPatches
|
||||
(patches_common ++ [ lowdown30PatchOld ]);
|
||||
@@ -181,14 +181,14 @@ lib.makeExtensible (
|
||||
|
||||
nixComponents_2_31 =
|
||||
(nixDependencies.callPackage ./modular/packages.nix rec {
|
||||
version = "2.31.4";
|
||||
version = "2.31.5";
|
||||
inherit teams;
|
||||
otherSplices = generateSplicesForNixComponents "nixComponents_2_31";
|
||||
src = fetchFromGitHub {
|
||||
owner = "NixOS";
|
||||
repo = "nix";
|
||||
tag = version;
|
||||
hash = "sha256-f/haYfcI+9IiYVH+g6cjhF8cK7QWHAFfcPtF+57ujZ0=";
|
||||
hash = "sha256-b7fhCXxl9qKTNPQvG8T/+nOxB95kalt9/aSY+ZSRctk=";
|
||||
};
|
||||
}).appendPatches
|
||||
[ ];
|
||||
@@ -197,14 +197,14 @@ lib.makeExtensible (
|
||||
|
||||
nixComponents_2_34 =
|
||||
(nixDependencies.callPackage ./modular/packages.nix rec {
|
||||
version = "2.34.6";
|
||||
version = "2.34.7";
|
||||
inherit teams;
|
||||
otherSplices = generateSplicesForNixComponents "nixComponents_2_34";
|
||||
src = fetchFromGitHub {
|
||||
owner = "NixOS";
|
||||
repo = "nix";
|
||||
tag = version;
|
||||
hash = "sha256-kHMyhuzhLtH3f+wAcNvAL62ct2kmwZOp2B54SHkMMo0=";
|
||||
hash = "sha256-uj5KNW8Vdm60FCUxD2KsrCVH/WwoemvczWmmrb3Gvlo=";
|
||||
};
|
||||
}).appendPatches
|
||||
patches_common;
|
||||
|
||||
Reference in New Issue
Block a user