mirror of
https://github.com/NixOS/nix
synced 2025-06-24 22:11:15 +02:00
Format .nix files
... with nixfmt (rfc style)
This commit is contained in:
parent
ba6425a7d0
commit
96e550efc5
266 changed files with 7460 additions and 5138 deletions
|
@ -4,8 +4,11 @@
|
|||
nodes.machine = {
|
||||
virtualisation.writableStore = true;
|
||||
# TODO add a test without allowed-users setting. allowed-users is uncommon among NixOS users.
|
||||
nix.settings.allowed-users = ["alice" "bob"];
|
||||
nix.settings.trusted-users = ["alice"];
|
||||
nix.settings.allowed-users = [
|
||||
"alice"
|
||||
"bob"
|
||||
];
|
||||
nix.settings.trusted-users = [ "alice" ];
|
||||
|
||||
users.users.alice.isNormalUser = true;
|
||||
users.users.bob.isNormalUser = true;
|
||||
|
@ -15,80 +18,80 @@
|
|||
};
|
||||
|
||||
testScript =
|
||||
let
|
||||
pathFour = "/nix/store/20xfy868aiic0r0flgzq4n5dq1yvmxkn-four";
|
||||
in
|
||||
''
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
machine.succeed("""
|
||||
exec 1>&2
|
||||
echo kSELDhobKaF8/VdxIxdP7EQe+Q > one
|
||||
diff $(nix store add-file one) one
|
||||
""")
|
||||
machine.succeed("""
|
||||
su --login alice -c '
|
||||
set -x
|
||||
cd ~
|
||||
echo ehHtmfuULXYyBV6NBk6QUi8iE0 > two
|
||||
ls
|
||||
diff $(echo $(nix store add-file two)) two' 1>&2
|
||||
""")
|
||||
machine.succeed("""
|
||||
su --login bob -c '
|
||||
set -x
|
||||
cd ~
|
||||
echo 0Jw8RNp7cK0W2AdNbcquofcOVk > three
|
||||
diff $(nix store add-file three) three
|
||||
' 1>&2
|
||||
""")
|
||||
|
||||
# We're going to check that a path is not created
|
||||
machine.succeed("""
|
||||
! [[ -e ${pathFour} ]]
|
||||
""")
|
||||
machine.succeed("""
|
||||
su --login mallory -c '
|
||||
set -x
|
||||
cd ~
|
||||
echo 5mgtDj0ohrWkT50TLR0f4tIIxY > four;
|
||||
(! nix store add-file four 2>&1) | grep -F "cannot open connection to remote store"
|
||||
(! nix store add-file four 2>&1) | grep -F "Connection reset by peer"
|
||||
! [[ -e ${pathFour} ]]
|
||||
' 1>&2
|
||||
""")
|
||||
|
||||
# Check that the file _can_ be added, and matches the expected path we were checking
|
||||
machine.succeed("""
|
||||
exec 1>&2
|
||||
echo 5mgtDj0ohrWkT50TLR0f4tIIxY > four
|
||||
four="$(nix store add-file four)"
|
||||
diff $four four
|
||||
diff <(echo $four) <(echo ${pathFour})
|
||||
""")
|
||||
|
||||
machine.succeed("""
|
||||
su --login alice -c 'nix-store --verify --repair'
|
||||
""")
|
||||
|
||||
machine.succeed("""
|
||||
set -x
|
||||
su --login bob -c '(! nix-store --verify --repair 2>&1)' | tee diag 1>&2
|
||||
grep -F "you are not privileged to repair paths" diag
|
||||
""")
|
||||
|
||||
machine.succeed("""
|
||||
set -x
|
||||
su --login mallory -c '
|
||||
nix-store --generate-binary-cache-key cache1.example.org sk1 pk1
|
||||
(! nix store sign --key-file sk1 ${pathFour} 2>&1)' | tee diag 1>&2
|
||||
grep -F "cannot open connection to remote store 'daemon'" diag
|
||||
""")
|
||||
|
||||
machine.succeed("""
|
||||
let
|
||||
pathFour = "/nix/store/20xfy868aiic0r0flgzq4n5dq1yvmxkn-four";
|
||||
in
|
||||
''
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
machine.succeed("""
|
||||
exec 1>&2
|
||||
echo kSELDhobKaF8/VdxIxdP7EQe+Q > one
|
||||
diff $(nix store add-file one) one
|
||||
""")
|
||||
machine.succeed("""
|
||||
su --login alice -c '
|
||||
set -x
|
||||
cd ~
|
||||
echo ehHtmfuULXYyBV6NBk6QUi8iE0 > two
|
||||
ls
|
||||
diff $(echo $(nix store add-file two)) two' 1>&2
|
||||
""")
|
||||
machine.succeed("""
|
||||
su --login bob -c '
|
||||
nix-store --generate-binary-cache-key cache1.example.org sk1 pk1
|
||||
nix store sign --key-file sk1 ${pathFour}
|
||||
'
|
||||
""")
|
||||
'';
|
||||
set -x
|
||||
cd ~
|
||||
echo 0Jw8RNp7cK0W2AdNbcquofcOVk > three
|
||||
diff $(nix store add-file three) three
|
||||
' 1>&2
|
||||
""")
|
||||
|
||||
# We're going to check that a path is not created
|
||||
machine.succeed("""
|
||||
! [[ -e ${pathFour} ]]
|
||||
""")
|
||||
machine.succeed("""
|
||||
su --login mallory -c '
|
||||
set -x
|
||||
cd ~
|
||||
echo 5mgtDj0ohrWkT50TLR0f4tIIxY > four;
|
||||
(! nix store add-file four 2>&1) | grep -F "cannot open connection to remote store"
|
||||
(! nix store add-file four 2>&1) | grep -F "Connection reset by peer"
|
||||
! [[ -e ${pathFour} ]]
|
||||
' 1>&2
|
||||
""")
|
||||
|
||||
# Check that the file _can_ be added, and matches the expected path we were checking
|
||||
machine.succeed("""
|
||||
exec 1>&2
|
||||
echo 5mgtDj0ohrWkT50TLR0f4tIIxY > four
|
||||
four="$(nix store add-file four)"
|
||||
diff $four four
|
||||
diff <(echo $four) <(echo ${pathFour})
|
||||
""")
|
||||
|
||||
machine.succeed("""
|
||||
su --login alice -c 'nix-store --verify --repair'
|
||||
""")
|
||||
|
||||
machine.succeed("""
|
||||
set -x
|
||||
su --login bob -c '(! nix-store --verify --repair 2>&1)' | tee diag 1>&2
|
||||
grep -F "you are not privileged to repair paths" diag
|
||||
""")
|
||||
|
||||
machine.succeed("""
|
||||
set -x
|
||||
su --login mallory -c '
|
||||
nix-store --generate-binary-cache-key cache1.example.org sk1 pk1
|
||||
(! nix store sign --key-file sk1 ${pathFour} 2>&1)' | tee diag 1>&2
|
||||
grep -F "cannot open connection to remote store 'daemon'" diag
|
||||
""")
|
||||
|
||||
machine.succeed("""
|
||||
su --login bob -c '
|
||||
nix-store --generate-binary-cache-key cache1.example.org sk1 pk1
|
||||
nix store sign --key-file sk1 ${pathFour}
|
||||
'
|
||||
""")
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -27,12 +27,15 @@ let
|
|||
# domain socket.
|
||||
# Compiled statically so that we can easily send it to the VM and use it
|
||||
# inside the build sandbox.
|
||||
sender = pkgs.runCommandWith {
|
||||
name = "sender";
|
||||
stdenv = pkgs.pkgsStatic.stdenv;
|
||||
} ''
|
||||
$CC -static -o $out ${./sender.c}
|
||||
'';
|
||||
sender =
|
||||
pkgs.runCommandWith
|
||||
{
|
||||
name = "sender";
|
||||
stdenv = pkgs.pkgsStatic.stdenv;
|
||||
}
|
||||
''
|
||||
$CC -static -o $out ${./sender.c}
|
||||
'';
|
||||
|
||||
# Okay, so we have a file descriptor shipped out of the FOD now. But the
|
||||
# Nix store is read-only, right? .. Well, yeah. But this file descriptor
|
||||
|
@ -47,44 +50,57 @@ in
|
|||
name = "ca-fd-leak";
|
||||
|
||||
nodes.machine =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ virtualisation.writableStore = true;
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
virtualisation.writableStore = true;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
virtualisation.additionalPaths = [ pkgs.busybox-sandbox-shell sender smuggler pkgs.socat ];
|
||||
virtualisation.additionalPaths = [
|
||||
pkgs.busybox-sandbox-shell
|
||||
sender
|
||||
smuggler
|
||||
pkgs.socat
|
||||
];
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
start_all()
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
start_all()
|
||||
|
||||
machine.succeed("echo hello")
|
||||
# Start the smuggler server
|
||||
machine.succeed("${smuggler}/bin/smuggler ${socketName} >&2 &")
|
||||
machine.succeed("echo hello")
|
||||
# Start the smuggler server
|
||||
machine.succeed("${smuggler}/bin/smuggler ${socketName} >&2 &")
|
||||
|
||||
# Build the smuggled derivation.
|
||||
# This will connect to the smuggler server and send it the file descriptor
|
||||
machine.succeed(r"""
|
||||
nix-build -E '
|
||||
builtins.derivation {
|
||||
name = "smuggled";
|
||||
system = builtins.currentSystem;
|
||||
# look ma, no tricks!
|
||||
outputHashMode = "flat";
|
||||
outputHashAlgo = "sha256";
|
||||
outputHash = builtins.hashString "sha256" "hello, world\n";
|
||||
builder = "${pkgs.busybox-sandbox-shell}/bin/sh";
|
||||
args = [ "-c" "echo \"hello, world\" > $out; ''${${sender}} ${socketName}" ];
|
||||
}'
|
||||
""".strip())
|
||||
# Build the smuggled derivation.
|
||||
# This will connect to the smuggler server and send it the file descriptor
|
||||
machine.succeed(r"""
|
||||
nix-build -E '
|
||||
builtins.derivation {
|
||||
name = "smuggled";
|
||||
system = builtins.currentSystem;
|
||||
# look ma, no tricks!
|
||||
outputHashMode = "flat";
|
||||
outputHashAlgo = "sha256";
|
||||
outputHash = builtins.hashString "sha256" "hello, world\n";
|
||||
builder = "${pkgs.busybox-sandbox-shell}/bin/sh";
|
||||
args = [ "-c" "echo \"hello, world\" > $out; ''${${sender}} ${socketName}" ];
|
||||
}'
|
||||
""".strip())
|
||||
|
||||
|
||||
# Tell the smuggler server that we're done
|
||||
machine.execute("echo done | ${pkgs.socat}/bin/socat - ABSTRACT-CONNECT:${socketName}")
|
||||
# Tell the smuggler server that we're done
|
||||
machine.execute("echo done | ${pkgs.socat}/bin/socat - ABSTRACT-CONNECT:${socketName}")
|
||||
|
||||
# Check that the file was not modified
|
||||
machine.succeed(r"""
|
||||
cat ./result
|
||||
test "$(cat ./result)" = "hello, world"
|
||||
""".strip())
|
||||
'';
|
||||
# Check that the file was not modified
|
||||
machine.succeed(r"""
|
||||
cat ./result
|
||||
test "$(cat ./result)" = "hello, world"
|
||||
""".strip())
|
||||
'';
|
||||
|
||||
}
|
||||
|
|
|
@ -3,38 +3,39 @@
|
|||
{
|
||||
name = "cgroups";
|
||||
|
||||
nodes =
|
||||
{
|
||||
host =
|
||||
{ config, pkgs, ... }:
|
||||
{ virtualisation.additionalPaths = [ pkgs.stdenvNoCC ];
|
||||
nix.extraOptions =
|
||||
''
|
||||
extra-experimental-features = nix-command auto-allocate-uids cgroups
|
||||
extra-system-features = uid-range
|
||||
'';
|
||||
nix.settings.use-cgroups = true;
|
||||
nix.nixPath = [ "nixpkgs=${nixpkgs}" ];
|
||||
};
|
||||
};
|
||||
nodes = {
|
||||
host =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
virtualisation.additionalPaths = [ pkgs.stdenvNoCC ];
|
||||
nix.extraOptions = ''
|
||||
extra-experimental-features = nix-command auto-allocate-uids cgroups
|
||||
extra-system-features = uid-range
|
||||
'';
|
||||
nix.settings.use-cgroups = true;
|
||||
nix.nixPath = [ "nixpkgs=${nixpkgs}" ];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
start_all()
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
start_all()
|
||||
|
||||
host.wait_for_unit("multi-user.target")
|
||||
host.wait_for_unit("multi-user.target")
|
||||
|
||||
# Start build in background
|
||||
host.execute("NIX_REMOTE=daemon nix build --auto-allocate-uids --file ${./hang.nix} >&2 &")
|
||||
service = "/sys/fs/cgroup/system.slice/nix-daemon.service"
|
||||
# Start build in background
|
||||
host.execute("NIX_REMOTE=daemon nix build --auto-allocate-uids --file ${./hang.nix} >&2 &")
|
||||
service = "/sys/fs/cgroup/system.slice/nix-daemon.service"
|
||||
|
||||
# Wait for cgroups to be created
|
||||
host.succeed(f"until [ -e {service}/nix-daemon ]; do sleep 1; done", timeout=30)
|
||||
host.succeed(f"until [ -e {service}/nix-build-uid-* ]; do sleep 1; done", timeout=30)
|
||||
# Wait for cgroups to be created
|
||||
host.succeed(f"until [ -e {service}/nix-daemon ]; do sleep 1; done", timeout=30)
|
||||
host.succeed(f"until [ -e {service}/nix-build-uid-* ]; do sleep 1; done", timeout=30)
|
||||
|
||||
# Check that there aren't processes where there shouldn't be, and that there are where there should be
|
||||
host.succeed(f'[ -z "$(cat {service}/cgroup.procs)" ]')
|
||||
host.succeed(f'[ -n "$(cat {service}/nix-daemon/cgroup.procs)" ]')
|
||||
host.succeed(f'[ -n "$(cat {service}/nix-build-uid-*/cgroup.procs)" ]')
|
||||
'';
|
||||
# Check that there aren't processes where there shouldn't be, and that there are where there should be
|
||||
host.succeed(f'[ -z "$(cat {service}/cgroup.procs)" ]')
|
||||
host.succeed(f'[ -n "$(cat {service}/nix-daemon/cgroup.procs)" ]')
|
||||
host.succeed(f'[ -n "$(cat {service}/nix-build-uid-*/cgroup.procs)" ]')
|
||||
'';
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
{ }:
|
||||
|
||||
with import <nixpkgs> {};
|
||||
with import <nixpkgs> { };
|
||||
|
||||
runCommand "hang"
|
||||
{ requiredSystemFeatures = "uid-range";
|
||||
{
|
||||
requiredSystemFeatures = "uid-range";
|
||||
}
|
||||
''
|
||||
sleep infinity
|
||||
|
|
|
@ -1,31 +1,45 @@
|
|||
{ lib, config, nixpkgs, ... }:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
nixpkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
pkgs = config.nodes.machine.nixpkgs.pkgs;
|
||||
pkgA = pkgs.hello;
|
||||
pkgB = pkgs.cowsay;
|
||||
in {
|
||||
in
|
||||
{
|
||||
name = "chroot-store";
|
||||
|
||||
nodes =
|
||||
{ machine =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [ pkgA ];
|
||||
environment.systemPackages = [ pkgB ];
|
||||
nix.extraOptions = "experimental-features = nix-command";
|
||||
};
|
||||
};
|
||||
nodes = {
|
||||
machine =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [ pkgA ];
|
||||
environment.systemPackages = [ pkgB ];
|
||||
nix.extraOptions = "experimental-features = nix-command";
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
# fmt: off
|
||||
start_all()
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
# fmt: off
|
||||
start_all()
|
||||
|
||||
machine.succeed("nix copy --no-check-sigs --to /tmp/nix ${pkgA}")
|
||||
machine.succeed("nix copy --no-check-sigs --to /tmp/nix ${pkgA}")
|
||||
|
||||
machine.succeed("nix shell --store /tmp/nix ${pkgA} --command hello >&2")
|
||||
machine.succeed("nix shell --store /tmp/nix ${pkgA} --command hello >&2")
|
||||
|
||||
# Test that /nix/store is available via an overlayfs mount.
|
||||
machine.succeed("nix shell --store /tmp/nix ${pkgA} --command cowsay foo >&2")
|
||||
'';
|
||||
# Test that /nix/store is available via an overlayfs mount.
|
||||
machine.succeed("nix shell --store /tmp/nix ${pkgA} --command cowsay foo >&2")
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -4,60 +4,67 @@
|
|||
{
|
||||
name = "containers";
|
||||
|
||||
nodes =
|
||||
{
|
||||
host =
|
||||
{ config, lib, pkgs, nodes, ... }:
|
||||
{ virtualisation.writableStore = true;
|
||||
virtualisation.diskSize = 2048;
|
||||
virtualisation.additionalPaths =
|
||||
[ pkgs.stdenvNoCC
|
||||
(import ./systemd-nspawn.nix { inherit nixpkgs; }).toplevel
|
||||
];
|
||||
virtualisation.memorySize = 4096;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
nix.extraOptions =
|
||||
''
|
||||
extra-experimental-features = nix-command auto-allocate-uids cgroups
|
||||
extra-system-features = uid-range
|
||||
'';
|
||||
nix.nixPath = [ "nixpkgs=${nixpkgs}" ];
|
||||
};
|
||||
};
|
||||
nodes = {
|
||||
host =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
nodes,
|
||||
...
|
||||
}:
|
||||
{
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.diskSize = 2048;
|
||||
virtualisation.additionalPaths = [
|
||||
pkgs.stdenvNoCC
|
||||
(import ./systemd-nspawn.nix { inherit nixpkgs; }).toplevel
|
||||
];
|
||||
virtualisation.memorySize = 4096;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
nix.extraOptions = ''
|
||||
extra-experimental-features = nix-command auto-allocate-uids cgroups
|
||||
extra-system-features = uid-range
|
||||
'';
|
||||
nix.nixPath = [ "nixpkgs=${nixpkgs}" ];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
start_all()
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
start_all()
|
||||
|
||||
host.succeed("nix --version >&2")
|
||||
host.succeed("nix --version >&2")
|
||||
|
||||
# Test that 'id' gives the expected result in various configurations.
|
||||
# Test that 'id' gives the expected result in various configurations.
|
||||
|
||||
# Existing UIDs, sandbox.
|
||||
host.succeed("nix build --no-auto-allocate-uids --sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-1")
|
||||
host.succeed("[[ $(cat ./result) = 'uid=1000(nixbld) gid=100(nixbld) groups=100(nixbld)' ]]")
|
||||
# Existing UIDs, sandbox.
|
||||
host.succeed("nix build --no-auto-allocate-uids --sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-1")
|
||||
host.succeed("[[ $(cat ./result) = 'uid=1000(nixbld) gid=100(nixbld) groups=100(nixbld)' ]]")
|
||||
|
||||
# Existing UIDs, no sandbox.
|
||||
host.succeed("nix build --no-auto-allocate-uids --no-sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-2")
|
||||
host.succeed("[[ $(cat ./result) = 'uid=30001(nixbld1) gid=30000(nixbld) groups=30000(nixbld)' ]]")
|
||||
# Existing UIDs, no sandbox.
|
||||
host.succeed("nix build --no-auto-allocate-uids --no-sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-2")
|
||||
host.succeed("[[ $(cat ./result) = 'uid=30001(nixbld1) gid=30000(nixbld) groups=30000(nixbld)' ]]")
|
||||
|
||||
# Auto-allocated UIDs, sandbox.
|
||||
host.succeed("nix build --auto-allocate-uids --sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-3")
|
||||
host.succeed("[[ $(cat ./result) = 'uid=1000(nixbld) gid=100(nixbld) groups=100(nixbld)' ]]")
|
||||
# Auto-allocated UIDs, sandbox.
|
||||
host.succeed("nix build --auto-allocate-uids --sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-3")
|
||||
host.succeed("[[ $(cat ./result) = 'uid=1000(nixbld) gid=100(nixbld) groups=100(nixbld)' ]]")
|
||||
|
||||
# Auto-allocated UIDs, no sandbox.
|
||||
host.succeed("nix build --auto-allocate-uids --no-sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-4")
|
||||
host.succeed("[[ $(cat ./result) = 'uid=872415232 gid=30000(nixbld) groups=30000(nixbld)' ]]")
|
||||
# Auto-allocated UIDs, no sandbox.
|
||||
host.succeed("nix build --auto-allocate-uids --no-sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-4")
|
||||
host.succeed("[[ $(cat ./result) = 'uid=872415232 gid=30000(nixbld) groups=30000(nixbld)' ]]")
|
||||
|
||||
# Auto-allocated UIDs, UID range, sandbox.
|
||||
host.succeed("nix build --auto-allocate-uids --sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-5 --arg uidRange true")
|
||||
host.succeed("[[ $(cat ./result) = 'uid=0(root) gid=0(root) groups=0(root)' ]]")
|
||||
# Auto-allocated UIDs, UID range, sandbox.
|
||||
host.succeed("nix build --auto-allocate-uids --sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-5 --arg uidRange true")
|
||||
host.succeed("[[ $(cat ./result) = 'uid=0(root) gid=0(root) groups=0(root)' ]]")
|
||||
|
||||
# Auto-allocated UIDs, UID range, no sandbox.
|
||||
host.fail("nix build --auto-allocate-uids --no-sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-6 --arg uidRange true")
|
||||
# Auto-allocated UIDs, UID range, no sandbox.
|
||||
host.fail("nix build --auto-allocate-uids --no-sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-6 --arg uidRange true")
|
||||
|
||||
# Run systemd-nspawn in a Nix build.
|
||||
host.succeed("nix build --auto-allocate-uids --sandbox -L --offline --impure --file ${./systemd-nspawn.nix} --argstr nixpkgs ${nixpkgs}")
|
||||
host.succeed("[[ $(cat ./result/msg) = 'Hello World' ]]")
|
||||
'';
|
||||
# Run systemd-nspawn in a Nix build.
|
||||
host.succeed("nix build --auto-allocate-uids --sandbox -L --offline --impure --file ${./systemd-nspawn.nix} --argstr nixpkgs ${nixpkgs}")
|
||||
host.succeed("[[ $(cat ./result/msg) = 'Hello World' ]]")
|
||||
'';
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
{ name, uidRange ? false }:
|
||||
{
|
||||
name,
|
||||
uidRange ? false,
|
||||
}:
|
||||
|
||||
with import <nixpkgs> {};
|
||||
with import <nixpkgs> { };
|
||||
|
||||
runCommand name
|
||||
{ requiredSystemFeatures = if uidRange then ["uid-range"] else [];
|
||||
}
|
||||
"id; id > $out"
|
||||
runCommand name {
|
||||
requiredSystemFeatures = if uidRange then [ "uid-range" ] else [ ];
|
||||
} "id; id > $out"
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
let
|
||||
|
||||
machine = { config, pkgs, ... }:
|
||||
machine =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
system.stateVersion = "22.05";
|
||||
boot.isContainer = true;
|
||||
|
@ -31,10 +32,12 @@ let
|
|||
};
|
||||
};
|
||||
|
||||
cfg = (import (nixpkgs + "/nixos/lib/eval-config.nix") {
|
||||
modules = [ machine ];
|
||||
system = "x86_64-linux";
|
||||
});
|
||||
cfg = (
|
||||
import (nixpkgs + "/nixos/lib/eval-config.nix") {
|
||||
modules = [ machine ];
|
||||
system = "x86_64-linux";
|
||||
}
|
||||
);
|
||||
|
||||
config = cfg.config;
|
||||
|
||||
|
@ -43,7 +46,8 @@ in
|
|||
with cfg._module.args.pkgs;
|
||||
|
||||
runCommand "test"
|
||||
{ buildInputs = [ config.system.path ];
|
||||
{
|
||||
buildInputs = [ config.system.path ];
|
||||
requiredSystemFeatures = [ "uid-range" ];
|
||||
toplevel = config.system.build.toplevel;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,26 @@
|
|||
{ lib, nixpkgs, nixpkgsFor, nixpkgs-23-11 }:
|
||||
{
|
||||
lib,
|
||||
nixpkgs,
|
||||
nixpkgsFor,
|
||||
nixpkgs-23-11,
|
||||
}:
|
||||
|
||||
let
|
||||
|
||||
nixos-lib = import (nixpkgs + "/nixos/lib") { };
|
||||
|
||||
noTests = pkg: pkg.overrideAttrs (
|
||||
finalAttrs: prevAttrs: {
|
||||
doCheck = false;
|
||||
doInstallCheck = false;
|
||||
});
|
||||
noTests =
|
||||
pkg:
|
||||
pkg.overrideAttrs (
|
||||
finalAttrs: prevAttrs: {
|
||||
doCheck = false;
|
||||
doInstallCheck = false;
|
||||
}
|
||||
);
|
||||
|
||||
# https://nixos.org/manual/nixos/unstable/index.html#sec-calling-nixos-tests
|
||||
runNixOSTestFor = system: test:
|
||||
runNixOSTestFor =
|
||||
system: test:
|
||||
(nixos-lib.runTest {
|
||||
imports = [
|
||||
test
|
||||
|
@ -36,44 +45,61 @@ let
|
|||
# allow running tests against older nix versions via `nix eval --apply`
|
||||
# Example:
|
||||
# nix build "$(nix eval --raw --impure .#hydraJobs.tests.fetch-git --apply 't: (t.forNix "2.19.2").drvPath')^*"
|
||||
forNix = nixVersion: runNixOSTestFor system {
|
||||
imports = [test];
|
||||
defaults.nixpkgs.overlays = [(curr: prev: {
|
||||
nix = let
|
||||
packages = (builtins.getFlake "nix/${nixVersion}").packages.${system};
|
||||
in packages.nix-cli or packages.nix;
|
||||
})];
|
||||
};
|
||||
forNix =
|
||||
nixVersion:
|
||||
runNixOSTestFor system {
|
||||
imports = [ test ];
|
||||
defaults.nixpkgs.overlays = [
|
||||
(curr: prev: {
|
||||
nix =
|
||||
let
|
||||
packages = (builtins.getFlake "nix/${nixVersion}").packages.${system};
|
||||
in
|
||||
packages.nix-cli or packages.nix;
|
||||
})
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# Checks that a NixOS configuration does not contain any references to our
|
||||
# locally defined Nix version.
|
||||
checkOverrideNixVersion = { pkgs, lib, ... }: {
|
||||
# pkgs.nix: The new Nix in this repo
|
||||
# We disallow it, to make sure we don't accidentally use it.
|
||||
system.forbiddenDependenciesRegexes = [
|
||||
(lib.strings.escapeRegex "nix-${pkgs.nix.version}")
|
||||
];
|
||||
};
|
||||
checkOverrideNixVersion =
|
||||
{ pkgs, lib, ... }:
|
||||
{
|
||||
# pkgs.nix: The new Nix in this repo
|
||||
# We disallow it, to make sure we don't accidentally use it.
|
||||
system.forbiddenDependenciesRegexes = [
|
||||
(lib.strings.escapeRegex "nix-${pkgs.nix.version}")
|
||||
];
|
||||
};
|
||||
|
||||
otherNixes.nix_2_3.setNixPackage = { lib, pkgs, ... }: {
|
||||
imports = [ checkOverrideNixVersion ];
|
||||
nix.package = lib.mkForce pkgs.nixVersions.nix_2_3;
|
||||
};
|
||||
otherNixes.nix_2_3.setNixPackage =
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
imports = [ checkOverrideNixVersion ];
|
||||
nix.package = lib.mkForce pkgs.nixVersions.nix_2_3;
|
||||
};
|
||||
|
||||
otherNixes.nix_2_13.setNixPackage = { lib, pkgs, ... }: {
|
||||
imports = [ checkOverrideNixVersion ];
|
||||
nix.package = lib.mkForce (
|
||||
nixpkgs-23-11.legacyPackages.${pkgs.stdenv.hostPlatform.system}.nixVersions.nix_2_13.overrideAttrs (o: {
|
||||
meta = o.meta // { knownVulnerabilities = []; };
|
||||
})
|
||||
);
|
||||
};
|
||||
otherNixes.nix_2_13.setNixPackage =
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
imports = [ checkOverrideNixVersion ];
|
||||
nix.package = lib.mkForce (
|
||||
nixpkgs-23-11.legacyPackages.${pkgs.stdenv.hostPlatform.system}.nixVersions.nix_2_13.overrideAttrs
|
||||
(o: {
|
||||
meta = o.meta // {
|
||||
knownVulnerabilities = [ ];
|
||||
};
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
otherNixes.nix_2_18.setNixPackage = { lib, pkgs, ... }: {
|
||||
imports = [ checkOverrideNixVersion ];
|
||||
nix.package = lib.mkForce pkgs.nixVersions.nix_2_18;
|
||||
};
|
||||
otherNixes.nix_2_18.setNixPackage =
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
imports = [ checkOverrideNixVersion ];
|
||||
nix.package = lib.mkForce pkgs.nixVersions.nix_2_18;
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
|
@ -86,30 +112,37 @@ in
|
|||
|
||||
}
|
||||
// lib.concatMapAttrs (
|
||||
nixVersion: { setNixPackage, ... }:
|
||||
nixVersion:
|
||||
{ setNixPackage, ... }:
|
||||
{
|
||||
"remoteBuilds_remote_${nixVersion}" = runNixOSTestFor "x86_64-linux" {
|
||||
name = "remoteBuilds_remote_${nixVersion}";
|
||||
imports = [ ./remote-builds.nix ];
|
||||
builders.config = { lib, pkgs, ... }: {
|
||||
imports = [ setNixPackage ];
|
||||
};
|
||||
builders.config =
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
imports = [ setNixPackage ];
|
||||
};
|
||||
};
|
||||
|
||||
"remoteBuilds_local_${nixVersion}" = runNixOSTestFor "x86_64-linux" {
|
||||
name = "remoteBuilds_local_${nixVersion}";
|
||||
imports = [ ./remote-builds.nix ];
|
||||
nodes.client = { lib, pkgs, ... }: {
|
||||
imports = [ setNixPackage ];
|
||||
};
|
||||
nodes.client =
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
imports = [ setNixPackage ];
|
||||
};
|
||||
};
|
||||
|
||||
"remoteBuildsSshNg_remote_${nixVersion}" = runNixOSTestFor "x86_64-linux" {
|
||||
name = "remoteBuildsSshNg_remote_${nixVersion}";
|
||||
imports = [ ./remote-builds-ssh-ng.nix ];
|
||||
builders.config = { lib, pkgs, ... }: {
|
||||
imports = [ setNixPackage ];
|
||||
};
|
||||
builders.config =
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
imports = [ setNixPackage ];
|
||||
};
|
||||
};
|
||||
|
||||
# FIXME: these tests don't work yet
|
||||
|
@ -143,9 +176,7 @@ in
|
|||
|
||||
containers = runNixOSTestFor "x86_64-linux" ./containers/containers.nix;
|
||||
|
||||
setuid = lib.genAttrs
|
||||
["x86_64-linux"]
|
||||
(system: runNixOSTestFor system ./setuid.nix);
|
||||
setuid = lib.genAttrs [ "x86_64-linux" ] (system: runNixOSTestFor system ./setuid.nix);
|
||||
|
||||
fetch-git = runNixOSTestFor "x86_64-linux" ./fetch-git;
|
||||
|
||||
|
|
|
@ -7,26 +7,27 @@
|
|||
];
|
||||
|
||||
/*
|
||||
Test cases
|
||||
Test cases
|
||||
|
||||
Test cases are automatically imported from ./test-cases/{name}
|
||||
Test cases are automatically imported from ./test-cases/{name}
|
||||
|
||||
The following is set up automatically for each test case:
|
||||
- a repo with the {name} is created on the gitea server
|
||||
- a repo with the {name} is created on the client
|
||||
- the client repo is configured to push to the server repo
|
||||
The following is set up automatically for each test case:
|
||||
- a repo with the {name} is created on the gitea server
|
||||
- a repo with the {name} is created on the client
|
||||
- the client repo is configured to push to the server repo
|
||||
|
||||
Python variables:
|
||||
- repo.path: the path to the directory of the client repo
|
||||
- repo.git: the git command with the client repo as the working directory
|
||||
- repo.remote: the url to the server repo
|
||||
Python variables:
|
||||
- repo.path: the path to the directory of the client repo
|
||||
- repo.git: the git command with the client repo as the working directory
|
||||
- repo.remote: the url to the server repo
|
||||
*/
|
||||
testCases =
|
||||
map
|
||||
(testCaseName: {...}: {
|
||||
testCases = map (
|
||||
testCaseName:
|
||||
{ ... }:
|
||||
{
|
||||
imports = [ (./test-cases + "/${testCaseName}") ];
|
||||
# ensures tests are named like their directories they are defined in
|
||||
name = testCaseName;
|
||||
})
|
||||
(lib.attrNames (builtins.readDir ./test-cases));
|
||||
}
|
||||
) (lib.attrNames (builtins.readDir ./test-cases));
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
script = ''
|
||||
# add a file to the repo
|
||||
client.succeed(f"""
|
||||
echo ${config.name /* to make the git tree and store path unique */} > {repo.path}/test-case \
|
||||
echo ${config.name # to make the git tree and store path unique
|
||||
} > {repo.path}/test-case \
|
||||
&& echo lutyabrook > {repo.path}/new-york-state \
|
||||
&& {repo.git} add test-case new-york-state \
|
||||
&& {repo.git} commit -m 'commit1'
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
script = ''
|
||||
# add a file to the repo
|
||||
client.succeed(f"""
|
||||
echo ${config.name /* to make the git tree and store path unique */} > {repo.path}/test-case \
|
||||
echo ${config.name # to make the git tree and store path unique
|
||||
} > {repo.path}/test-case \
|
||||
&& echo chiang-mai > {repo.path}/thailand \
|
||||
&& {repo.git} add test-case thailand \
|
||||
&& {repo.git} commit -m 'commit1'
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
script = ''
|
||||
# add a file to the repo
|
||||
client.succeed(f"""
|
||||
echo ${config.name /* to make the git tree and store path unique */} > {repo.path}/test-case \
|
||||
echo ${config.name # to make the git tree and store path unique
|
||||
} > {repo.path}/test-case \
|
||||
&& echo chiang-mai > {repo.path}/thailand \
|
||||
&& {repo.git} add test-case thailand \
|
||||
&& {repo.git} commit -m 'commit1'
|
||||
|
|
|
@ -8,25 +8,27 @@ let
|
|||
|
||||
boolPyLiteral = b: if b then "True" else "False";
|
||||
|
||||
testCaseExtension = { config, ... }: {
|
||||
options = {
|
||||
repo.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Whether to provide a repo variable - automatic repo creation.";
|
||||
testCaseExtension =
|
||||
{ config, ... }:
|
||||
{
|
||||
options = {
|
||||
repo.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Whether to provide a repo variable - automatic repo creation.";
|
||||
};
|
||||
repo.private = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether the repo should be private.";
|
||||
};
|
||||
};
|
||||
repo.private = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether the repo should be private.";
|
||||
config = mkIf config.repo.enable {
|
||||
setupScript = ''
|
||||
repo = Repo("${config.name}", private=${boolPyLiteral config.repo.private})
|
||||
'';
|
||||
};
|
||||
};
|
||||
config = mkIf config.repo.enable {
|
||||
setupScript = ''
|
||||
repo = Repo("${config.name}", private=${boolPyLiteral config.repo.private})
|
||||
'';
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options = {
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
{ lib, nixpkgs, system, pkgs, ... }: let
|
||||
{
|
||||
lib,
|
||||
nixpkgs,
|
||||
system,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
clientPrivateKey = pkgs.writeText "id_ed25519" ''
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
|
@ -9,41 +16,52 @@
|
|||
-----END OPENSSH PRIVATE KEY-----
|
||||
'';
|
||||
|
||||
clientPublicKey =
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFt5a8eH8BYZYjoQhzXGVKKHJe1pw1D0p7O2Vb9VTLzB";
|
||||
clientPublicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFt5a8eH8BYZYjoQhzXGVKKHJe1pw1D0p7O2Vb9VTLzB";
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
../testsupport/setup.nix
|
||||
../testsupport/gitea-repo.nix
|
||||
];
|
||||
nodes = {
|
||||
gitea = { pkgs, ... }: {
|
||||
services.gitea.enable = true;
|
||||
services.gitea.settings.service.DISABLE_REGISTRATION = true;
|
||||
services.gitea.settings.log.LEVEL = "Info";
|
||||
services.gitea.settings.database.LOG_SQL = false;
|
||||
services.openssh.enable = true;
|
||||
networking.firewall.allowedTCPPorts = [ 3000 ];
|
||||
environment.systemPackages = [ pkgs.git pkgs.gitea ];
|
||||
|
||||
users.users.root.openssh.authorizedKeys.keys = [clientPublicKey];
|
||||
|
||||
# TODO: remove this after updating to nixos-23.11
|
||||
nixpkgs.pkgs = lib.mkForce (import nixpkgs {
|
||||
inherit system;
|
||||
config.permittedInsecurePackages = [
|
||||
"gitea-1.19.4"
|
||||
gitea =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.gitea.enable = true;
|
||||
services.gitea.settings.service.DISABLE_REGISTRATION = true;
|
||||
services.gitea.settings.log.LEVEL = "Info";
|
||||
services.gitea.settings.database.LOG_SQL = false;
|
||||
services.openssh.enable = true;
|
||||
networking.firewall.allowedTCPPorts = [ 3000 ];
|
||||
environment.systemPackages = [
|
||||
pkgs.git
|
||||
pkgs.gitea
|
||||
];
|
||||
});
|
||||
};
|
||||
client = { pkgs, ... }: {
|
||||
environment.systemPackages = [ pkgs.git ];
|
||||
};
|
||||
};
|
||||
defaults = { pkgs, ... }: {
|
||||
environment.systemPackages = [ pkgs.jq ];
|
||||
|
||||
users.users.root.openssh.authorizedKeys.keys = [ clientPublicKey ];
|
||||
|
||||
# TODO: remove this after updating to nixos-23.11
|
||||
nixpkgs.pkgs = lib.mkForce (
|
||||
import nixpkgs {
|
||||
inherit system;
|
||||
config.permittedInsecurePackages = [
|
||||
"gitea-1.19.4"
|
||||
];
|
||||
}
|
||||
);
|
||||
};
|
||||
client =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = [ pkgs.git ];
|
||||
};
|
||||
};
|
||||
defaults =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = [ pkgs.jq ];
|
||||
};
|
||||
|
||||
setupScript = ''
|
||||
import shlex
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
{ lib, config, extendModules, ... }:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
extendModules,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
|
||||
indent = lib.replaceStrings ["\n"] ["\n "];
|
||||
indent = lib.replaceStrings [ "\n" ] [ "\n " ];
|
||||
|
||||
execTestCase = testCase: ''
|
||||
|
||||
|
@ -35,37 +40,39 @@ in
|
|||
description = ''
|
||||
The test cases. See `testScript`.
|
||||
'';
|
||||
type = types.listOf (types.submodule {
|
||||
options.name = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
The name of the test case.
|
||||
type = types.listOf (
|
||||
types.submodule {
|
||||
options.name = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
The name of the test case.
|
||||
|
||||
A repository with that name will be set up on the gitea server and locally.
|
||||
'';
|
||||
};
|
||||
options.description = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
A description of the test case.
|
||||
'';
|
||||
};
|
||||
options.setupScript = mkOption {
|
||||
type = types.lines;
|
||||
description = ''
|
||||
Python code that runs before the test case.
|
||||
'';
|
||||
default = "";
|
||||
};
|
||||
options.script = mkOption {
|
||||
type = types.lines;
|
||||
description = ''
|
||||
Python code that runs the test.
|
||||
A repository with that name will be set up on the gitea server and locally.
|
||||
'';
|
||||
};
|
||||
options.description = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
A description of the test case.
|
||||
'';
|
||||
};
|
||||
options.setupScript = mkOption {
|
||||
type = types.lines;
|
||||
description = ''
|
||||
Python code that runs before the test case.
|
||||
'';
|
||||
default = "";
|
||||
};
|
||||
options.script = mkOption {
|
||||
type = types.lines;
|
||||
description = ''
|
||||
Python code that runs the test.
|
||||
|
||||
Variables defined by the global `setupScript`, as well as `testCases.*.setupScript` will be available here.
|
||||
'';
|
||||
};
|
||||
});
|
||||
Variables defined by the global `setupScript`, as well as `testCases.*.setupScript` will be available here.
|
||||
'';
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -74,10 +81,12 @@ in
|
|||
environment.variables = {
|
||||
_NIX_FORCE_HTTP = "1";
|
||||
};
|
||||
nix.settings.experimental-features = ["nix-command" "flakes"];
|
||||
nix.settings.experimental-features = [
|
||||
"nix-command"
|
||||
"flakes"
|
||||
];
|
||||
};
|
||||
setupScript = ''
|
||||
'';
|
||||
setupScript = '''';
|
||||
testScript = ''
|
||||
start_all();
|
||||
|
||||
|
|
|
@ -5,16 +5,20 @@
|
|||
|
||||
let
|
||||
|
||||
makeTlsCert = name: pkgs.runCommand name {
|
||||
nativeBuildInputs = with pkgs; [ openssl ];
|
||||
} ''
|
||||
mkdir -p $out
|
||||
openssl req -x509 \
|
||||
-subj '/CN=${name}/' -days 49710 \
|
||||
-addext 'subjectAltName = DNS:${name}' \
|
||||
-keyout "$out/key.pem" -newkey ed25519 \
|
||||
-out "$out/cert.pem" -noenc
|
||||
'';
|
||||
makeTlsCert =
|
||||
name:
|
||||
pkgs.runCommand name
|
||||
{
|
||||
nativeBuildInputs = with pkgs; [ openssl ];
|
||||
}
|
||||
''
|
||||
mkdir -p $out
|
||||
openssl req -x509 \
|
||||
-subj '/CN=${name}/' -days 49710 \
|
||||
-addext 'subjectAltName = DNS:${name}' \
|
||||
-keyout "$out/key.pem" -newkey ed25519 \
|
||||
-out "$out/cert.pem" -noenc
|
||||
'';
|
||||
|
||||
goodCert = makeTlsCert "good";
|
||||
badCert = makeTlsCert "bad";
|
||||
|
@ -25,39 +29,44 @@ in
|
|||
name = "fetchurl";
|
||||
|
||||
nodes = {
|
||||
machine = { pkgs, ... }: {
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
|
||||
virtualHosts."good" = {
|
||||
addSSL = true;
|
||||
sslCertificate = "${goodCert}/cert.pem";
|
||||
sslCertificateKey = "${goodCert}/key.pem";
|
||||
root = pkgs.runCommand "nginx-root" {} ''
|
||||
mkdir "$out"
|
||||
echo 'hello world' > "$out/index.html"
|
||||
'';
|
||||
virtualHosts."good" = {
|
||||
addSSL = true;
|
||||
sslCertificate = "${goodCert}/cert.pem";
|
||||
sslCertificateKey = "${goodCert}/key.pem";
|
||||
root = pkgs.runCommand "nginx-root" { } ''
|
||||
mkdir "$out"
|
||||
echo 'hello world' > "$out/index.html"
|
||||
'';
|
||||
};
|
||||
|
||||
virtualHosts."bad" = {
|
||||
addSSL = true;
|
||||
sslCertificate = "${badCert}/cert.pem";
|
||||
sslCertificateKey = "${badCert}/key.pem";
|
||||
root = pkgs.runCommand "nginx-root" { } ''
|
||||
mkdir "$out"
|
||||
echo 'foobar' > "$out/index.html"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
virtualHosts."bad" = {
|
||||
addSSL = true;
|
||||
sslCertificate = "${badCert}/cert.pem";
|
||||
sslCertificateKey = "${badCert}/key.pem";
|
||||
root = pkgs.runCommand "nginx-root" {} ''
|
||||
mkdir "$out"
|
||||
echo 'foobar' > "$out/index.html"
|
||||
'';
|
||||
};
|
||||
security.pki.certificateFiles = [ "${goodCert}/cert.pem" ];
|
||||
|
||||
networking.hosts."127.0.0.1" = [
|
||||
"good"
|
||||
"bad"
|
||||
];
|
||||
|
||||
virtualisation.writableStore = true;
|
||||
|
||||
nix.settings.experimental-features = "nix-command";
|
||||
};
|
||||
|
||||
security.pki.certificateFiles = [ "${goodCert}/cert.pem" ];
|
||||
|
||||
networking.hosts."127.0.0.1" = [ "good" "bad" ];
|
||||
|
||||
virtualisation.writableStore = true;
|
||||
|
||||
nix.settings.experimental-features = "nix-command";
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
{ lib, config, nixpkgs, pkgs, ... }:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
nixpkgs,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
pkg1 = pkgs.go;
|
||||
|
@ -8,32 +14,44 @@ in
|
|||
name = "fsync";
|
||||
|
||||
nodes.machine =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ virtualisation.emptyDiskImages = [ 1024 ];
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
virtualisation.emptyDiskImages = [ 1024 ];
|
||||
environment.systemPackages = [ pkg1 ];
|
||||
nix.settings.experimental-features = [ "nix-command" ];
|
||||
nix.settings.fsync-store-paths = true;
|
||||
nix.settings.require-sigs = false;
|
||||
boot.supportedFilesystems = [ "ext4" "btrfs" "xfs" ];
|
||||
boot.supportedFilesystems = [
|
||||
"ext4"
|
||||
"btrfs"
|
||||
"xfs"
|
||||
];
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
# fmt: off
|
||||
for fs in ("ext4", "btrfs", "xfs"):
|
||||
machine.succeed("mkfs.{} {} /dev/vdb".format(fs, "-F" if fs == "ext4" else "-f"))
|
||||
machine.succeed("mkdir -p /mnt")
|
||||
machine.succeed("mount /dev/vdb /mnt")
|
||||
machine.succeed("sync")
|
||||
machine.succeed("nix copy --offline ${pkg1} --to /mnt")
|
||||
machine.crash()
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
# fmt: off
|
||||
for fs in ("ext4", "btrfs", "xfs"):
|
||||
machine.succeed("mkfs.{} {} /dev/vdb".format(fs, "-F" if fs == "ext4" else "-f"))
|
||||
machine.succeed("mkdir -p /mnt")
|
||||
machine.succeed("mount /dev/vdb /mnt")
|
||||
machine.succeed("sync")
|
||||
machine.succeed("nix copy --offline ${pkg1} --to /mnt")
|
||||
machine.crash()
|
||||
|
||||
machine.start()
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
machine.succeed("mkdir -p /mnt")
|
||||
machine.succeed("mount /dev/vdb /mnt")
|
||||
machine.succeed("nix path-info --offline --store /mnt ${pkg1}")
|
||||
machine.succeed("nix store verify --all --store /mnt --no-trust")
|
||||
machine.start()
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
machine.succeed("mkdir -p /mnt")
|
||||
machine.succeed("mount /dev/vdb /mnt")
|
||||
machine.succeed("nix path-info --offline --store /mnt ${pkg1}")
|
||||
machine.succeed("nix store verify --all --store /mnt --no-trust")
|
||||
|
||||
machine.succeed("umount /dev/vdb")
|
||||
'';
|
||||
machine.succeed("umount /dev/vdb")
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
imports = [ ./common.nix ];
|
||||
|
||||
nodes.machine = {
|
||||
users.users.alice = { isNormalUser = true; };
|
||||
users.users.alice = {
|
||||
isNormalUser = true;
|
||||
};
|
||||
nix.settings.trusted-users = [ "alice" ];
|
||||
};
|
||||
|
||||
|
@ -15,4 +17,4 @@
|
|||
su --login --command "run-test-suite" alice >&2
|
||||
""")
|
||||
'';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
imports = [ ./common.nix ];
|
||||
|
||||
nodes.machine = {
|
||||
users.users.alice = { isNormalUser = true; };
|
||||
users.users.alice = {
|
||||
isNormalUser = true;
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
|
||||
let
|
||||
# FIXME (roberth) reference issue
|
||||
inputDerivation = pkg: (pkg.overrideAttrs (o: {
|
||||
disallowedReferences = [ ];
|
||||
})).inputDerivation;
|
||||
inputDerivation =
|
||||
pkg:
|
||||
(pkg.overrideAttrs (o: {
|
||||
disallowedReferences = [ ];
|
||||
})).inputDerivation;
|
||||
|
||||
in
|
||||
{
|
||||
|
@ -12,59 +14,63 @@ in
|
|||
# we skip it to save time.
|
||||
skipTypeCheck = true;
|
||||
|
||||
nodes.machine = { config, pkgs, ... }: {
|
||||
nodes.machine =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
|
||||
virtualisation.writableStore = true;
|
||||
system.extraDependencies = [
|
||||
(inputDerivation config.nix.package)
|
||||
];
|
||||
virtualisation.writableStore = true;
|
||||
system.extraDependencies = [
|
||||
(inputDerivation config.nix.package)
|
||||
];
|
||||
|
||||
nix.settings.substituters = lib.mkForce [];
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
|
||||
environment.systemPackages = let
|
||||
run-test-suite = pkgs.writeShellApplication {
|
||||
name = "run-test-suite";
|
||||
runtimeInputs = [
|
||||
pkgs.meson
|
||||
pkgs.ninja
|
||||
pkgs.jq
|
||||
environment.systemPackages =
|
||||
let
|
||||
run-test-suite = pkgs.writeShellApplication {
|
||||
name = "run-test-suite";
|
||||
runtimeInputs = [
|
||||
pkgs.meson
|
||||
pkgs.ninja
|
||||
pkgs.jq
|
||||
pkgs.git
|
||||
|
||||
# Want to avoid `/run/current-system/sw/bin/bash` because we
|
||||
# want a store path. Likewise for coreutils.
|
||||
pkgs.bash
|
||||
pkgs.coreutils
|
||||
];
|
||||
text = ''
|
||||
set -x
|
||||
|
||||
cat /proc/sys/fs/file-max
|
||||
ulimit -Hn
|
||||
ulimit -Sn
|
||||
|
||||
cd ~
|
||||
|
||||
cp -r ${pkgs.nixComponents.nix-functional-tests.src} nix
|
||||
chmod -R +w nix
|
||||
|
||||
chmod u+w nix/.version
|
||||
echo ${pkgs.nixComponents.version} > nix/.version
|
||||
|
||||
export isTestOnNixOS=1
|
||||
|
||||
export NIX_REMOTE_=daemon
|
||||
export NIX_REMOTE=daemon
|
||||
|
||||
export NIX_STORE=${builtins.storeDir}
|
||||
|
||||
meson setup nix/tests/functional build
|
||||
cd build
|
||||
meson test -j1 --print-errorlogs
|
||||
'';
|
||||
};
|
||||
in
|
||||
[
|
||||
run-test-suite
|
||||
pkgs.git
|
||||
|
||||
# Want to avoid `/run/current-system/sw/bin/bash` because we
|
||||
# want a store path. Likewise for coreutils.
|
||||
pkgs.bash
|
||||
pkgs.coreutils
|
||||
];
|
||||
text = ''
|
||||
set -x
|
||||
|
||||
cat /proc/sys/fs/file-max
|
||||
ulimit -Hn
|
||||
ulimit -Sn
|
||||
|
||||
cd ~
|
||||
|
||||
cp -r ${pkgs.nixComponents.nix-functional-tests.src} nix
|
||||
chmod -R +w nix
|
||||
|
||||
chmod u+w nix/.version
|
||||
echo ${pkgs.nixComponents.version} > nix/.version
|
||||
|
||||
export isTestOnNixOS=1
|
||||
|
||||
export NIX_REMOTE_=daemon
|
||||
export NIX_REMOTE=daemon
|
||||
|
||||
export NIX_STORE=${builtins.storeDir}
|
||||
|
||||
meson setup nix/tests/functional build
|
||||
cd build
|
||||
meson test -j1 --print-errorlogs
|
||||
'';
|
||||
};
|
||||
in [
|
||||
run-test-suite
|
||||
pkgs.git
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
imports = [ ./common.nix ];
|
||||
|
||||
nodes.machine = {
|
||||
users.users.alice = { isNormalUser = true; };
|
||||
users.users.alice = {
|
||||
isNormalUser = true;
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
|
|
|
@ -6,68 +6,74 @@
|
|||
config = {
|
||||
name = lib.mkDefault "git-submodules";
|
||||
|
||||
nodes =
|
||||
{
|
||||
remote =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
services.openssh.enable = true;
|
||||
environment.systemPackages = [ pkgs.git ];
|
||||
};
|
||||
nodes = {
|
||||
remote =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
services.openssh.enable = true;
|
||||
environment.systemPackages = [ pkgs.git ];
|
||||
};
|
||||
|
||||
client =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
programs.ssh.extraConfig = "ConnectTimeout 30";
|
||||
environment.systemPackages = [ pkgs.git ];
|
||||
nix.extraOptions = "experimental-features = nix-command flakes";
|
||||
};
|
||||
};
|
||||
client =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
programs.ssh.extraConfig = "ConnectTimeout 30";
|
||||
environment.systemPackages = [ pkgs.git ];
|
||||
nix.extraOptions = "experimental-features = nix-command flakes";
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
# fmt: off
|
||||
import subprocess
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
# fmt: off
|
||||
import subprocess
|
||||
|
||||
start_all()
|
||||
start_all()
|
||||
|
||||
# Create an SSH key on the client.
|
||||
subprocess.run([
|
||||
"${hostPkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
|
||||
], capture_output=True, check=True)
|
||||
client.succeed("mkdir -p -m 700 /root/.ssh")
|
||||
client.copy_from_host("key", "/root/.ssh/id_ed25519")
|
||||
client.succeed("chmod 600 /root/.ssh/id_ed25519")
|
||||
# Create an SSH key on the client.
|
||||
subprocess.run([
|
||||
"${hostPkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
|
||||
], capture_output=True, check=True)
|
||||
client.succeed("mkdir -p -m 700 /root/.ssh")
|
||||
client.copy_from_host("key", "/root/.ssh/id_ed25519")
|
||||
client.succeed("chmod 600 /root/.ssh/id_ed25519")
|
||||
|
||||
# Install the SSH key on the builders.
|
||||
client.wait_for_unit("network-online.target")
|
||||
# Install the SSH key on the builders.
|
||||
client.wait_for_unit("network-online.target")
|
||||
|
||||
remote.succeed("mkdir -p -m 700 /root/.ssh")
|
||||
remote.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
|
||||
remote.wait_for_unit("sshd")
|
||||
remote.wait_for_unit("multi-user.target")
|
||||
remote.wait_for_unit("network-online.target")
|
||||
client.wait_for_unit("network-online.target")
|
||||
client.succeed(f"ssh -o StrictHostKeyChecking=no {remote.name} 'echo hello world'")
|
||||
remote.succeed("mkdir -p -m 700 /root/.ssh")
|
||||
remote.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
|
||||
remote.wait_for_unit("sshd")
|
||||
remote.wait_for_unit("multi-user.target")
|
||||
remote.wait_for_unit("network-online.target")
|
||||
client.wait_for_unit("network-online.target")
|
||||
client.succeed(f"ssh -o StrictHostKeyChecking=no {remote.name} 'echo hello world'")
|
||||
|
||||
remote.succeed("""
|
||||
git init bar
|
||||
git -C bar config user.email foobar@example.com
|
||||
git -C bar config user.name Foobar
|
||||
echo test >> bar/content
|
||||
git -C bar add content
|
||||
git -C bar commit -m 'Initial commit'
|
||||
""")
|
||||
remote.succeed("""
|
||||
git init bar
|
||||
git -C bar config user.email foobar@example.com
|
||||
git -C bar config user.name Foobar
|
||||
echo test >> bar/content
|
||||
git -C bar add content
|
||||
git -C bar commit -m 'Initial commit'
|
||||
""")
|
||||
|
||||
client.succeed(f"""
|
||||
git init foo
|
||||
git -C foo config user.email foobar@example.com
|
||||
git -C foo config user.name Foobar
|
||||
git -C foo submodule add root@{remote.name}:/tmp/bar sub
|
||||
git -C foo add sub
|
||||
git -C foo commit -m 'Add submodule'
|
||||
""")
|
||||
client.succeed(f"""
|
||||
git init foo
|
||||
git -C foo config user.email foobar@example.com
|
||||
git -C foo config user.name Foobar
|
||||
git -C foo submodule add root@{remote.name}:/tmp/bar sub
|
||||
git -C foo add sub
|
||||
git -C foo commit -m 'Add submodule'
|
||||
""")
|
||||
|
||||
client.succeed("nix --flake-registry \"\" flake prefetch 'git+file:///tmp/foo?submodules=1&ref=master'")
|
||||
'';
|
||||
client.succeed("nix --flake-registry \"\" flake prefetch 'git+file:///tmp/foo?submodules=1&ref=master'")
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,21 +1,25 @@
|
|||
{ lib, config, nixpkgs, ... }:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
nixpkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
pkgs = config.nodes.client.nixpkgs.pkgs;
|
||||
|
||||
# Generate a fake root CA and a fake api.github.com / github.com / channels.nixos.org certificate.
|
||||
cert = pkgs.runCommand "cert" { nativeBuildInputs = [ pkgs.openssl ]; }
|
||||
''
|
||||
mkdir -p $out
|
||||
cert = pkgs.runCommand "cert" { nativeBuildInputs = [ pkgs.openssl ]; } ''
|
||||
mkdir -p $out
|
||||
|
||||
openssl genrsa -out ca.key 2048
|
||||
openssl req -new -x509 -days 36500 -key ca.key \
|
||||
-subj "/C=NL/ST=Denial/L=Springfield/O=Dis/CN=Root CA" -out $out/ca.crt
|
||||
openssl genrsa -out ca.key 2048
|
||||
openssl req -new -x509 -days 36500 -key ca.key \
|
||||
-subj "/C=NL/ST=Denial/L=Springfield/O=Dis/CN=Root CA" -out $out/ca.crt
|
||||
|
||||
openssl req -newkey rsa:2048 -nodes -keyout $out/server.key \
|
||||
-subj "/C=CN/ST=Denial/L=Springfield/O=Dis/CN=github.com" -out server.csr
|
||||
openssl x509 -req -extfile <(printf "subjectAltName=DNS:api.github.com,DNS:github.com,DNS:channels.nixos.org") \
|
||||
-days 36500 -in server.csr -CA $out/ca.crt -CAkey ca.key -CAcreateserial -out $out/server.crt
|
||||
'';
|
||||
openssl req -newkey rsa:2048 -nodes -keyout $out/server.key \
|
||||
-subj "/C=CN/ST=Denial/L=Springfield/O=Dis/CN=github.com" -out server.csr
|
||||
openssl x509 -req -extfile <(printf "subjectAltName=DNS:api.github.com,DNS:github.com,DNS:channels.nixos.org") \
|
||||
-days 36500 -in server.csr -CA $out/ca.crt -CAkey ca.key -CAcreateserial -out $out/server.crt
|
||||
'';
|
||||
|
||||
registry = pkgs.writeTextFile {
|
||||
name = "registry";
|
||||
|
@ -53,168 +57,190 @@ let
|
|||
|
||||
private-flake-rev = "9f1dd0df5b54a7dc75b618034482ed42ce34383d";
|
||||
|
||||
private-flake-api = pkgs.runCommand "private-flake" {}
|
||||
''
|
||||
mkdir -p $out/{commits,tarball}
|
||||
private-flake-api = pkgs.runCommand "private-flake" { } ''
|
||||
mkdir -p $out/{commits,tarball}
|
||||
|
||||
# Setup https://docs.github.com/en/rest/commits/commits#get-a-commit
|
||||
echo '{"sha": "${private-flake-rev}", "commit": {"tree": {"sha": "ffffffffffffffffffffffffffffffffffffffff"}}}' > $out/commits/HEAD
|
||||
# Setup https://docs.github.com/en/rest/commits/commits#get-a-commit
|
||||
echo '{"sha": "${private-flake-rev}", "commit": {"tree": {"sha": "ffffffffffffffffffffffffffffffffffffffff"}}}' > $out/commits/HEAD
|
||||
|
||||
# Setup tarball download via API
|
||||
dir=private-flake
|
||||
mkdir $dir
|
||||
echo '{ outputs = {...}: {}; }' > $dir/flake.nix
|
||||
tar cfz $out/tarball/${private-flake-rev} $dir --hard-dereference
|
||||
'';
|
||||
# Setup tarball download via API
|
||||
dir=private-flake
|
||||
mkdir $dir
|
||||
echo '{ outputs = {...}: {}; }' > $dir/flake.nix
|
||||
tar cfz $out/tarball/${private-flake-rev} $dir --hard-dereference
|
||||
'';
|
||||
|
||||
nixpkgs-api = pkgs.runCommand "nixpkgs-flake" {}
|
||||
''
|
||||
mkdir -p $out/commits
|
||||
nixpkgs-api = pkgs.runCommand "nixpkgs-flake" { } ''
|
||||
mkdir -p $out/commits
|
||||
|
||||
# Setup https://docs.github.com/en/rest/commits/commits#get-a-commit
|
||||
echo '{"sha": "${nixpkgs.rev}", "commit": {"tree": {"sha": "ffffffffffffffffffffffffffffffffffffffff"}}}' > $out/commits/HEAD
|
||||
'';
|
||||
# Setup https://docs.github.com/en/rest/commits/commits#get-a-commit
|
||||
echo '{"sha": "${nixpkgs.rev}", "commit": {"tree": {"sha": "ffffffffffffffffffffffffffffffffffffffff"}}}' > $out/commits/HEAD
|
||||
'';
|
||||
|
||||
archive = pkgs.runCommand "nixpkgs-flake" {}
|
||||
''
|
||||
mkdir -p $out/archive
|
||||
archive = pkgs.runCommand "nixpkgs-flake" { } ''
|
||||
mkdir -p $out/archive
|
||||
|
||||
dir=NixOS-nixpkgs-${nixpkgs.shortRev}
|
||||
cp -prd ${nixpkgs} $dir
|
||||
# Set the correct timestamp in the tarball.
|
||||
find $dir -print0 | xargs -0 touch -h -t ${builtins.substring 0 12 nixpkgs.lastModifiedDate}.${builtins.substring 12 2 nixpkgs.lastModifiedDate} --
|
||||
tar cfz $out/archive/${nixpkgs.rev}.tar.gz $dir --hard-dereference
|
||||
'';
|
||||
dir=NixOS-nixpkgs-${nixpkgs.shortRev}
|
||||
cp -prd ${nixpkgs} $dir
|
||||
# Set the correct timestamp in the tarball.
|
||||
find $dir -print0 | xargs -0 touch -h -t ${builtins.substring 0 12 nixpkgs.lastModifiedDate}.${
|
||||
builtins.substring 12 2 nixpkgs.lastModifiedDate
|
||||
} --
|
||||
tar cfz $out/archive/${nixpkgs.rev}.tar.gz $dir --hard-dereference
|
||||
'';
|
||||
in
|
||||
|
||||
{
|
||||
name = "github-flakes";
|
||||
|
||||
nodes =
|
||||
{
|
||||
github =
|
||||
{ config, pkgs, ... }:
|
||||
{ networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
nodes = {
|
||||
github =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
80
|
||||
443
|
||||
];
|
||||
|
||||
services.httpd.enable = true;
|
||||
services.httpd.adminAddr = "foo@example.org";
|
||||
services.httpd.extraConfig = ''
|
||||
ErrorLog syslog:local6
|
||||
'';
|
||||
services.httpd.virtualHosts."channels.nixos.org" =
|
||||
{ forceSSL = true;
|
||||
sslServerKey = "${cert}/server.key";
|
||||
sslServerCert = "${cert}/server.crt";
|
||||
servedDirs =
|
||||
[ { urlPath = "/";
|
||||
dir = registry;
|
||||
}
|
||||
];
|
||||
};
|
||||
services.httpd.virtualHosts."api.github.com" =
|
||||
{ forceSSL = true;
|
||||
sslServerKey = "${cert}/server.key";
|
||||
sslServerCert = "${cert}/server.crt";
|
||||
servedDirs =
|
||||
[ { urlPath = "/repos/NixOS/nixpkgs";
|
||||
dir = nixpkgs-api;
|
||||
}
|
||||
{ urlPath = "/repos/fancy-enterprise/private-flake";
|
||||
dir = private-flake-api;
|
||||
}
|
||||
];
|
||||
};
|
||||
services.httpd.virtualHosts."github.com" =
|
||||
{ forceSSL = true;
|
||||
sslServerKey = "${cert}/server.key";
|
||||
sslServerCert = "${cert}/server.crt";
|
||||
servedDirs =
|
||||
[ { urlPath = "/NixOS/nixpkgs";
|
||||
dir = archive;
|
||||
}
|
||||
];
|
||||
};
|
||||
services.httpd.enable = true;
|
||||
services.httpd.adminAddr = "foo@example.org";
|
||||
services.httpd.extraConfig = ''
|
||||
ErrorLog syslog:local6
|
||||
'';
|
||||
services.httpd.virtualHosts."channels.nixos.org" = {
|
||||
forceSSL = true;
|
||||
sslServerKey = "${cert}/server.key";
|
||||
sslServerCert = "${cert}/server.crt";
|
||||
servedDirs = [
|
||||
{
|
||||
urlPath = "/";
|
||||
dir = registry;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
client =
|
||||
{ config, lib, pkgs, nodes, ... }:
|
||||
{ virtualisation.writableStore = true;
|
||||
virtualisation.diskSize = 2048;
|
||||
virtualisation.additionalPaths = [ pkgs.hello pkgs.fuse ];
|
||||
virtualisation.memorySize = 4096;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
nix.extraOptions = "experimental-features = nix-command flakes";
|
||||
networking.hosts.${(builtins.head nodes.github.networking.interfaces.eth1.ipv4.addresses).address} =
|
||||
[ "channels.nixos.org" "api.github.com" "github.com" ];
|
||||
security.pki.certificateFiles = [ "${cert}/ca.crt" ];
|
||||
services.httpd.virtualHosts."api.github.com" = {
|
||||
forceSSL = true;
|
||||
sslServerKey = "${cert}/server.key";
|
||||
sslServerCert = "${cert}/server.crt";
|
||||
servedDirs = [
|
||||
{
|
||||
urlPath = "/repos/NixOS/nixpkgs";
|
||||
dir = nixpkgs-api;
|
||||
}
|
||||
{
|
||||
urlPath = "/repos/fancy-enterprise/private-flake";
|
||||
dir = private-flake-api;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
services.httpd.virtualHosts."github.com" = {
|
||||
forceSSL = true;
|
||||
sslServerKey = "${cert}/server.key";
|
||||
sslServerCert = "${cert}/server.crt";
|
||||
servedDirs = [
|
||||
{
|
||||
urlPath = "/NixOS/nixpkgs";
|
||||
dir = archive;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
# fmt: off
|
||||
import json
|
||||
import time
|
||||
client =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
nodes,
|
||||
...
|
||||
}:
|
||||
{
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.diskSize = 2048;
|
||||
virtualisation.additionalPaths = [
|
||||
pkgs.hello
|
||||
pkgs.fuse
|
||||
];
|
||||
virtualisation.memorySize = 4096;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
nix.extraOptions = "experimental-features = nix-command flakes";
|
||||
networking.hosts.${(builtins.head nodes.github.networking.interfaces.eth1.ipv4.addresses).address} =
|
||||
[
|
||||
"channels.nixos.org"
|
||||
"api.github.com"
|
||||
"github.com"
|
||||
];
|
||||
security.pki.certificateFiles = [ "${cert}/ca.crt" ];
|
||||
};
|
||||
};
|
||||
|
||||
start_all()
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
# fmt: off
|
||||
import json
|
||||
import time
|
||||
|
||||
def cat_log():
|
||||
github.succeed("cat /var/log/httpd/*.log >&2")
|
||||
start_all()
|
||||
|
||||
github.wait_for_unit("httpd.service")
|
||||
github.wait_for_unit("network-online.target")
|
||||
def cat_log():
|
||||
github.succeed("cat /var/log/httpd/*.log >&2")
|
||||
|
||||
client.wait_for_unit("network-online.target")
|
||||
client.succeed("curl -v https://github.com/ >&2")
|
||||
out = client.succeed("nix registry list")
|
||||
print(out)
|
||||
assert "github:NixOS/nixpkgs" in out, "nixpkgs flake not found"
|
||||
assert "github:fancy-enterprise/private-flake" in out, "private flake not found"
|
||||
cat_log()
|
||||
github.wait_for_unit("httpd.service")
|
||||
github.wait_for_unit("network-online.target")
|
||||
|
||||
# If no github access token is provided, nix should use the public archive url...
|
||||
out = client.succeed("nix flake metadata nixpkgs --json")
|
||||
print(out)
|
||||
info = json.loads(out)
|
||||
assert info["revision"] == "${nixpkgs.rev}", f"revision mismatch: {info['revision']} != ${nixpkgs.rev}"
|
||||
cat_log()
|
||||
client.wait_for_unit("network-online.target")
|
||||
client.succeed("curl -v https://github.com/ >&2")
|
||||
out = client.succeed("nix registry list")
|
||||
print(out)
|
||||
assert "github:NixOS/nixpkgs" in out, "nixpkgs flake not found"
|
||||
assert "github:fancy-enterprise/private-flake" in out, "private flake not found"
|
||||
cat_log()
|
||||
|
||||
# ... otherwise it should use the API
|
||||
out = client.succeed("nix flake metadata private-flake --json --access-tokens github.com=ghp_000000000000000000000000000000000000 --tarball-ttl 0")
|
||||
print(out)
|
||||
info = json.loads(out)
|
||||
assert info["revision"] == "${private-flake-rev}", f"revision mismatch: {info['revision']} != ${private-flake-rev}"
|
||||
assert info["fingerprint"]
|
||||
cat_log()
|
||||
# If no github access token is provided, nix should use the public archive url...
|
||||
out = client.succeed("nix flake metadata nixpkgs --json")
|
||||
print(out)
|
||||
info = json.loads(out)
|
||||
assert info["revision"] == "${nixpkgs.rev}", f"revision mismatch: {info['revision']} != ${nixpkgs.rev}"
|
||||
cat_log()
|
||||
|
||||
# Fetching with the resolved URL should produce the same result.
|
||||
info2 = json.loads(client.succeed(f"nix flake metadata {info['url']} --json --access-tokens github.com=ghp_000000000000000000000000000000000000 --tarball-ttl 0"))
|
||||
print(info["fingerprint"], info2["fingerprint"])
|
||||
assert info["fingerprint"] == info2["fingerprint"], "fingerprint mismatch"
|
||||
# ... otherwise it should use the API
|
||||
out = client.succeed("nix flake metadata private-flake --json --access-tokens github.com=ghp_000000000000000000000000000000000000 --tarball-ttl 0")
|
||||
print(out)
|
||||
info = json.loads(out)
|
||||
assert info["revision"] == "${private-flake-rev}", f"revision mismatch: {info['revision']} != ${private-flake-rev}"
|
||||
assert info["fingerprint"]
|
||||
cat_log()
|
||||
|
||||
client.succeed("nix registry pin nixpkgs")
|
||||
client.succeed("nix flake metadata nixpkgs --tarball-ttl 0 >&2")
|
||||
# Fetching with the resolved URL should produce the same result.
|
||||
info2 = json.loads(client.succeed(f"nix flake metadata {info['url']} --json --access-tokens github.com=ghp_000000000000000000000000000000000000 --tarball-ttl 0"))
|
||||
print(info["fingerprint"], info2["fingerprint"])
|
||||
assert info["fingerprint"] == info2["fingerprint"], "fingerprint mismatch"
|
||||
|
||||
# Test fetchTree on a github URL.
|
||||
hash = client.succeed(f"nix eval --no-trust-tarballs-from-git-forges --raw --expr '(fetchTree {info['url']}).narHash'")
|
||||
assert hash == info['locked']['narHash']
|
||||
client.succeed("nix registry pin nixpkgs")
|
||||
client.succeed("nix flake metadata nixpkgs --tarball-ttl 0 >&2")
|
||||
|
||||
# Fetching without a narHash should succeed if trust-github is set and fail otherwise.
|
||||
client.succeed(f"nix eval --raw --expr 'builtins.fetchTree github:github:fancy-enterprise/private-flake/{info['revision']}'")
|
||||
out = client.fail(f"nix eval --no-trust-tarballs-from-git-forges --raw --expr 'builtins.fetchTree github:github:fancy-enterprise/private-flake/{info['revision']}' 2>&1")
|
||||
assert "will not fetch unlocked input" in out, "--no-trust-tarballs-from-git-forges did not fail with the expected error"
|
||||
# Test fetchTree on a github URL.
|
||||
hash = client.succeed(f"nix eval --no-trust-tarballs-from-git-forges --raw --expr '(fetchTree {info['url']}).narHash'")
|
||||
assert hash == info['locked']['narHash']
|
||||
|
||||
# Shut down the web server. The flake should be cached on the client.
|
||||
github.succeed("systemctl stop httpd.service")
|
||||
# Fetching without a narHash should succeed if trust-github is set and fail otherwise.
|
||||
client.succeed(f"nix eval --raw --expr 'builtins.fetchTree github:github:fancy-enterprise/private-flake/{info['revision']}'")
|
||||
out = client.fail(f"nix eval --no-trust-tarballs-from-git-forges --raw --expr 'builtins.fetchTree github:github:fancy-enterprise/private-flake/{info['revision']}' 2>&1")
|
||||
assert "will not fetch unlocked input" in out, "--no-trust-tarballs-from-git-forges did not fail with the expected error"
|
||||
|
||||
info = json.loads(client.succeed("nix flake metadata nixpkgs --json"))
|
||||
date = time.strftime("%Y%m%d%H%M%S", time.gmtime(info['lastModified']))
|
||||
assert date == "${nixpkgs.lastModifiedDate}", "time mismatch"
|
||||
# Shut down the web server. The flake should be cached on the client.
|
||||
github.succeed("systemctl stop httpd.service")
|
||||
|
||||
client.succeed("nix build nixpkgs#hello")
|
||||
info = json.loads(client.succeed("nix flake metadata nixpkgs --json"))
|
||||
date = time.strftime("%Y%m%d%H%M%S", time.gmtime(info['lastModified']))
|
||||
assert date == "${nixpkgs.lastModifiedDate}", "time mismatch"
|
||||
|
||||
# The build shouldn't fail even with --tarball-ttl 0 (the server
|
||||
# being down should not be a fatal error).
|
||||
client.succeed("nix build nixpkgs#fuse --tarball-ttl 0")
|
||||
'';
|
||||
client.succeed("nix build nixpkgs#hello")
|
||||
|
||||
# The build shouldn't fail even with --tarball-ttl 0 (the server
|
||||
# being down should not be a fatal error).
|
||||
client.succeed("nix build nixpkgs#fuse --tarball-ttl 0")
|
||||
'';
|
||||
|
||||
}
|
||||
|
|
|
@ -30,42 +30,45 @@ in
|
|||
{
|
||||
name = "gzip-content-encoding";
|
||||
|
||||
nodes =
|
||||
{ machine =
|
||||
nodes = {
|
||||
machine =
|
||||
{ config, pkgs, ... }:
|
||||
{ networking.firewall.allowedTCPPorts = [ 80 ];
|
||||
{
|
||||
networking.firewall.allowedTCPPorts = [ 80 ];
|
||||
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts."localhost" =
|
||||
{ root = "${ztdCompressedFile}/share/";
|
||||
# Make sure that nginx really tries to compress the
|
||||
# file on the fly with no regard to size/mime.
|
||||
# http://nginx.org/en/docs/http/ngx_http_gzip_module.html
|
||||
extraConfig = ''
|
||||
gzip on;
|
||||
gzip_types *;
|
||||
gzip_proxied any;
|
||||
gzip_min_length 0;
|
||||
'';
|
||||
};
|
||||
services.nginx.virtualHosts."localhost" = {
|
||||
root = "${ztdCompressedFile}/share/";
|
||||
# Make sure that nginx really tries to compress the
|
||||
# file on the fly with no regard to size/mime.
|
||||
# http://nginx.org/en/docs/http/ngx_http_gzip_module.html
|
||||
extraConfig = ''
|
||||
gzip on;
|
||||
gzip_types *;
|
||||
gzip_proxied any;
|
||||
gzip_min_length 0;
|
||||
'';
|
||||
};
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = with pkgs; [ file ];
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Check that when nix-prefetch-url is used with a zst tarball it does not get decompressed.
|
||||
testScript = { nodes }: ''
|
||||
# fmt: off
|
||||
start_all()
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
# fmt: off
|
||||
start_all()
|
||||
|
||||
machine.wait_for_unit("nginx.service")
|
||||
machine.succeed("""
|
||||
# Make sure that the file is properly compressed as the test would be meaningless otherwise
|
||||
curl --compressed -v http://localhost/archive |& tr -s ' ' |& grep --ignore-case 'content-encoding: gzip'
|
||||
archive_path=$(nix-prefetch-url http://localhost/archive --print-path | tail -n1)
|
||||
[[ $(${fileCmd} --brief --mime-type $archive_path) == "application/zstd" ]]
|
||||
tar --zstd -xf $archive_path
|
||||
""")
|
||||
'';
|
||||
machine.wait_for_unit("nginx.service")
|
||||
machine.succeed("""
|
||||
# Make sure that the file is properly compressed as the test would be meaningless otherwise
|
||||
curl --compressed -v http://localhost/archive |& tr -s ' ' |& grep --ignore-case 'content-encoding: gzip'
|
||||
archive_path=$(nix-prefetch-url http://localhost/archive --print-path | tail -n1)
|
||||
[[ $(${fileCmd} --brief --mime-type $archive_path) == "application/zstd" ]]
|
||||
tar --zstd -xf $archive_path
|
||||
""")
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
# Test ‘nix-copy-closure’.
|
||||
|
||||
{ lib, config, nixpkgs, ... }:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
nixpkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
pkgs = config.nodes.client.nixpkgs.pkgs;
|
||||
|
@ -10,74 +15,90 @@ let
|
|||
pkgC = pkgs.hello;
|
||||
pkgD = pkgs.tmux;
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
name = "nix-copy-closure";
|
||||
|
||||
nodes =
|
||||
{ client =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [ pkgA pkgD.drvPath ];
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
};
|
||||
nodes = {
|
||||
client =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [
|
||||
pkgA
|
||||
pkgD.drvPath
|
||||
];
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
};
|
||||
|
||||
server =
|
||||
{ config, pkgs, ... }:
|
||||
{ services.openssh.enable = true;
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [ pkgB pkgC ];
|
||||
};
|
||||
};
|
||||
server =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
services.openssh.enable = true;
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [
|
||||
pkgB
|
||||
pkgC
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
# fmt: off
|
||||
import subprocess
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
# fmt: off
|
||||
import subprocess
|
||||
|
||||
start_all()
|
||||
start_all()
|
||||
|
||||
# Create an SSH key on the client.
|
||||
subprocess.run([
|
||||
"${pkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
|
||||
], capture_output=True, check=True)
|
||||
# Create an SSH key on the client.
|
||||
subprocess.run([
|
||||
"${pkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
|
||||
], capture_output=True, check=True)
|
||||
|
||||
client.succeed("mkdir -m 700 /root/.ssh")
|
||||
client.copy_from_host("key", "/root/.ssh/id_ed25519")
|
||||
client.succeed("chmod 600 /root/.ssh/id_ed25519")
|
||||
client.succeed("mkdir -m 700 /root/.ssh")
|
||||
client.copy_from_host("key", "/root/.ssh/id_ed25519")
|
||||
client.succeed("chmod 600 /root/.ssh/id_ed25519")
|
||||
|
||||
# Install the SSH key on the server.
|
||||
server.succeed("mkdir -m 700 /root/.ssh")
|
||||
server.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
|
||||
server.wait_for_unit("sshd")
|
||||
server.wait_for_unit("multi-user.target")
|
||||
server.wait_for_unit("network-online.target")
|
||||
# Install the SSH key on the server.
|
||||
server.succeed("mkdir -m 700 /root/.ssh")
|
||||
server.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
|
||||
server.wait_for_unit("sshd")
|
||||
server.wait_for_unit("multi-user.target")
|
||||
server.wait_for_unit("network-online.target")
|
||||
|
||||
client.wait_for_unit("network-online.target")
|
||||
client.succeed(f"ssh -o StrictHostKeyChecking=no {server.name} 'echo hello world'")
|
||||
client.wait_for_unit("network-online.target")
|
||||
client.succeed(f"ssh -o StrictHostKeyChecking=no {server.name} 'echo hello world'")
|
||||
|
||||
# Copy the closure of package A from the client to the server.
|
||||
server.fail("nix-store --check-validity ${pkgA}")
|
||||
client.succeed("nix-copy-closure --to server --gzip ${pkgA} >&2")
|
||||
server.succeed("nix-store --check-validity ${pkgA}")
|
||||
# Copy the closure of package A from the client to the server.
|
||||
server.fail("nix-store --check-validity ${pkgA}")
|
||||
client.succeed("nix-copy-closure --to server --gzip ${pkgA} >&2")
|
||||
server.succeed("nix-store --check-validity ${pkgA}")
|
||||
|
||||
# Copy the closure of package B from the server to the client.
|
||||
client.fail("nix-store --check-validity ${pkgB}")
|
||||
client.succeed("nix-copy-closure --from server --gzip ${pkgB} >&2")
|
||||
client.succeed("nix-store --check-validity ${pkgB}")
|
||||
# Copy the closure of package B from the server to the client.
|
||||
client.fail("nix-store --check-validity ${pkgB}")
|
||||
client.succeed("nix-copy-closure --from server --gzip ${pkgB} >&2")
|
||||
client.succeed("nix-store --check-validity ${pkgB}")
|
||||
|
||||
# Copy the closure of package C via the SSH substituter.
|
||||
client.fail("nix-store -r ${pkgC}")
|
||||
# Copy the closure of package C via the SSH substituter.
|
||||
client.fail("nix-store -r ${pkgC}")
|
||||
|
||||
# Copy the derivation of package D's derivation from the client to the server.
|
||||
server.fail("nix-store --check-validity ${pkgD.drvPath}")
|
||||
client.succeed("nix-copy-closure --to server --gzip ${pkgD.drvPath} >&2")
|
||||
server.succeed("nix-store --check-validity ${pkgD.drvPath}")
|
||||
# Copy the derivation of package D's derivation from the client to the server.
|
||||
server.fail("nix-store --check-validity ${pkgD.drvPath}")
|
||||
client.succeed("nix-copy-closure --to server --gzip ${pkgD.drvPath} >&2")
|
||||
server.succeed("nix-store --check-validity ${pkgD.drvPath}")
|
||||
|
||||
# FIXME
|
||||
# client.succeed(
|
||||
# "nix-store --option use-ssh-substituter true"
|
||||
# " --option ssh-substituter-hosts root\@server"
|
||||
# " -r ${pkgC} >&2"
|
||||
# )
|
||||
# client.succeed("nix-store --check-validity ${pkgC}")
|
||||
'';
|
||||
# FIXME
|
||||
# client.succeed(
|
||||
# "nix-store --option use-ssh-substituter true"
|
||||
# " --option ssh-substituter-hosts root\@server"
|
||||
# " -r ${pkgC} >&2"
|
||||
# )
|
||||
# client.succeed("nix-store --check-validity ${pkgC}")
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -2,7 +2,13 @@
|
|||
# Run interactively with:
|
||||
# rm key key.pub; nix run .#hydraJobs.tests.nix-copy.driverInteractive
|
||||
|
||||
{ lib, config, nixpkgs, hostPkgs, ... }:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
nixpkgs,
|
||||
hostPkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
pkgs = config.nodes.client.nixpkgs.pkgs;
|
||||
|
@ -12,101 +18,117 @@ let
|
|||
pkgC = pkgs.hello;
|
||||
pkgD = pkgs.tmux;
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
name = "nix-copy";
|
||||
|
||||
enableOCR = true;
|
||||
|
||||
nodes =
|
||||
{ client =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [ pkgA pkgD.drvPath ];
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
nix.settings.experimental-features = [ "nix-command" ];
|
||||
services.getty.autologinUser = "root";
|
||||
programs.ssh.extraConfig = ''
|
||||
Host *
|
||||
ControlMaster auto
|
||||
ControlPath ~/.ssh/master-%h:%r@%n:%p
|
||||
ControlPersist 15m
|
||||
'';
|
||||
};
|
||||
nodes = {
|
||||
client =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [
|
||||
pkgA
|
||||
pkgD.drvPath
|
||||
];
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
nix.settings.experimental-features = [ "nix-command" ];
|
||||
services.getty.autologinUser = "root";
|
||||
programs.ssh.extraConfig = ''
|
||||
Host *
|
||||
ControlMaster auto
|
||||
ControlPath ~/.ssh/master-%h:%r@%n:%p
|
||||
ControlPersist 15m
|
||||
'';
|
||||
};
|
||||
|
||||
server =
|
||||
{ config, pkgs, ... }:
|
||||
{ services.openssh.enable = true;
|
||||
services.openssh.settings.PermitRootLogin = "yes";
|
||||
users.users.root.hashedPasswordFile = null;
|
||||
users.users.root.password = "foobar";
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [ pkgB pkgC ];
|
||||
};
|
||||
};
|
||||
server =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
services.openssh.enable = true;
|
||||
services.openssh.settings.PermitRootLogin = "yes";
|
||||
users.users.root.hashedPasswordFile = null;
|
||||
users.users.root.password = "foobar";
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [
|
||||
pkgB
|
||||
pkgC
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
# fmt: off
|
||||
import subprocess
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
# fmt: off
|
||||
import subprocess
|
||||
|
||||
# Create an SSH key on the client.
|
||||
subprocess.run([
|
||||
"${pkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
|
||||
], capture_output=True, check=True)
|
||||
# Create an SSH key on the client.
|
||||
subprocess.run([
|
||||
"${pkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
|
||||
], capture_output=True, check=True)
|
||||
|
||||
start_all()
|
||||
start_all()
|
||||
|
||||
server.wait_for_unit("sshd")
|
||||
server.wait_for_unit("multi-user.target")
|
||||
server.wait_for_unit("network-online.target")
|
||||
server.wait_for_unit("sshd")
|
||||
server.wait_for_unit("multi-user.target")
|
||||
server.wait_for_unit("network-online.target")
|
||||
|
||||
client.wait_for_unit("network-online.target")
|
||||
client.wait_for_unit("getty@tty1.service")
|
||||
# Either the prompt: ]#
|
||||
# or an OCR misreading of it: 1#
|
||||
client.wait_for_text("[]1]#")
|
||||
client.wait_for_unit("network-online.target")
|
||||
client.wait_for_unit("getty@tty1.service")
|
||||
# Either the prompt: ]#
|
||||
# or an OCR misreading of it: 1#
|
||||
client.wait_for_text("[]1]#")
|
||||
|
||||
# Copy the closure of package A from the client to the server using password authentication,
|
||||
# and check that all prompts are visible
|
||||
server.fail("nix-store --check-validity ${pkgA}")
|
||||
client.send_chars("nix copy --to ssh://server ${pkgA} >&2; echo -n do; echo ne\n")
|
||||
client.wait_for_text("continue connecting")
|
||||
client.send_chars("yes\n")
|
||||
client.wait_for_text("Password:")
|
||||
client.send_chars("foobar\n")
|
||||
client.wait_for_text("done")
|
||||
server.succeed("nix-store --check-validity ${pkgA}")
|
||||
# Copy the closure of package A from the client to the server using password authentication,
|
||||
# and check that all prompts are visible
|
||||
server.fail("nix-store --check-validity ${pkgA}")
|
||||
client.send_chars("nix copy --to ssh://server ${pkgA} >&2; echo -n do; echo ne\n")
|
||||
client.wait_for_text("continue connecting")
|
||||
client.send_chars("yes\n")
|
||||
client.wait_for_text("Password:")
|
||||
client.send_chars("foobar\n")
|
||||
client.wait_for_text("done")
|
||||
server.succeed("nix-store --check-validity ${pkgA}")
|
||||
|
||||
# Check that ControlMaster is working
|
||||
client.send_chars("nix copy --to ssh://server ${pkgA} >&2; echo done\n")
|
||||
client.wait_for_text("done")
|
||||
# Check that ControlMaster is working
|
||||
client.send_chars("nix copy --to ssh://server ${pkgA} >&2; echo done\n")
|
||||
client.wait_for_text("done")
|
||||
|
||||
client.copy_from_host("key", "/root/.ssh/id_ed25519")
|
||||
client.succeed("chmod 600 /root/.ssh/id_ed25519")
|
||||
client.copy_from_host("key", "/root/.ssh/id_ed25519")
|
||||
client.succeed("chmod 600 /root/.ssh/id_ed25519")
|
||||
|
||||
# Install the SSH key on the server.
|
||||
server.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
|
||||
server.succeed("systemctl restart sshd")
|
||||
client.succeed(f"ssh -o StrictHostKeyChecking=no {server.name} 'echo hello world'")
|
||||
client.succeed(f"ssh -O check {server.name}")
|
||||
client.succeed(f"ssh -O exit {server.name}")
|
||||
client.fail(f"ssh -O check {server.name}")
|
||||
# Install the SSH key on the server.
|
||||
server.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
|
||||
server.succeed("systemctl restart sshd")
|
||||
client.succeed(f"ssh -o StrictHostKeyChecking=no {server.name} 'echo hello world'")
|
||||
client.succeed(f"ssh -O check {server.name}")
|
||||
client.succeed(f"ssh -O exit {server.name}")
|
||||
client.fail(f"ssh -O check {server.name}")
|
||||
|
||||
# Check that an explicit master will work
|
||||
client.succeed(f"ssh -MNfS /tmp/master {server.name}")
|
||||
client.succeed(f"ssh -S /tmp/master -O check {server.name}")
|
||||
client.succeed("NIX_SSHOPTS='-oControlPath=/tmp/master' nix copy --to ssh://server ${pkgA} >&2")
|
||||
client.succeed(f"ssh -S /tmp/master -O exit {server.name}")
|
||||
# Check that an explicit master will work
|
||||
client.succeed(f"ssh -MNfS /tmp/master {server.name}")
|
||||
client.succeed(f"ssh -S /tmp/master -O check {server.name}")
|
||||
client.succeed("NIX_SSHOPTS='-oControlPath=/tmp/master' nix copy --to ssh://server ${pkgA} >&2")
|
||||
client.succeed(f"ssh -S /tmp/master -O exit {server.name}")
|
||||
|
||||
# Copy the closure of package B from the server to the client, using ssh-ng.
|
||||
client.fail("nix-store --check-validity ${pkgB}")
|
||||
# Shouldn't download untrusted paths by default
|
||||
client.fail("nix copy --from ssh-ng://server ${pkgB} >&2")
|
||||
client.succeed("nix copy --no-check-sigs --from ssh-ng://server ${pkgB} >&2")
|
||||
client.succeed("nix-store --check-validity ${pkgB}")
|
||||
# Copy the closure of package B from the server to the client, using ssh-ng.
|
||||
client.fail("nix-store --check-validity ${pkgB}")
|
||||
# Shouldn't download untrusted paths by default
|
||||
client.fail("nix copy --from ssh-ng://server ${pkgB} >&2")
|
||||
client.succeed("nix copy --no-check-sigs --from ssh-ng://server ${pkgB} >&2")
|
||||
client.succeed("nix-store --check-validity ${pkgB}")
|
||||
|
||||
# Copy the derivation of package D's derivation from the client to the server.
|
||||
server.fail("nix-store --check-validity ${pkgD.drvPath}")
|
||||
client.succeed("nix copy --derivation --to ssh://server ${pkgD.drvPath} >&2")
|
||||
server.succeed("nix-store --check-validity ${pkgD.drvPath}")
|
||||
'';
|
||||
# Copy the derivation of package D's derivation from the client to the server.
|
||||
server.fail("nix-store --check-validity ${pkgD.drvPath}")
|
||||
client.succeed("nix copy --derivation --to ssh://server ${pkgD.drvPath} >&2")
|
||||
server.succeed("nix-store --check-validity ${pkgD.drvPath}")
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
# Test the container built by ../../docker.nix.
|
||||
|
||||
{ lib, config, nixpkgs, hostPkgs, ... }:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
nixpkgs,
|
||||
hostPkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
pkgs = config.nodes.machine.nixpkgs.pkgs;
|
||||
|
@ -19,36 +25,54 @@ let
|
|||
|
||||
containerTestScript = ./nix-docker-test.sh;
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
name = "nix-docker";
|
||||
|
||||
nodes =
|
||||
{ machine =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ virtualisation.diskSize = 4096;
|
||||
};
|
||||
cache =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ virtualisation.additionalPaths = [ pkgs.stdenv pkgs.hello ];
|
||||
services.harmonia.enable = true;
|
||||
networking.firewall.allowedTCPPorts = [ 5000 ];
|
||||
};
|
||||
};
|
||||
nodes = {
|
||||
machine =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
virtualisation.diskSize = 4096;
|
||||
};
|
||||
cache =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
virtualisation.additionalPaths = [
|
||||
pkgs.stdenv
|
||||
pkgs.hello
|
||||
];
|
||||
services.harmonia.enable = true;
|
||||
networking.firewall.allowedTCPPorts = [ 5000 ];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
cache.wait_for_unit("harmonia.service")
|
||||
cache.wait_for_unit("network-online.target")
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
cache.wait_for_unit("harmonia.service")
|
||||
cache.wait_for_unit("network-online.target")
|
||||
|
||||
machine.succeed("mkdir -p /etc/containers")
|
||||
machine.succeed("""echo '{"default":[{"type":"insecureAcceptAnything"}]}' > /etc/containers/policy.json""")
|
||||
machine.succeed("mkdir -p /etc/containers")
|
||||
machine.succeed("""echo '{"default":[{"type":"insecureAcceptAnything"}]}' > /etc/containers/policy.json""")
|
||||
|
||||
machine.succeed("${pkgs.podman}/bin/podman load -i ${nixImage}")
|
||||
machine.succeed("${pkgs.podman}/bin/podman run --rm nix nix --version")
|
||||
machine.succeed("${pkgs.podman}/bin/podman run --rm -i nix < ${containerTestScript}")
|
||||
machine.succeed("${pkgs.podman}/bin/podman load -i ${nixImage}")
|
||||
machine.succeed("${pkgs.podman}/bin/podman run --rm nix nix --version")
|
||||
machine.succeed("${pkgs.podman}/bin/podman run --rm -i nix < ${containerTestScript}")
|
||||
|
||||
machine.succeed("${pkgs.podman}/bin/podman load -i ${nixUserImage}")
|
||||
machine.succeed("${pkgs.podman}/bin/podman run --rm nix-user nix --version")
|
||||
machine.succeed("${pkgs.podman}/bin/podman run --rm -i nix-user < ${containerTestScript}")
|
||||
machine.succeed("[[ $(${pkgs.podman}/bin/podman run --rm nix-user stat -c %u /nix/store) = 1000 ]]")
|
||||
'';
|
||||
machine.succeed("${pkgs.podman}/bin/podman load -i ${nixUserImage}")
|
||||
machine.succeed("${pkgs.podman}/bin/podman run --rm nix-user nix --version")
|
||||
machine.succeed("${pkgs.podman}/bin/podman run --rm -i nix-user < ${containerTestScript}")
|
||||
machine.succeed("[[ $(${pkgs.podman}/bin/podman run --rm nix-user stat -c %u /nix/store) = 1000 ]]")
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{ lib, config, nixpkgs, ... }:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
nixpkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
|
||||
|
@ -44,81 +49,119 @@ in
|
|||
name = "nss-preload";
|
||||
|
||||
nodes = {
|
||||
http_dns = { lib, pkgs, config, ... }: {
|
||||
networking.firewall.enable = false;
|
||||
networking.interfaces.eth1.ipv6.addresses = lib.mkForce [
|
||||
{ address = "fd21::1"; prefixLength = 64; }
|
||||
];
|
||||
networking.interfaces.eth1.ipv4.addresses = lib.mkForce [
|
||||
{ address = "192.168.0.1"; prefixLength = 24; }
|
||||
];
|
||||
http_dns =
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
{
|
||||
networking.firewall.enable = false;
|
||||
networking.interfaces.eth1.ipv6.addresses = lib.mkForce [
|
||||
{
|
||||
address = "fd21::1";
|
||||
prefixLength = 64;
|
||||
}
|
||||
];
|
||||
networking.interfaces.eth1.ipv4.addresses = lib.mkForce [
|
||||
{
|
||||
address = "192.168.0.1";
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
|
||||
services.unbound = {
|
||||
enable = true;
|
||||
enableRootTrustAnchor = false;
|
||||
settings = {
|
||||
server = {
|
||||
interface = [ "192.168.0.1" "fd21::1" "::1" "127.0.0.1" ];
|
||||
access-control = [ "192.168.0.0/24 allow" "fd21::/64 allow" "::1 allow" "127.0.0.0/8 allow" ];
|
||||
local-data = [
|
||||
''"example.com. IN A 192.168.0.1"''
|
||||
''"example.com. IN AAAA fd21::1"''
|
||||
''"tarballs.nixos.org. IN A 192.168.0.1"''
|
||||
''"tarballs.nixos.org. IN AAAA fd21::1"''
|
||||
];
|
||||
services.unbound = {
|
||||
enable = true;
|
||||
enableRootTrustAnchor = false;
|
||||
settings = {
|
||||
server = {
|
||||
interface = [
|
||||
"192.168.0.1"
|
||||
"fd21::1"
|
||||
"::1"
|
||||
"127.0.0.1"
|
||||
];
|
||||
access-control = [
|
||||
"192.168.0.0/24 allow"
|
||||
"fd21::/64 allow"
|
||||
"::1 allow"
|
||||
"127.0.0.0/8 allow"
|
||||
];
|
||||
local-data = [
|
||||
''"example.com. IN A 192.168.0.1"''
|
||||
''"example.com. IN AAAA fd21::1"''
|
||||
''"tarballs.nixos.org. IN A 192.168.0.1"''
|
||||
''"tarballs.nixos.org. IN AAAA fd21::1"''
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts."example.com" = {
|
||||
root = pkgs.runCommand "testdir" { } ''
|
||||
mkdir "$out"
|
||||
echo hello world > "$out/index.html"
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts."example.com" = {
|
||||
root = pkgs.runCommand "testdir" {} ''
|
||||
mkdir "$out"
|
||||
echo hello world > "$out/index.html"
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# client consumes a remote resolver
|
||||
client = { lib, nodes, pkgs, ... }: {
|
||||
networking.useDHCP = false;
|
||||
networking.nameservers = [
|
||||
(lib.head nodes.http_dns.networking.interfaces.eth1.ipv6.addresses).address
|
||||
(lib.head nodes.http_dns.networking.interfaces.eth1.ipv4.addresses).address
|
||||
];
|
||||
networking.interfaces.eth1.ipv6.addresses = [
|
||||
{ address = "fd21::10"; prefixLength = 64; }
|
||||
];
|
||||
networking.interfaces.eth1.ipv4.addresses = [
|
||||
{ address = "192.168.0.10"; prefixLength = 24; }
|
||||
];
|
||||
client =
|
||||
{
|
||||
lib,
|
||||
nodes,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
networking.useDHCP = false;
|
||||
networking.nameservers = [
|
||||
(lib.head nodes.http_dns.networking.interfaces.eth1.ipv6.addresses).address
|
||||
(lib.head nodes.http_dns.networking.interfaces.eth1.ipv4.addresses).address
|
||||
];
|
||||
networking.interfaces.eth1.ipv6.addresses = [
|
||||
{
|
||||
address = "fd21::10";
|
||||
prefixLength = 64;
|
||||
}
|
||||
];
|
||||
networking.interfaces.eth1.ipv4.addresses = [
|
||||
{
|
||||
address = "192.168.0.10";
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
|
||||
nix.settings.extra-sandbox-paths = lib.mkForce [];
|
||||
nix.settings.substituters = lib.mkForce [];
|
||||
nix.settings.sandbox = lib.mkForce true;
|
||||
};
|
||||
nix.settings.extra-sandbox-paths = lib.mkForce [ ];
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
nix.settings.sandbox = lib.mkForce true;
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes, ... }: ''
|
||||
http_dns.wait_for_unit("network-online.target")
|
||||
http_dns.wait_for_unit("nginx")
|
||||
http_dns.wait_for_open_port(80)
|
||||
http_dns.wait_for_unit("unbound")
|
||||
http_dns.wait_for_open_port(53)
|
||||
testScript =
|
||||
{ nodes, ... }:
|
||||
''
|
||||
http_dns.wait_for_unit("network-online.target")
|
||||
http_dns.wait_for_unit("nginx")
|
||||
http_dns.wait_for_open_port(80)
|
||||
http_dns.wait_for_unit("unbound")
|
||||
http_dns.wait_for_open_port(53)
|
||||
|
||||
client.start()
|
||||
client.wait_for_unit('multi-user.target')
|
||||
client.wait_for_unit('network-online.target')
|
||||
client.start()
|
||||
client.wait_for_unit('multi-user.target')
|
||||
client.wait_for_unit('network-online.target')
|
||||
|
||||
with subtest("can fetch data from a remote server outside sandbox"):
|
||||
client.succeed("nix --version >&2")
|
||||
client.succeed("curl -vvv http://example.com/index.html >&2")
|
||||
with subtest("can fetch data from a remote server outside sandbox"):
|
||||
client.succeed("nix --version >&2")
|
||||
client.succeed("curl -vvv http://example.com/index.html >&2")
|
||||
|
||||
with subtest("nix-build can lookup dns and fetch data"):
|
||||
client.succeed("""
|
||||
nix-build ${nix-fetch} >&2
|
||||
""")
|
||||
'';
|
||||
with subtest("nix-build can lookup dns and fetch data"):
|
||||
client.succeed("""
|
||||
nix-build ${nix-fetch} >&2
|
||||
""")
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
test@{ config, lib, hostPkgs, ... }:
|
||||
test@{
|
||||
config,
|
||||
lib,
|
||||
hostPkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
pkgs = config.nodes.client.nixpkgs.pkgs;
|
||||
|
||||
# Trivial Nix expression to build remotely.
|
||||
expr = config: nr: pkgs.writeText "expr.nix"
|
||||
''
|
||||
expr =
|
||||
config: nr:
|
||||
pkgs.writeText "expr.nix" ''
|
||||
let utils = builtins.storePath ${config.system.build.extraUtils}; in
|
||||
derivation {
|
||||
name = "hello-${toString nr}";
|
||||
|
@ -41,87 +47,94 @@ in
|
|||
config = {
|
||||
name = lib.mkDefault "remote-builds-ssh-ng";
|
||||
|
||||
nodes =
|
||||
{
|
||||
builder =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
imports = [ test.config.builders.config ];
|
||||
services.openssh.enable = true;
|
||||
virtualisation.writableStore = true;
|
||||
nix.settings.sandbox = true;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
};
|
||||
nodes = {
|
||||
builder =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
imports = [ test.config.builders.config ];
|
||||
services.openssh.enable = true;
|
||||
virtualisation.writableStore = true;
|
||||
nix.settings.sandbox = true;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
};
|
||||
|
||||
client =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
nix.settings.max-jobs = 0; # force remote building
|
||||
nix.distributedBuilds = true;
|
||||
nix.buildMachines =
|
||||
[{
|
||||
hostName = "builder";
|
||||
sshUser = "root";
|
||||
sshKey = "/root/.ssh/id_ed25519";
|
||||
system = "i686-linux";
|
||||
maxJobs = 1;
|
||||
protocol = "ssh-ng";
|
||||
}];
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [ config.system.build.extraUtils ];
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
programs.ssh.extraConfig = "ConnectTimeout 30";
|
||||
};
|
||||
};
|
||||
client =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
nix.settings.max-jobs = 0; # force remote building
|
||||
nix.distributedBuilds = true;
|
||||
nix.buildMachines = [
|
||||
{
|
||||
hostName = "builder";
|
||||
sshUser = "root";
|
||||
sshKey = "/root/.ssh/id_ed25519";
|
||||
system = "i686-linux";
|
||||
maxJobs = 1;
|
||||
protocol = "ssh-ng";
|
||||
}
|
||||
];
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [ config.system.build.extraUtils ];
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
programs.ssh.extraConfig = "ConnectTimeout 30";
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
# fmt: off
|
||||
import subprocess
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
# fmt: off
|
||||
import subprocess
|
||||
|
||||
start_all()
|
||||
start_all()
|
||||
|
||||
# Create an SSH key on the client.
|
||||
subprocess.run([
|
||||
"${hostPkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
|
||||
], capture_output=True, check=True)
|
||||
client.succeed("mkdir -p -m 700 /root/.ssh")
|
||||
client.copy_from_host("key", "/root/.ssh/id_ed25519")
|
||||
client.succeed("chmod 600 /root/.ssh/id_ed25519")
|
||||
# Create an SSH key on the client.
|
||||
subprocess.run([
|
||||
"${hostPkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
|
||||
], capture_output=True, check=True)
|
||||
client.succeed("mkdir -p -m 700 /root/.ssh")
|
||||
client.copy_from_host("key", "/root/.ssh/id_ed25519")
|
||||
client.succeed("chmod 600 /root/.ssh/id_ed25519")
|
||||
|
||||
# Install the SSH key on the builder.
|
||||
client.wait_for_unit("network-online.target")
|
||||
builder.succeed("mkdir -p -m 700 /root/.ssh")
|
||||
builder.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
|
||||
builder.wait_for_unit("sshd")
|
||||
builder.wait_for_unit("multi-user.target")
|
||||
builder.wait_for_unit("network-online.target")
|
||||
# Install the SSH key on the builder.
|
||||
client.wait_for_unit("network-online.target")
|
||||
builder.succeed("mkdir -p -m 700 /root/.ssh")
|
||||
builder.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
|
||||
builder.wait_for_unit("sshd")
|
||||
builder.wait_for_unit("multi-user.target")
|
||||
builder.wait_for_unit("network-online.target")
|
||||
|
||||
client.succeed(f"ssh -o StrictHostKeyChecking=no {builder.name} 'echo hello world'")
|
||||
client.succeed(f"ssh -o StrictHostKeyChecking=no {builder.name} 'echo hello world'")
|
||||
|
||||
# Perform a build
|
||||
out = client.succeed("nix-build ${expr nodes.client 1} 2> build-output")
|
||||
# Perform a build
|
||||
out = client.succeed("nix-build ${expr nodes.client 1} 2> build-output")
|
||||
|
||||
# Verify that the build was done on the builder
|
||||
builder.succeed(f"test -e {out.strip()}")
|
||||
# Verify that the build was done on the builder
|
||||
builder.succeed(f"test -e {out.strip()}")
|
||||
|
||||
# Print the build log, prefix the log lines to avoid nix intercepting lines starting with @nix
|
||||
buildOutput = client.succeed("sed -e 's/^/build-output:/' build-output")
|
||||
print(buildOutput)
|
||||
# Print the build log, prefix the log lines to avoid nix intercepting lines starting with @nix
|
||||
buildOutput = client.succeed("sed -e 's/^/build-output:/' build-output")
|
||||
print(buildOutput)
|
||||
|
||||
# Make sure that we get the expected build output
|
||||
client.succeed("grep -qF Hello build-output")
|
||||
# Make sure that we get the expected build output
|
||||
client.succeed("grep -qF Hello build-output")
|
||||
|
||||
# We don't want phase reporting in the build output
|
||||
client.fail("grep -qF '@nix' build-output")
|
||||
# We don't want phase reporting in the build output
|
||||
client.fail("grep -qF '@nix' build-output")
|
||||
|
||||
# Get the log file
|
||||
client.succeed(f"nix-store --read-log {out.strip()} > log-output")
|
||||
# Prefix the log lines to avoid nix intercepting lines starting with @nix
|
||||
logOutput = client.succeed("sed -e 's/^/log-file:/' log-output")
|
||||
print(logOutput)
|
||||
# Get the log file
|
||||
client.succeed(f"nix-store --read-log {out.strip()} > log-output")
|
||||
# Prefix the log lines to avoid nix intercepting lines starting with @nix
|
||||
logOutput = client.succeed("sed -e 's/^/log-file:/' log-output")
|
||||
print(logOutput)
|
||||
|
||||
# Check that we get phase reporting in the log file
|
||||
client.succeed("grep -q '@nix {\"action\":\"setPhase\",\"phase\":\"buildPhase\"}' log-output")
|
||||
'';
|
||||
# Check that we get phase reporting in the log file
|
||||
client.succeed("grep -q '@nix {\"action\":\"setPhase\",\"phase\":\"buildPhase\"}' log-output")
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
# Test Nix's remote build feature.
|
||||
|
||||
test@{ config, lib, hostPkgs, ... }:
|
||||
test@{
|
||||
config,
|
||||
lib,
|
||||
hostPkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
pkgs = config.nodes.client.nixpkgs.pkgs;
|
||||
|
@ -21,8 +26,9 @@ let
|
|||
};
|
||||
|
||||
# Trivial Nix expression to build remotely.
|
||||
expr = config: nr: pkgs.writeText "expr.nix"
|
||||
''
|
||||
expr =
|
||||
config: nr:
|
||||
pkgs.writeText "expr.nix" ''
|
||||
let utils = builtins.storePath ${config.system.build.extraUtils}; in
|
||||
derivation {
|
||||
name = "hello-${toString nr}";
|
||||
|
@ -52,107 +58,112 @@ in
|
|||
config = {
|
||||
name = lib.mkDefault "remote-builds";
|
||||
|
||||
nodes =
|
||||
{
|
||||
builder1 = builder;
|
||||
builder2 = builder;
|
||||
nodes = {
|
||||
builder1 = builder;
|
||||
builder2 = builder;
|
||||
|
||||
client =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
nix.settings.max-jobs = 0; # force remote building
|
||||
nix.distributedBuilds = true;
|
||||
nix.buildMachines =
|
||||
[
|
||||
{
|
||||
hostName = "builder1";
|
||||
sshUser = "root";
|
||||
sshKey = "/root/.ssh/id_ed25519";
|
||||
system = "i686-linux";
|
||||
maxJobs = 1;
|
||||
}
|
||||
{
|
||||
hostName = "builder2";
|
||||
sshUser = "root";
|
||||
sshKey = "/root/.ssh/id_ed25519";
|
||||
system = "i686-linux";
|
||||
maxJobs = 1;
|
||||
}
|
||||
];
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [ config.system.build.extraUtils ];
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
programs.ssh.extraConfig = "ConnectTimeout 30";
|
||||
environment.systemPackages = [
|
||||
# `bad-shell` is used to make sure Nix works in an environment with a misbehaving shell.
|
||||
#
|
||||
# More realistically, a bad shell would still run the command ("echo started")
|
||||
# but considering that our solution is to avoid this shell (set via $SHELL), we
|
||||
# don't need to bother with a more functional mock shell.
|
||||
(pkgs.writeScriptBin "bad-shell" ''
|
||||
#!${pkgs.runtimeShell}
|
||||
echo "Hello, I am a broken shell"
|
||||
'')
|
||||
];
|
||||
};
|
||||
};
|
||||
client =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
nix.settings.max-jobs = 0; # force remote building
|
||||
nix.distributedBuilds = true;
|
||||
nix.buildMachines = [
|
||||
{
|
||||
hostName = "builder1";
|
||||
sshUser = "root";
|
||||
sshKey = "/root/.ssh/id_ed25519";
|
||||
system = "i686-linux";
|
||||
maxJobs = 1;
|
||||
}
|
||||
{
|
||||
hostName = "builder2";
|
||||
sshUser = "root";
|
||||
sshKey = "/root/.ssh/id_ed25519";
|
||||
system = "i686-linux";
|
||||
maxJobs = 1;
|
||||
}
|
||||
];
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [ config.system.build.extraUtils ];
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
programs.ssh.extraConfig = "ConnectTimeout 30";
|
||||
environment.systemPackages = [
|
||||
# `bad-shell` is used to make sure Nix works in an environment with a misbehaving shell.
|
||||
#
|
||||
# More realistically, a bad shell would still run the command ("echo started")
|
||||
# but considering that our solution is to avoid this shell (set via $SHELL), we
|
||||
# don't need to bother with a more functional mock shell.
|
||||
(pkgs.writeScriptBin "bad-shell" ''
|
||||
#!${pkgs.runtimeShell}
|
||||
echo "Hello, I am a broken shell"
|
||||
'')
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
# fmt: off
|
||||
import subprocess
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
# fmt: off
|
||||
import subprocess
|
||||
|
||||
start_all()
|
||||
start_all()
|
||||
|
||||
# Create an SSH key on the client.
|
||||
subprocess.run([
|
||||
"${hostPkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
|
||||
], capture_output=True, check=True)
|
||||
client.succeed("mkdir -p -m 700 /root/.ssh")
|
||||
client.copy_from_host("key", "/root/.ssh/id_ed25519")
|
||||
client.succeed("chmod 600 /root/.ssh/id_ed25519")
|
||||
# Create an SSH key on the client.
|
||||
subprocess.run([
|
||||
"${hostPkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
|
||||
], capture_output=True, check=True)
|
||||
client.succeed("mkdir -p -m 700 /root/.ssh")
|
||||
client.copy_from_host("key", "/root/.ssh/id_ed25519")
|
||||
client.succeed("chmod 600 /root/.ssh/id_ed25519")
|
||||
|
||||
# Install the SSH key on the builders.
|
||||
client.wait_for_unit("network-online.target")
|
||||
for builder in [builder1, builder2]:
|
||||
builder.succeed("mkdir -p -m 700 /root/.ssh")
|
||||
builder.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
|
||||
builder.wait_for_unit("sshd")
|
||||
builder.wait_for_unit("network-online.target")
|
||||
# Make sure the builder can handle our login correctly
|
||||
builder.wait_for_unit("multi-user.target")
|
||||
# Make sure there's no funny business on the client either
|
||||
# (should not be necessary, but we have reason to be careful)
|
||||
client.wait_for_unit("multi-user.target")
|
||||
client.succeed(f"""
|
||||
ssh -o StrictHostKeyChecking=no {builder.name} \
|
||||
'echo hello world on $(hostname)' >&2
|
||||
""")
|
||||
# Install the SSH key on the builders.
|
||||
client.wait_for_unit("network-online.target")
|
||||
for builder in [builder1, builder2]:
|
||||
builder.succeed("mkdir -p -m 700 /root/.ssh")
|
||||
builder.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
|
||||
builder.wait_for_unit("sshd")
|
||||
builder.wait_for_unit("network-online.target")
|
||||
# Make sure the builder can handle our login correctly
|
||||
builder.wait_for_unit("multi-user.target")
|
||||
# Make sure there's no funny business on the client either
|
||||
# (should not be necessary, but we have reason to be careful)
|
||||
client.wait_for_unit("multi-user.target")
|
||||
client.succeed(f"""
|
||||
ssh -o StrictHostKeyChecking=no {builder.name} \
|
||||
'echo hello world on $(hostname)' >&2
|
||||
""")
|
||||
|
||||
${lib.optionalString supportsBadShell ''
|
||||
# Check that SSH uses SHELL for LocalCommand, as expected, and check that
|
||||
# our test setup here is working. The next test will use this bad SHELL.
|
||||
client.succeed(f"SHELL=$(which bad-shell) ssh -oLocalCommand='true' -oPermitLocalCommand=yes {builder1.name} 'echo hello world' | grep -F 'Hello, I am a broken shell'")
|
||||
''}
|
||||
${lib.optionalString supportsBadShell ''
|
||||
# Check that SSH uses SHELL for LocalCommand, as expected, and check that
|
||||
# our test setup here is working. The next test will use this bad SHELL.
|
||||
client.succeed(f"SHELL=$(which bad-shell) ssh -oLocalCommand='true' -oPermitLocalCommand=yes {builder1.name} 'echo hello world' | grep -F 'Hello, I am a broken shell'")
|
||||
''}
|
||||
|
||||
# Perform a build and check that it was performed on the builder.
|
||||
out = client.succeed(
|
||||
"${lib.optionalString supportsBadShell "SHELL=$(which bad-shell)"} nix-build ${expr nodes.client 1} 2> build-output",
|
||||
"grep -q Hello build-output"
|
||||
)
|
||||
builder1.succeed(f"test -e {out}")
|
||||
# Perform a build and check that it was performed on the builder.
|
||||
out = client.succeed(
|
||||
"${lib.optionalString supportsBadShell "SHELL=$(which bad-shell)"} nix-build ${expr nodes.client 1} 2> build-output",
|
||||
"grep -q Hello build-output"
|
||||
)
|
||||
builder1.succeed(f"test -e {out}")
|
||||
|
||||
# And a parallel build.
|
||||
paths = client.succeed(r'nix-store -r $(nix-instantiate ${expr nodes.client 2})\!out $(nix-instantiate ${expr nodes.client 3})\!out')
|
||||
out1, out2 = paths.split()
|
||||
builder1.succeed(f"test -e {out1} -o -e {out2}")
|
||||
builder2.succeed(f"test -e {out1} -o -e {out2}")
|
||||
# And a parallel build.
|
||||
paths = client.succeed(r'nix-store -r $(nix-instantiate ${expr nodes.client 2})\!out $(nix-instantiate ${expr nodes.client 3})\!out')
|
||||
out1, out2 = paths.split()
|
||||
builder1.succeed(f"test -e {out1} -o -e {out2}")
|
||||
builder2.succeed(f"test -e {out1} -o -e {out2}")
|
||||
|
||||
# And a failing build.
|
||||
client.fail("nix-build ${expr nodes.client 5}")
|
||||
# And a failing build.
|
||||
client.fail("nix-build ${expr nodes.client 5}")
|
||||
|
||||
# Test whether the build hook automatically skips unavailable builders.
|
||||
builder1.block()
|
||||
client.succeed("nix-build ${expr nodes.client 4}")
|
||||
'';
|
||||
# Test whether the build hook automatically skips unavailable builders.
|
||||
builder1.block()
|
||||
client.succeed("nix-build ${expr nodes.client 4}")
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{ lib, config, nixpkgs, ... }:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
nixpkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
pkgs = config.nodes.client.nixpkgs.pkgs;
|
||||
|
@ -12,71 +17,81 @@ let
|
|||
storeUrl = "s3://my-cache?endpoint=http://server:9000®ion=eu-west-1";
|
||||
objectThatDoesNotExist = "s3://my-cache/foo-that-does-not-exist?endpoint=http://server:9000®ion=eu-west-1";
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
name = "s3-binary-cache-store";
|
||||
|
||||
nodes =
|
||||
{ server =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [ pkgA ];
|
||||
environment.systemPackages = [ pkgs.minio-client ];
|
||||
nix.extraOptions = ''
|
||||
experimental-features = nix-command
|
||||
substituters =
|
||||
'';
|
||||
services.minio = {
|
||||
enable = true;
|
||||
region = "eu-west-1";
|
||||
rootCredentialsFile = pkgs.writeText "minio-credentials-full" ''
|
||||
MINIO_ROOT_USER=${accessKey}
|
||||
MINIO_ROOT_PASSWORD=${secretKey}
|
||||
'';
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [ 9000 ];
|
||||
};
|
||||
|
||||
client =
|
||||
{ config, pkgs, ... }:
|
||||
{ virtualisation.writableStore = true;
|
||||
nix.extraOptions = ''
|
||||
experimental-features = nix-command
|
||||
substituters =
|
||||
nodes = {
|
||||
server =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [ pkgA ];
|
||||
environment.systemPackages = [ pkgs.minio-client ];
|
||||
nix.extraOptions = ''
|
||||
experimental-features = nix-command
|
||||
substituters =
|
||||
'';
|
||||
services.minio = {
|
||||
enable = true;
|
||||
region = "eu-west-1";
|
||||
rootCredentialsFile = pkgs.writeText "minio-credentials-full" ''
|
||||
MINIO_ROOT_USER=${accessKey}
|
||||
MINIO_ROOT_PASSWORD=${secretKey}
|
||||
'';
|
||||
};
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [ 9000 ];
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
# fmt: off
|
||||
start_all()
|
||||
client =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
virtualisation.writableStore = true;
|
||||
nix.extraOptions = ''
|
||||
experimental-features = nix-command
|
||||
substituters =
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
# Create a binary cache.
|
||||
server.wait_for_unit("minio")
|
||||
server.wait_for_unit("network-online.target")
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
# fmt: off
|
||||
start_all()
|
||||
|
||||
server.succeed("mc config host add minio http://localhost:9000 ${accessKey} ${secretKey} --api s3v4")
|
||||
server.succeed("mc mb minio/my-cache")
|
||||
# Create a binary cache.
|
||||
server.wait_for_unit("minio")
|
||||
server.wait_for_unit("network-online.target")
|
||||
|
||||
server.succeed("${env} nix copy --to '${storeUrl}' ${pkgA}")
|
||||
server.succeed("mc config host add minio http://localhost:9000 ${accessKey} ${secretKey} --api s3v4")
|
||||
server.succeed("mc mb minio/my-cache")
|
||||
|
||||
client.wait_for_unit("network-online.target")
|
||||
server.succeed("${env} nix copy --to '${storeUrl}' ${pkgA}")
|
||||
|
||||
# Test fetchurl on s3:// URLs while we're at it.
|
||||
client.succeed("${env} nix eval --impure --expr 'builtins.fetchurl { name = \"foo\"; url = \"s3://my-cache/nix-cache-info?endpoint=http://server:9000®ion=eu-west-1\"; }'")
|
||||
client.wait_for_unit("network-online.target")
|
||||
|
||||
# Test that the format string in the error message is properly setup and won't display `%s` instead of the failed URI
|
||||
msg = client.fail("${env} nix eval --impure --expr 'builtins.fetchurl { name = \"foo\"; url = \"${objectThatDoesNotExist}\"; }' 2>&1")
|
||||
if "S3 object '${objectThatDoesNotExist}' does not exist" not in msg:
|
||||
print(msg) # So that you can see the message that was improperly formatted
|
||||
raise Exception("Error message formatting didn't work")
|
||||
# Test fetchurl on s3:// URLs while we're at it.
|
||||
client.succeed("${env} nix eval --impure --expr 'builtins.fetchurl { name = \"foo\"; url = \"s3://my-cache/nix-cache-info?endpoint=http://server:9000®ion=eu-west-1\"; }'")
|
||||
|
||||
# Copy a package from the binary cache.
|
||||
client.fail("nix path-info ${pkgA}")
|
||||
# Test that the format string in the error message is properly setup and won't display `%s` instead of the failed URI
|
||||
msg = client.fail("${env} nix eval --impure --expr 'builtins.fetchurl { name = \"foo\"; url = \"${objectThatDoesNotExist}\"; }' 2>&1")
|
||||
if "S3 object '${objectThatDoesNotExist}' does not exist" not in msg:
|
||||
print(msg) # So that you can see the message that was improperly formatted
|
||||
raise Exception("Error message formatting didn't work")
|
||||
|
||||
client.succeed("${env} nix store info --store '${storeUrl}' >&2")
|
||||
# Copy a package from the binary cache.
|
||||
client.fail("nix path-info ${pkgA}")
|
||||
|
||||
client.succeed("${env} nix copy --no-check-sigs --from '${storeUrl}' ${pkgA}")
|
||||
client.succeed("${env} nix store info --store '${storeUrl}' >&2")
|
||||
|
||||
client.succeed("nix path-info ${pkgA}")
|
||||
'';
|
||||
client.succeed("${env} nix copy --no-check-sigs --from '${storeUrl}' ${pkgA}")
|
||||
|
||||
client.succeed("nix path-info ${pkgA}")
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
# Verify that Linux builds cannot create setuid or setgid binaries.
|
||||
|
||||
{ lib, config, nixpkgs, ... }:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
nixpkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
pkgs = config.nodes.machine.nixpkgs.pkgs;
|
||||
|
@ -10,116 +15,127 @@ in
|
|||
name = "setuid";
|
||||
|
||||
nodes.machine =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ virtualisation.writableStore = true;
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
virtualisation.writableStore = true;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
nix.nixPath = [ "nixpkgs=${lib.cleanSource pkgs.path}" ];
|
||||
virtualisation.additionalPaths = [ pkgs.stdenvNoCC pkgs.pkgsi686Linux.stdenvNoCC ];
|
||||
virtualisation.additionalPaths = [
|
||||
pkgs.stdenvNoCC
|
||||
pkgs.pkgsi686Linux.stdenvNoCC
|
||||
];
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
# fmt: off
|
||||
start_all()
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
# fmt: off
|
||||
start_all()
|
||||
|
||||
# Copying to /tmp should succeed.
|
||||
machine.succeed(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" {} "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
")'
|
||||
""".strip())
|
||||
# Copying to /tmp should succeed.
|
||||
machine.succeed(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" {} "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
")'
|
||||
""".strip())
|
||||
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]')
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]')
|
||||
|
||||
machine.succeed("rm /tmp/id")
|
||||
machine.succeed("rm /tmp/id")
|
||||
|
||||
# Creating a setuid binary should fail.
|
||||
machine.fail(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" {} "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
chmod 4755 /tmp/id
|
||||
")'
|
||||
""".strip())
|
||||
# Creating a setuid binary should fail.
|
||||
machine.fail(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" {} "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
chmod 4755 /tmp/id
|
||||
")'
|
||||
""".strip())
|
||||
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]')
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]')
|
||||
|
||||
machine.succeed("rm /tmp/id")
|
||||
machine.succeed("rm /tmp/id")
|
||||
|
||||
# Creating a setgid binary should fail.
|
||||
machine.fail(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" {} "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
chmod 2755 /tmp/id
|
||||
")'
|
||||
""".strip())
|
||||
# Creating a setgid binary should fail.
|
||||
machine.fail(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" {} "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
chmod 2755 /tmp/id
|
||||
")'
|
||||
""".strip())
|
||||
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]')
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]')
|
||||
|
||||
machine.succeed("rm /tmp/id")
|
||||
machine.succeed("rm /tmp/id")
|
||||
|
||||
# The checks should also work on 32-bit binaries.
|
||||
machine.fail(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> { system = "i686-linux"; }; runCommand "foo" {} "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
chmod 2755 /tmp/id
|
||||
")'
|
||||
""".strip())
|
||||
# The checks should also work on 32-bit binaries.
|
||||
machine.fail(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> { system = "i686-linux"; }; runCommand "foo" {} "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
chmod 2755 /tmp/id
|
||||
")'
|
||||
""".strip())
|
||||
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]')
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]')
|
||||
|
||||
machine.succeed("rm /tmp/id")
|
||||
machine.succeed("rm /tmp/id")
|
||||
|
||||
# The tests above use fchmodat(). Test chmod() as well.
|
||||
machine.succeed(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
perl -e \"chmod 0666, qw(/tmp/id) or die\"
|
||||
")'
|
||||
""".strip())
|
||||
# The tests above use fchmodat(). Test chmod() as well.
|
||||
machine.succeed(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
perl -e \"chmod 0666, qw(/tmp/id) or die\"
|
||||
")'
|
||||
""".strip())
|
||||
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 666 ]]')
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 666 ]]')
|
||||
|
||||
machine.succeed("rm /tmp/id")
|
||||
machine.succeed("rm /tmp/id")
|
||||
|
||||
machine.fail(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
perl -e \"chmod 04755, qw(/tmp/id) or die\"
|
||||
")'
|
||||
""".strip())
|
||||
machine.fail(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
perl -e \"chmod 04755, qw(/tmp/id) or die\"
|
||||
")'
|
||||
""".strip())
|
||||
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]')
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]')
|
||||
|
||||
machine.succeed("rm /tmp/id")
|
||||
machine.succeed("rm /tmp/id")
|
||||
|
||||
# And test fchmod().
|
||||
machine.succeed(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 01750, \\\$x or die\"
|
||||
")'
|
||||
""".strip())
|
||||
# And test fchmod().
|
||||
machine.succeed(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 01750, \\\$x or die\"
|
||||
")'
|
||||
""".strip())
|
||||
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 1750 ]]')
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 1750 ]]')
|
||||
|
||||
machine.succeed("rm /tmp/id")
|
||||
machine.succeed("rm /tmp/id")
|
||||
|
||||
machine.fail(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 04777, \\\$x or die\"
|
||||
")'
|
||||
""".strip())
|
||||
machine.fail(r"""
|
||||
nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
|
||||
mkdir -p $out
|
||||
cp ${pkgs.coreutils}/bin/id /tmp/id
|
||||
perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 04777, \\\$x or die\"
|
||||
")'
|
||||
""".strip())
|
||||
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]')
|
||||
machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]')
|
||||
|
||||
machine.succeed("rm /tmp/id")
|
||||
'';
|
||||
machine.succeed("rm /tmp/id")
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -1,22 +1,27 @@
|
|||
{ lib, config, hostPkgs, nixpkgs, ... }:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
hostPkgs,
|
||||
nixpkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
pkgs = config.nodes.sourcehut.nixpkgs.pkgs;
|
||||
|
||||
# Generate a fake root CA and a fake git.sr.ht certificate.
|
||||
cert = pkgs.runCommand "cert" { buildInputs = [ pkgs.openssl ]; }
|
||||
''
|
||||
mkdir -p $out
|
||||
cert = pkgs.runCommand "cert" { buildInputs = [ pkgs.openssl ]; } ''
|
||||
mkdir -p $out
|
||||
|
||||
openssl genrsa -out ca.key 2048
|
||||
openssl req -new -x509 -days 36500 -key ca.key \
|
||||
-subj "/C=NL/ST=Denial/L=Springfield/O=Dis/CN=Root CA" -out $out/ca.crt
|
||||
openssl genrsa -out ca.key 2048
|
||||
openssl req -new -x509 -days 36500 -key ca.key \
|
||||
-subj "/C=NL/ST=Denial/L=Springfield/O=Dis/CN=Root CA" -out $out/ca.crt
|
||||
|
||||
openssl req -newkey rsa:2048 -nodes -keyout $out/server.key \
|
||||
-subj "/C=CN/ST=Denial/L=Springfield/O=Dis/CN=git.sr.ht" -out server.csr
|
||||
openssl x509 -req -extfile <(printf "subjectAltName=DNS:git.sr.ht") \
|
||||
-days 36500 -in server.csr -CA $out/ca.crt -CAkey ca.key -CAcreateserial -out $out/server.crt
|
||||
'';
|
||||
openssl req -newkey rsa:2048 -nodes -keyout $out/server.key \
|
||||
-subj "/C=CN/ST=Denial/L=Springfield/O=Dis/CN=git.sr.ht" -out server.csr
|
||||
openssl x509 -req -extfile <(printf "subjectAltName=DNS:git.sr.ht") \
|
||||
-days 36500 -in server.csr -CA $out/ca.crt -CAkey ca.key -CAcreateserial -out $out/server.crt
|
||||
'';
|
||||
|
||||
registry = pkgs.writeTextFile {
|
||||
name = "registry";
|
||||
|
@ -41,80 +46,92 @@ let
|
|||
destination = "/flake-registry.json";
|
||||
};
|
||||
|
||||
nixpkgs-repo = pkgs.runCommand "nixpkgs-flake" { }
|
||||
''
|
||||
dir=NixOS-nixpkgs-${nixpkgs.shortRev}
|
||||
cp -prd ${nixpkgs} $dir
|
||||
nixpkgs-repo = pkgs.runCommand "nixpkgs-flake" { } ''
|
||||
dir=NixOS-nixpkgs-${nixpkgs.shortRev}
|
||||
cp -prd ${nixpkgs} $dir
|
||||
|
||||
# Set the correct timestamp in the tarball.
|
||||
find $dir -print0 | xargs -0 touch -h -t ${builtins.substring 0 12 nixpkgs.lastModifiedDate}.${builtins.substring 12 2 nixpkgs.lastModifiedDate} --
|
||||
# Set the correct timestamp in the tarball.
|
||||
find $dir -print0 | xargs -0 touch -h -t ${builtins.substring 0 12 nixpkgs.lastModifiedDate}.${
|
||||
builtins.substring 12 2 nixpkgs.lastModifiedDate
|
||||
} --
|
||||
|
||||
mkdir -p $out/archive
|
||||
tar cfz $out/archive/${nixpkgs.rev}.tar.gz $dir --hard-dereference
|
||||
mkdir -p $out/archive
|
||||
tar cfz $out/archive/${nixpkgs.rev}.tar.gz $dir --hard-dereference
|
||||
|
||||
echo 'ref: refs/heads/master' > $out/HEAD
|
||||
echo 'ref: refs/heads/master' > $out/HEAD
|
||||
|
||||
mkdir -p $out/info
|
||||
echo -e '${nixpkgs.rev}\trefs/heads/master\n${nixpkgs.rev}\trefs/tags/foo-bar' > $out/info/refs
|
||||
'';
|
||||
mkdir -p $out/info
|
||||
echo -e '${nixpkgs.rev}\trefs/heads/master\n${nixpkgs.rev}\trefs/tags/foo-bar' > $out/info/refs
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
name = "sourcehut-flakes";
|
||||
{
|
||||
name = "sourcehut-flakes";
|
||||
|
||||
nodes =
|
||||
nodes = {
|
||||
# Impersonate git.sr.ht
|
||||
sourcehut =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
# Impersonate git.sr.ht
|
||||
sourcehut =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
80
|
||||
443
|
||||
];
|
||||
|
||||
services.httpd.enable = true;
|
||||
services.httpd.adminAddr = "foo@example.org";
|
||||
services.httpd.extraConfig = ''
|
||||
ErrorLog syslog:local6
|
||||
'';
|
||||
services.httpd.virtualHosts."git.sr.ht" =
|
||||
{
|
||||
forceSSL = true;
|
||||
sslServerKey = "${cert}/server.key";
|
||||
sslServerCert = "${cert}/server.crt";
|
||||
servedDirs =
|
||||
[
|
||||
{
|
||||
urlPath = "/~NixOS/nixpkgs";
|
||||
dir = nixpkgs-repo;
|
||||
}
|
||||
{
|
||||
urlPath = "/~NixOS/flake-registry/blob/master";
|
||||
dir = registry;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
client =
|
||||
{ config, lib, pkgs, nodes, ... }:
|
||||
{
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.diskSize = 2048;
|
||||
virtualisation.additionalPaths = [ pkgs.hello pkgs.fuse ];
|
||||
virtualisation.memorySize = 4096;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
nix.extraOptions = ''
|
||||
experimental-features = nix-command flakes
|
||||
flake-registry = https://git.sr.ht/~NixOS/flake-registry/blob/master/flake-registry.json
|
||||
'';
|
||||
environment.systemPackages = [ pkgs.jq ];
|
||||
networking.hosts.${(builtins.head nodes.sourcehut.networking.interfaces.eth1.ipv4.addresses).address} =
|
||||
[ "git.sr.ht" ];
|
||||
security.pki.certificateFiles = [ "${cert}/ca.crt" ];
|
||||
};
|
||||
services.httpd.enable = true;
|
||||
services.httpd.adminAddr = "foo@example.org";
|
||||
services.httpd.extraConfig = ''
|
||||
ErrorLog syslog:local6
|
||||
'';
|
||||
services.httpd.virtualHosts."git.sr.ht" = {
|
||||
forceSSL = true;
|
||||
sslServerKey = "${cert}/server.key";
|
||||
sslServerCert = "${cert}/server.crt";
|
||||
servedDirs = [
|
||||
{
|
||||
urlPath = "/~NixOS/nixpkgs";
|
||||
dir = nixpkgs-repo;
|
||||
}
|
||||
{
|
||||
urlPath = "/~NixOS/flake-registry/blob/master";
|
||||
dir = registry;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
client =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
nodes,
|
||||
...
|
||||
}:
|
||||
{
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.diskSize = 2048;
|
||||
virtualisation.additionalPaths = [
|
||||
pkgs.hello
|
||||
pkgs.fuse
|
||||
];
|
||||
virtualisation.memorySize = 4096;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
nix.extraOptions = ''
|
||||
experimental-features = nix-command flakes
|
||||
flake-registry = https://git.sr.ht/~NixOS/flake-registry/blob/master/flake-registry.json
|
||||
'';
|
||||
environment.systemPackages = [ pkgs.jq ];
|
||||
networking.hosts.${(builtins.head nodes.sourcehut.networking.interfaces.eth1.ipv4.addresses).address} =
|
||||
[ "git.sr.ht" ];
|
||||
security.pki.certificateFiles = [ "${cert}/ca.crt" ];
|
||||
};
|
||||
};
|
||||
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
# fmt: off
|
||||
import json
|
||||
import time
|
||||
|
|
|
@ -1,94 +1,106 @@
|
|||
{ lib, config, nixpkgs, ... }:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
nixpkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
pkgs = config.nodes.machine.nixpkgs.pkgs;
|
||||
|
||||
root = pkgs.runCommand "nixpkgs-flake" {}
|
||||
''
|
||||
mkdir -p $out/{stable,tags}
|
||||
root = pkgs.runCommand "nixpkgs-flake" { } ''
|
||||
mkdir -p $out/{stable,tags}
|
||||
|
||||
set -x
|
||||
dir=nixpkgs-${nixpkgs.shortRev}
|
||||
cp -prd ${nixpkgs} $dir
|
||||
# Set the correct timestamp in the tarball.
|
||||
find $dir -print0 | xargs -0 touch -h -t ${builtins.substring 0 12 nixpkgs.lastModifiedDate}.${builtins.substring 12 2 nixpkgs.lastModifiedDate} --
|
||||
tar cfz $out/stable/${nixpkgs.rev}.tar.gz $dir --hard-dereference
|
||||
set -x
|
||||
dir=nixpkgs-${nixpkgs.shortRev}
|
||||
cp -prd ${nixpkgs} $dir
|
||||
# Set the correct timestamp in the tarball.
|
||||
find $dir -print0 | xargs -0 touch -h -t ${builtins.substring 0 12 nixpkgs.lastModifiedDate}.${
|
||||
builtins.substring 12 2 nixpkgs.lastModifiedDate
|
||||
} --
|
||||
tar cfz $out/stable/${nixpkgs.rev}.tar.gz $dir --hard-dereference
|
||||
|
||||
# Set the "Link" header on the redirect but not the final response to
|
||||
# simulate an S3-like serving environment where the final host cannot set
|
||||
# arbitrary headers.
|
||||
cat >$out/tags/.htaccess <<EOF
|
||||
Redirect "/tags/latest.tar.gz" "/stable/${nixpkgs.rev}.tar.gz"
|
||||
Header always set Link "<http://localhost/stable/${nixpkgs.rev}.tar.gz?rev=${nixpkgs.rev}&revCount=1234>; rel=\"immutable\""
|
||||
EOF
|
||||
'';
|
||||
# Set the "Link" header on the redirect but not the final response to
|
||||
# simulate an S3-like serving environment where the final host cannot set
|
||||
# arbitrary headers.
|
||||
cat >$out/tags/.htaccess <<EOF
|
||||
Redirect "/tags/latest.tar.gz" "/stable/${nixpkgs.rev}.tar.gz"
|
||||
Header always set Link "<http://localhost/stable/${nixpkgs.rev}.tar.gz?rev=${nixpkgs.rev}&revCount=1234>; rel=\"immutable\""
|
||||
EOF
|
||||
'';
|
||||
in
|
||||
|
||||
{
|
||||
name = "tarball-flakes";
|
||||
|
||||
nodes =
|
||||
{
|
||||
machine =
|
||||
{ config, pkgs, ... }:
|
||||
{ networking.firewall.allowedTCPPorts = [ 80 ];
|
||||
nodes = {
|
||||
machine =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
networking.firewall.allowedTCPPorts = [ 80 ];
|
||||
|
||||
services.httpd.enable = true;
|
||||
services.httpd.adminAddr = "foo@example.org";
|
||||
services.httpd.extraConfig = ''
|
||||
ErrorLog syslog:local6
|
||||
'';
|
||||
services.httpd.virtualHosts."localhost" =
|
||||
{ servedDirs =
|
||||
[ { urlPath = "/";
|
||||
dir = root;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.diskSize = 2048;
|
||||
virtualisation.additionalPaths = [ pkgs.hello pkgs.fuse ];
|
||||
virtualisation.memorySize = 4096;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
nix.extraOptions = "experimental-features = nix-command flakes";
|
||||
services.httpd.enable = true;
|
||||
services.httpd.adminAddr = "foo@example.org";
|
||||
services.httpd.extraConfig = ''
|
||||
ErrorLog syslog:local6
|
||||
'';
|
||||
services.httpd.virtualHosts."localhost" = {
|
||||
servedDirs = [
|
||||
{
|
||||
urlPath = "/";
|
||||
dir = root;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
# fmt: off
|
||||
import json
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.diskSize = 2048;
|
||||
virtualisation.additionalPaths = [
|
||||
pkgs.hello
|
||||
pkgs.fuse
|
||||
];
|
||||
virtualisation.memorySize = 4096;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
nix.extraOptions = "experimental-features = nix-command flakes";
|
||||
};
|
||||
};
|
||||
|
||||
start_all()
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
# fmt: off
|
||||
import json
|
||||
|
||||
machine.wait_for_unit("httpd.service")
|
||||
start_all()
|
||||
|
||||
out = machine.succeed("nix flake metadata --json http://localhost/tags/latest.tar.gz")
|
||||
print(out)
|
||||
info = json.loads(out)
|
||||
machine.wait_for_unit("httpd.service")
|
||||
|
||||
# Check that we got redirected to the immutable URL.
|
||||
assert info["locked"]["url"] == "http://localhost/stable/${nixpkgs.rev}.tar.gz"
|
||||
out = machine.succeed("nix flake metadata --json http://localhost/tags/latest.tar.gz")
|
||||
print(out)
|
||||
info = json.loads(out)
|
||||
|
||||
# Check that we got a fingerprint for caching.
|
||||
assert info["fingerprint"]
|
||||
# Check that we got redirected to the immutable URL.
|
||||
assert info["locked"]["url"] == "http://localhost/stable/${nixpkgs.rev}.tar.gz"
|
||||
|
||||
# Check that we got the rev and revCount attributes.
|
||||
assert info["revision"] == "${nixpkgs.rev}"
|
||||
assert info["revCount"] == 1234
|
||||
# Check that we got a fingerprint for caching.
|
||||
assert info["fingerprint"]
|
||||
|
||||
# Check that a 0-byte HTTP 304 "Not modified" result works.
|
||||
machine.succeed("nix flake metadata --refresh --json http://localhost/tags/latest.tar.gz")
|
||||
# Check that we got the rev and revCount attributes.
|
||||
assert info["revision"] == "${nixpkgs.rev}"
|
||||
assert info["revCount"] == 1234
|
||||
|
||||
# Check that fetching with rev/revCount/narHash succeeds.
|
||||
machine.succeed("nix flake metadata --json http://localhost/tags/latest.tar.gz?rev=" + info["revision"])
|
||||
machine.succeed("nix flake metadata --json http://localhost/tags/latest.tar.gz?revCount=" + str(info["revCount"]))
|
||||
machine.succeed("nix flake metadata --json http://localhost/tags/latest.tar.gz?narHash=" + info["locked"]["narHash"])
|
||||
# Check that a 0-byte HTTP 304 "Not modified" result works.
|
||||
machine.succeed("nix flake metadata --refresh --json http://localhost/tags/latest.tar.gz")
|
||||
|
||||
# Check that fetching fails if we provide incorrect attributes.
|
||||
machine.fail("nix flake metadata --json http://localhost/tags/latest.tar.gz?rev=493300eb13ae6fb387fbd47bf54a85915acc31c0")
|
||||
machine.fail("nix flake metadata --json http://localhost/tags/latest.tar.gz?revCount=789")
|
||||
machine.fail("nix flake metadata --json http://localhost/tags/latest.tar.gz?narHash=sha256-tbudgBSg+bHWHiHnlteNzN8TUvI80ygS9IULh4rklEw=")
|
||||
'';
|
||||
# Check that fetching with rev/revCount/narHash succeeds.
|
||||
machine.succeed("nix flake metadata --json http://localhost/tags/latest.tar.gz?rev=" + info["revision"])
|
||||
machine.succeed("nix flake metadata --json http://localhost/tags/latest.tar.gz?revCount=" + str(info["revCount"]))
|
||||
machine.succeed("nix flake metadata --json http://localhost/tags/latest.tar.gz?narHash=" + info["locked"]["narHash"])
|
||||
|
||||
# Check that fetching fails if we provide incorrect attributes.
|
||||
machine.fail("nix flake metadata --json http://localhost/tags/latest.tar.gz?rev=493300eb13ae6fb387fbd47bf54a85915acc31c0")
|
||||
machine.fail("nix flake metadata --json http://localhost/tags/latest.tar.gz?revCount=789")
|
||||
machine.fail("nix flake metadata --json http://localhost/tags/latest.tar.gz?narHash=sha256-tbudgBSg+bHWHiHnlteNzN8TUvI80ygS9IULh4rklEw=")
|
||||
'';
|
||||
|
||||
}
|
||||
|
|
|
@ -3,12 +3,15 @@
|
|||
let
|
||||
pkgs = config.nodes.machine.nixpkgs.pkgs;
|
||||
|
||||
attacker = pkgs.runCommandWith {
|
||||
name = "attacker";
|
||||
stdenv = pkgs.pkgsStatic.stdenv;
|
||||
} ''
|
||||
$CC -static -o $out ${./attacker.c}
|
||||
'';
|
||||
attacker =
|
||||
pkgs.runCommandWith
|
||||
{
|
||||
name = "attacker";
|
||||
stdenv = pkgs.pkgsStatic.stdenv;
|
||||
}
|
||||
''
|
||||
$CC -static -o $out ${./attacker.c}
|
||||
'';
|
||||
|
||||
try-open-build-dir = pkgs.writeScript "try-open-build-dir" ''
|
||||
export PATH=${pkgs.coreutils}/bin:$PATH
|
||||
|
@ -55,75 +58,88 @@ in
|
|||
name = "sandbox-setuid-leak";
|
||||
|
||||
nodes.machine =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ virtualisation.writableStore = true;
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
virtualisation.writableStore = true;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
nix.nrBuildUsers = 1;
|
||||
virtualisation.additionalPaths = [ pkgs.busybox-sandbox-shell attacker try-open-build-dir create-hello-world pkgs.socat ];
|
||||
virtualisation.additionalPaths = [
|
||||
pkgs.busybox-sandbox-shell
|
||||
attacker
|
||||
try-open-build-dir
|
||||
create-hello-world
|
||||
pkgs.socat
|
||||
];
|
||||
boot.kernelPackages = pkgs.linuxPackages_latest;
|
||||
users.users.alice = {
|
||||
isNormalUser = true;
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
start_all()
|
||||
testScript =
|
||||
{ nodes }:
|
||||
''
|
||||
start_all()
|
||||
|
||||
with subtest("A builder can't give access to its build directory"):
|
||||
# Make sure that a builder can't change the permissions on its build
|
||||
# directory to the point of opening it up to external users
|
||||
with subtest("A builder can't give access to its build directory"):
|
||||
# Make sure that a builder can't change the permissions on its build
|
||||
# directory to the point of opening it up to external users
|
||||
|
||||
# A derivation whose builder tries to make its build directory as open
|
||||
# as possible and wait for someone to hijack it
|
||||
machine.succeed(r"""
|
||||
nix-build -v -E '
|
||||
builtins.derivation {
|
||||
name = "open-build-dir";
|
||||
system = builtins.currentSystem;
|
||||
builder = "${pkgs.busybox-sandbox-shell}/bin/sh";
|
||||
args = [ (builtins.storePath "${try-open-build-dir}") ];
|
||||
}' >&2 &
|
||||
""".strip())
|
||||
# A derivation whose builder tries to make its build directory as open
|
||||
# as possible and wait for someone to hijack it
|
||||
machine.succeed(r"""
|
||||
nix-build -v -E '
|
||||
builtins.derivation {
|
||||
name = "open-build-dir";
|
||||
system = builtins.currentSystem;
|
||||
builder = "${pkgs.busybox-sandbox-shell}/bin/sh";
|
||||
args = [ (builtins.storePath "${try-open-build-dir}") ];
|
||||
}' >&2 &
|
||||
""".strip())
|
||||
|
||||
# Wait for the build to be ready
|
||||
# This is OK because it runs as root, so we can access everything
|
||||
machine.wait_for_file("/tmp/nix-build-open-build-dir.drv-0/build/syncPoint")
|
||||
# Wait for the build to be ready
|
||||
# This is OK because it runs as root, so we can access everything
|
||||
machine.wait_for_file("/tmp/nix-build-open-build-dir.drv-0/build/syncPoint")
|
||||
|
||||
# But Alice shouldn't be able to access the build directory
|
||||
machine.fail("su alice -c 'ls /tmp/nix-build-open-build-dir.drv-0/build'")
|
||||
machine.fail("su alice -c 'touch /tmp/nix-build-open-build-dir.drv-0/build/bar'")
|
||||
machine.fail("su alice -c 'cat /tmp/nix-build-open-build-dir.drv-0/build/foo'")
|
||||
# But Alice shouldn't be able to access the build directory
|
||||
machine.fail("su alice -c 'ls /tmp/nix-build-open-build-dir.drv-0/build'")
|
||||
machine.fail("su alice -c 'touch /tmp/nix-build-open-build-dir.drv-0/build/bar'")
|
||||
machine.fail("su alice -c 'cat /tmp/nix-build-open-build-dir.drv-0/build/foo'")
|
||||
|
||||
# Tell the user to finish the build
|
||||
machine.succeed("echo foo > /tmp/nix-build-open-build-dir.drv-0/build/syncPoint")
|
||||
# Tell the user to finish the build
|
||||
machine.succeed("echo foo > /tmp/nix-build-open-build-dir.drv-0/build/syncPoint")
|
||||
|
||||
with subtest("Being able to execute stuff as the build user doesn't give access to the build dir"):
|
||||
machine.succeed(r"""
|
||||
nix-build -E '
|
||||
builtins.derivation {
|
||||
name = "innocent";
|
||||
system = builtins.currentSystem;
|
||||
builder = "${pkgs.busybox-sandbox-shell}/bin/sh";
|
||||
args = [ (builtins.storePath "${create-hello-world}") ];
|
||||
}' >&2 &
|
||||
""".strip())
|
||||
machine.wait_for_file("/tmp/nix-build-innocent.drv-0/build/syncPoint")
|
||||
with subtest("Being able to execute stuff as the build user doesn't give access to the build dir"):
|
||||
machine.succeed(r"""
|
||||
nix-build -E '
|
||||
builtins.derivation {
|
||||
name = "innocent";
|
||||
system = builtins.currentSystem;
|
||||
builder = "${pkgs.busybox-sandbox-shell}/bin/sh";
|
||||
args = [ (builtins.storePath "${create-hello-world}") ];
|
||||
}' >&2 &
|
||||
""".strip())
|
||||
machine.wait_for_file("/tmp/nix-build-innocent.drv-0/build/syncPoint")
|
||||
|
||||
# The build ran as `nixbld1` (which is the only build user on the
|
||||
# machine), but a process running as `nixbld1` outside the sandbox
|
||||
# shouldn't be able to touch the build directory regardless
|
||||
machine.fail("su nixbld1 --shell ${pkgs.busybox-sandbox-shell}/bin/sh -c 'ls /tmp/nix-build-innocent.drv-0/build'")
|
||||
machine.fail("su nixbld1 --shell ${pkgs.busybox-sandbox-shell}/bin/sh -c 'echo pwned > /tmp/nix-build-innocent.drv-0/build/result'")
|
||||
# The build ran as `nixbld1` (which is the only build user on the
|
||||
# machine), but a process running as `nixbld1` outside the sandbox
|
||||
# shouldn't be able to touch the build directory regardless
|
||||
machine.fail("su nixbld1 --shell ${pkgs.busybox-sandbox-shell}/bin/sh -c 'ls /tmp/nix-build-innocent.drv-0/build'")
|
||||
machine.fail("su nixbld1 --shell ${pkgs.busybox-sandbox-shell}/bin/sh -c 'echo pwned > /tmp/nix-build-innocent.drv-0/build/result'")
|
||||
|
||||
# Finish the build
|
||||
machine.succeed("echo foo > /tmp/nix-build-innocent.drv-0/build/syncPoint")
|
||||
# Finish the build
|
||||
machine.succeed("echo foo > /tmp/nix-build-innocent.drv-0/build/syncPoint")
|
||||
|
||||
# Check that the build was not affected
|
||||
machine.succeed(r"""
|
||||
cat ./result
|
||||
test "$(cat ./result)" = "hello, world"
|
||||
""".strip())
|
||||
'';
|
||||
# Check that the build was not affected
|
||||
machine.succeed(r"""
|
||||
cat ./result
|
||||
test "$(cat ./result)" = "hello, world"
|
||||
""".strip())
|
||||
'';
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue