diff options
| -rwxr-xr-x | scripts/import-wireguard-configs.sh | 8 | ||||
| -rw-r--r-- | tests/import-wireguard-configs/fake-nmcli | 3 | ||||
| -rw-r--r-- | tests/import-wireguard-configs/test_import_wireguard_configs.py | 22 |
3 files changed, 30 insertions, 3 deletions
diff --git a/scripts/import-wireguard-configs.sh b/scripts/import-wireguard-configs.sh index 9e42033..e1db5a6 100755 --- a/scripts/import-wireguard-configs.sh +++ b/scripts/import-wireguard-configs.sh @@ -55,11 +55,13 @@ for conf in "$dir"/*.conf; do echo " $out" >&2 exit 1 fi + # nmcli import auto-activates a full-tunnel (0.0.0.0/0) profile. Bring it + # down FIRST, before the rename/modify that could fail under set -e, so a + # failed modify can never leave a live unasked-for VPN up. A profile that + # didn't activate makes this a harmless no-op. + nmcli connection down "$uuid" >/dev/null 2>&1 || true nmcli connection modify "$uuid" connection.id "$name" \ connection.autoconnect no - # nmcli import auto-activates; bring it back down so importing never leaves - # a tunnel up. A profile that didn't activate makes this a harmless no-op. - nmcli connection down "$uuid" >/dev/null 2>&1 || true echo "imported: $name (inactive, autoconnect off, iface wgpvpn)" done [ "$found" = 1 ] || { echo "no .conf files in $dir" >&2; exit 1; } diff --git a/tests/import-wireguard-configs/fake-nmcli b/tests/import-wireguard-configs/fake-nmcli index 45b88cd..30de62f 100644 --- a/tests/import-wireguard-configs/fake-nmcli +++ b/tests/import-wireguard-configs/fake-nmcli @@ -38,6 +38,9 @@ case "$1 $2" in "connection modify") exit "${FAKE_NMCLI_MODIFY_RC:-0}" ;; +"connection down") + exit "${FAKE_NMCLI_DOWN_RC:-0}" + ;; *) echo "fake-nmcli: unexpected args: $*" >&2 exit 99 diff --git a/tests/import-wireguard-configs/test_import_wireguard_configs.py b/tests/import-wireguard-configs/test_import_wireguard_configs.py index 0307041..45afa54 100644 --- a/tests/import-wireguard-configs/test_import_wireguard_configs.py +++ b/tests/import-wireguard-configs/test_import_wireguard_configs.py @@ -162,6 +162,28 @@ class ImportWireguardConfigs(unittest.TestCase): imports = [ln for ln in self.log_lines() if ln.startswith("connection import")] self.assertEqual(len(imports), 1) + def test_tunnel_is_brought_down_before_the_modify(self): + # nmcli import auto-activates a full-tunnel (0.0.0.0/0) profile. The + # down must run before the rename/modify so a failed modify under set -e + # can never leave a live unasked-for VPN up. + self.write_conf("USNY") + r = self.run_script() + self.assertEqual(r.returncode, 0, r.stderr) + verbs = [ln.split()[1] for ln in self.log_lines() + if ln.startswith("connection ")] + self.assertEqual(verbs, ["import", "down", "modify"], verbs) + + def test_modify_failure_still_left_the_tunnel_down(self): + # Even when the modify fails and aborts the run, the down already ran, + # so no live tunnel survives. + self.write_conf("USNY") + r = self.run_script(env_extra={"FAKE_NMCLI_MODIFY_RC": "4"}) + self.assertNotEqual(r.returncode, 0) + verbs = [ln.split()[1] for ln in self.log_lines() + if ln.startswith("connection ")] + self.assertIn("down", verbs, "the tunnel must be downed before the modify aborts") + self.assertLess(verbs.index("down"), verbs.index("modify")) + if __name__ == "__main__": unittest.main() |
