From a7bb8ca7cb4f856d5c9d54656f066d61c06c173b Mon Sep 17 00:00:00 2001 From: Eric Rodrigues Pires Date: Sat, 4 Apr 2026 12:40:50 -0300 Subject: [PATCH] Add sandhole-websites test --- nix/checks.nix | 4 + nix/modules/tests/blacklist.nix | 10 +-- nix/modules/tests/websites.nix | 150 ++++++++++++++++++++++++++++++++ src/entrypoint.rs | 14 +++ 4 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 nix/modules/tests/websites.nix diff --git a/nix/checks.nix b/nix/checks.nix index c64466e..1f7fc73 100644 --- a/nix/checks.nix +++ b/nix/checks.nix @@ -107,4 +107,8 @@ sandhole-module-test-with-container = pkgs.testers.runNixOSTest ( import ./modules/tests/with-container.nix { inherit pkgs sandhole; } ); + + sandhole-module-test-websites = pkgs.testers.runNixOSTest ( + import ./modules/tests/websites.nix { inherit pkgs sandhole; } + ); } diff --git a/nix/modules/tests/blacklist.nix b/nix/modules/tests/blacklist.nix index c3533d2..9f1b156 100644 --- a/nix/modules/tests/blacklist.nix +++ b/nix/modules/tests/blacklist.nix @@ -21,7 +21,6 @@ in # The reverse proxy running Sandhole. sandhole = { lib, ... }: - with lib; { imports = [ ../sandhole.nix ]; virtualisation.vlans = [ 10 ]; @@ -36,7 +35,7 @@ in prefixLength = 24; } ]; - routes = mkForce [ + routes = lib.mkForce [ { address = "0.0.0.0"; prefixLength = 0; @@ -50,6 +49,7 @@ in "8.8.4.4" ]; }; + services.sandhole = { enable = true; package = sandhole; @@ -68,7 +68,6 @@ in # The server that will be proxied via SSH. server = { lib, ... }: - with lib; { virtualisation.vlans = [ 10 ]; networking = { @@ -82,7 +81,7 @@ in prefixLength = 24; } ]; - routes = mkForce [ + routes = lib.mkForce [ { address = "0.0.0.0"; prefixLength = 0; @@ -130,7 +129,6 @@ in # The client that will be blocked from accessing Sandhole. blocked = { lib, ... }: - with lib; { virtualisation.vlans = [ 10 ]; networking = { @@ -144,7 +142,7 @@ in prefixLength = 24; } ]; - routes = mkForce [ + routes = lib.mkForce [ { address = "0.0.0.0"; prefixLength = 0; diff --git a/nix/modules/tests/websites.nix b/nix/modules/tests/websites.nix new file mode 100644 index 0000000..70a5d25 --- /dev/null +++ b/nix/modules/tests/websites.nix @@ -0,0 +1,150 @@ +# Set up a Sandhole server with HTTPS certificates, +# and connect to it from a different host with the custom +# sandhole-websites module. + +{ pkgs, sandhole, ... }: + +let + pubKeys = "${../../../tests/data/user_keys}"; + privKey = "${../../../tests/data/private_keys/key1}"; + adminKey = "${../../../tests/data/private_keys/admin}"; + + sandholeCerts = import ./generate-certs.nix { + inherit pkgs; + domain = "sandhole.nix"; + }; +in + +{ + name = "sandhole-module-test-websites"; + + nodes = { + # The reverse proxy running Sandhole. + sandhole = + { lib, ... }: + { + imports = [ ../sandhole.nix ]; + virtualisation.vlans = [ 10 ]; + networking = { + useDHCP = false; + interfaces.eth1 = { + useDHCP = false; + ipv4 = { + addresses = [ + { + address = "192.168.10.10"; + prefixLength = 24; + } + ]; + routes = lib.mkForce [ + { + address = "0.0.0.0"; + prefixLength = 0; + via = "192.168.10.1"; + } + ]; + }; + }; + nameservers = [ + "8.8.8.8" + "8.8.4.4" + ]; + }; + + environment.etc.admin_key = { + source = adminKey; + mode = "0400"; + }; + + services.sandhole = { + enable = true; + package = sandhole; + openFirewall = true; + settings = { + no-domain = true; + user-keys-directory = pubKeys; + certificates-directory = sandholeCerts; + bind-hostnames = "all"; + force-https = true; + }; + }; + }; + + # The server that will be proxied via SSH. + server = + { lib, ... }: + { + imports = [ ../sandhole-websites.nix ]; + virtualisation.vlans = [ 10 ]; + networking = { + useDHCP = false; + interfaces.eth1 = { + useDHCP = false; + ipv4 = { + addresses = [ + { + address = "192.168.10.20"; + prefixLength = 24; + } + ]; + routes = lib.mkForce [ + { + address = "0.0.0.0"; + prefixLength = 0; + via = "192.168.10.1"; + } + ]; + }; + }; + }; + + services.openssh.enable = true; + + environment.etc.ssh_key = { + source = privKey; + mode = "0400"; + }; + + sandhole.websites.example-website = { + authorizedKeys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDpmDGLbC68yM87r+fD/aoEimDdnzZtmnZXCnxkIGHMq admin" + ]; + domains = [ "example.sandhole.nix" ]; + hostAddress6 = "fc00::2:1"; + localAddress6 = "fc00::2:2"; + autosshExtraArguments = "-o ServerAliveInterval=30 -c aes256-gcm@openssh.com"; + sandholeHost = "192.168.10.10"; + sandholePort = 2222; + sandholeKeyPath = "/etc/ssh_key"; + }; + }; + }; + + testScript = '' + sandhole.start() + sandhole.wait_for_unit("sandhole.service") + sandhole.wait_for_open_port(2222) + + with subtest("add index.html to server"): + server.start() + server.wait_for_open_port(22) + sandhole.succeed( + "${pkgs.openssh}/bin/ssh" + " -i /etc/admin_key" + " -o StrictHostKeyChecking=accept-new" + " example-website@192.168.10.20" + " 'echo \"Hello from NGINX!\" > /home/example-website/www/index.html'" + ) + + with subtest("connect to Sandhole"): + server.wait_for_unit("autossh-example-website.service") + server.wait_until_succeeds( + "${pkgs.curl}/bin/curl --fail" + " --resolve example.sandhole.nix:443:192.168.10.10" + " --cacert ${sandholeCerts}/ca.cert.pem" + " https://example.sandhole.nix" + " | grep 'Hello from NGINX!'", + timeout=30, + ) + ''; +} diff --git a/src/entrypoint.rs b/src/entrypoint.rs index 99845a4..0a96f96 100644 --- a/src/entrypoint.rs +++ b/src/entrypoint.rs @@ -90,6 +90,20 @@ pub async fn entrypoint(config: ApplicationConfig) -> color_eyre::Result<()> { ) .into()); } + if config.force_https { + if config.disable_http { + return Err(ServerError::InvalidConfig( + "--force-https is incompatible with --disable-http".into(), + ) + .into()); + } + if config.disable_https { + return Err(ServerError::InvalidConfig( + "--force-https is incompatible with --disable-https".into(), + ) + .into()); + } + } if config.domain.no_domain { if config.allow_requested_subdomains { #[cfg(not(coverage_nightly))] -- 2.51.2