From 2e96dea0217e26e01d282d6df0f476e55ef9b1c8 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Oct 2026 20:36:35 +0000 Subject: [PATCH 1/5] ci(packaging): install without weak dependencies in the smoke test - the dependencies of nm-sshuttle-gnome include openh264, fetched from Cisco's server, whose failure to answer failed a publish after the packages were built and signed - the only weak dependency of the packages themselves is iptables-nft for method=tproxy, which the test does not exercise Co-Authored-By: Claude Sonnet 5.5 --- packaging/smoke-test.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packaging/smoke-test.sh b/packaging/smoke-test.sh index 86a2930..c82f428 100755 --- a/packaging/smoke-test.sh +++ b/packaging/smoke-test.sh @@ -17,8 +17,10 @@ dnf -y install "$base/nm-sshuttle-release.noarch.rpm" # nm-sshuttle.repo points at the public site; follow the site under test # instead. --allowerasing: the container has systemd-standalone-tmpfiles, # which conflicts with the systemd that systemd-resolved needs; a real system -# has the full systemd. -dnf -y install --allowerasing --setopt="nm-sshuttle.baseurl=$base/rpm/fedora/\$releasever/\$basearch/" \ +# has the full systemd. No weak dependencies: GTK's media codecs include +# openh264, which comes from a third-party host that a hosted runner fails to +# reach now and then, and nothing here uses them. +dnf -y install --allowerasing --setopt=install_weak_deps=False --setopt="nm-sshuttle.baseurl=$base/rpm/fedora/\$releasever/\$basearch/" \ nm-sshuttle nm-sshuttle-gnome rpm -q --qf '%{NAME}-%{VERSION}-%{RELEASE}: %{SIGPGP:pgpsig}\n' \ From 8fb2ec291cd78bcb38a3d2017f5624902085d6e4 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Oct 2026 20:36:52 +0000 Subject: [PATCH 2/5] chore: set the version to 0.1.0 - meson project, Python package, both RPM specs and the Debian changelog drop the development suffix - the editor's test protocol builds the same version Co-Authored-By: Claude Sonnet 5.5 --- debian/changelog | 2 +- meson.build | 2 +- nm_sshuttle/__init__.py | 2 +- packaging/rpm/nm-sshuttle-gnome.spec | 4 ++-- packaging/rpm/nm-sshuttle.spec | 4 ++-- test-vm/gnome-editor-protocol.md | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/debian/changelog b/debian/changelog index ba3ee45..e7ac5a8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nm-sshuttle (0.1.0~dev0-1) unstable; urgency=medium +nm-sshuttle (0.1.0-1) unstable; urgency=medium * Initial package. diff --git a/meson.build b/meson.build index 0d4297d..a4306bc 100644 --- a/meson.build +++ b/meson.build @@ -7,7 +7,7 @@ # Paths follow design ยง4.1. NetworkManager's directories are fixed under # /usr/lib, whatever the prefix: NM looks for VPN plugins and its packaged # conf.d nowhere else. -project('nm-sshuttle', version: '0.1.0.dev0', license: 'MIT', meson_version: '>= 0.64') +project('nm-sshuttle', version: '0.1.0', license: 'MIT', meson_version: '>= 0.64') python = import('python').find_installation('python3') prefix = get_option('prefix') diff --git a/nm_sshuttle/__init__.py b/nm_sshuttle/__init__.py index b1ee59d..28cda9f 100644 --- a/nm_sshuttle/__init__.py +++ b/nm_sshuttle/__init__.py @@ -1,4 +1,4 @@ # SPDX-License-Identifier: MIT """NetworkManager VPN service plugin for sshuttle (docs/design.md).""" -__version__ = "0.1.0.dev0" +__version__ = "0.1.0" diff --git a/packaging/rpm/nm-sshuttle-gnome.spec b/packaging/rpm/nm-sshuttle-gnome.spec index 69d4e2e..40f2a62 100644 --- a/packaging/rpm/nm-sshuttle-gnome.spec +++ b/packaging/rpm/nm-sshuttle-gnome.spec @@ -3,7 +3,7 @@ # The editor for GNOME Settings, from the same tarball as nm-sshuttle.spec. It # has its own spec because it is compiled code and nm-sshuttle is noarch. Name: nm-sshuttle-gnome -Version: 0.1.0~dev0 +Version: 0.1.0 Release: 1%{?dist} Summary: GNOME Settings editor for nm-sshuttle profiles License: MIT @@ -53,5 +53,5 @@ xvfb-run -a %{__meson} test -C %{_vpath_builddir} --no-rebuild --print-errorlogs %{_libdir}/NetworkManager/libnm-vpn-plugin-sshuttle.so %changelog -* Sun Oct 11 2026 Dennis Klein - 0.1.0~dev0-1 +* Sun Oct 11 2026 Dennis Klein - 0.1.0-1 - Initial package diff --git a/packaging/rpm/nm-sshuttle.spec b/packaging/rpm/nm-sshuttle.spec index ba13a96..5ca8fa2 100644 --- a/packaging/rpm/nm-sshuttle.spec +++ b/packaging/rpm/nm-sshuttle.spec @@ -2,7 +2,7 @@ %global nm_libdir %{_prefix}/lib/NetworkManager Name: nm-sshuttle -Version: 0.1.0~dev0 +Version: 0.1.0 Release: 1%{?dist} Summary: NetworkManager VPN plugin that tunnels with sshuttle License: MIT @@ -82,5 +82,5 @@ fi %{_unitdir}/nm-sshuttle-tunnel@.service %changelog -* Sat Oct 10 2026 Dennis Klein - 0.1.0~dev0-1 +* Sat Oct 10 2026 Dennis Klein - 0.1.0-1 - Initial package diff --git a/test-vm/gnome-editor-protocol.md b/test-vm/gnome-editor-protocol.md index e59b633..e729493 100644 --- a/test-vm/gnome-editor-protocol.md +++ b/test-vm/gnome-editor-protocol.md @@ -29,7 +29,7 @@ than "Expect" is a finding, even if it looks harmless: write down what you saw. $ sudo dnf install git rpm-build dnf5-plugins $ git clone -b claude/project-thread-c5oyfl https://github.com/dennisklein/nm-sshuttle ~/src/nm-sshuttle $ cd ~/src/nm-sshuttle -$ version=0.1.0~dev0 +$ version=0.1.0 $ mkdir -p ~/rpmbuild/SOURCES $ git archive --format=tar.gz --prefix="nm-sshuttle-$version/" \ -o ~/rpmbuild/SOURCES/"nm-sshuttle-$version.tar.gz" HEAD From f3227e90668f5257a4bbabe776ba5f27060b411f Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Oct 2026 20:37:00 +0000 Subject: [PATCH 3/5] docs: add a changelog with the 0.1.0 entry - list what the first release contains and its known limits Co-Authored-By: Claude Sonnet 5.5 --- CHANGELOG.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..efa411b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,48 @@ +# Changelog + +All notable changes to nm-sshuttle are listed here. The format follows +[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project +uses [semantic versioning](https://semver.org/). + +## [0.1.0] - 2026-10-11 + +The first release. + +### Added + +- NetworkManager VPN plugin that runs an sshuttle tunnel, so the tunnel is a + toggle in GNOME Quick Settings and a connection in `nmcli`. sshuttle runs + as root in its own systemd unit; only `ssh` runs as the user, with their + own `~/.ssh/config`, `ProxyJump`, `known_hosts` and agent. +- Fail-closed guard: traffic to the tunnelled networks is blocked while the + tunnel is down. +- Lifecycle handling: reconnect with backoff after suspend, roaming, a + captive portal, a dropped connection or a locked screen; health checks, + with an optional `probe`, notice a tunnel that is up but stuck; another + VPN's activation triggers an immediate reconnect. +- Split DNS through systemd-resolved, or all lookups through the tunnel. +- IPv4 and IPv6 networks, exclusions and first hops. +- UDP through the tunnel with `method=tproxy`. +- Up to 8 tunnels at once, one plugin instance per activation; a profile that + conflicts with an active one is refused. +- The `nm-sshuttle` command with `add`, `check`, `list` and `remove` to + manage profiles as the user. +- GTK4 editor for GNOME Settings (`nm-sshuttle-gnome`), validating profiles + with the same rules as the plugin. +- Packages: RPMs for Fedora 43 and 44 from a signed dnf repository on GitHub + Pages (`nm-sshuttle-release` sets it up), and Debian 13 and Ubuntu 26.04 + packages built by CI. +- User guide and design documentation, a lab that checks the sshuttle and + kernel behaviour the design relies on, and VM tests that run in CI. + +### Known limits + +- The tunnel's DNS needs systemd-resolved. Without it (NetworkManager + writing `/etc/resolv.conf` itself), `dns split` sends every lookup to the + tunnel's resolvers, and a resolver entry that NetworkManager fails to + remove can stay until it restarts. The case is described in the design + (section 4.5) but not tested on a VM. +- There is no Debian or Ubuntu package repository; take the `.deb` files + from a CI run. + +[0.1.0]: https://github.com/dennisklein/nm-sshuttle/releases/tag/v0.1.0 From 3e37369c8d169e99c7aa418ece079990812cf43f Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Oct 2026 20:37:10 +0000 Subject: [PATCH 4/5] docs(packaging): list the files that carry the version before a release Co-Authored-By: Claude Sonnet 5.5 --- packaging/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packaging/README.md b/packaging/README.md index 73ffd88..be5e475 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -37,7 +37,9 @@ with a throwaway key and deploy nothing. ### Releasing -Push an annotated tag whose version is the release's: +Merge the release's version into `main` first: `meson.build`, +`nm_sshuttle/__init__.py`, the two specs, `debian/changelog` and +`CHANGELOG.md`. Then push an annotated tag whose version is the release's: ```console $ git tag -a v0.1.0 -m 'nm-sshuttle 0.1.0' From 054dc565b8cf2a7568e951459450d855c880e5e1 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Oct 2026 20:38:47 +0000 Subject: [PATCH 5/5] chore: use the maintainer's institutional address - the RPM and Debian changelogs, the Debian maintainer and the default user ID of scripts/signing-key.sh name d.klein@gsi.de Co-Authored-By: Claude Sonnet 5.5 --- debian/changelog | 2 +- debian/control | 2 +- packaging/nm-sshuttle-release/nm-sshuttle-release.spec | 2 +- packaging/rpm/nm-sshuttle-gnome.spec | 2 +- packaging/rpm/nm-sshuttle.spec | 2 +- scripts/signing-key.sh | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/debian/changelog b/debian/changelog index e7ac5a8..697d851 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,4 +2,4 @@ nm-sshuttle (0.1.0-1) unstable; urgency=medium * Initial package. - -- Dennis Klein Sat, 10 Oct 2026 20:00:00 +0000 + -- Dennis Klein Sat, 10 Oct 2026 20:00:00 +0000 diff --git a/debian/control b/debian/control index 4e05851..365ba97 100644 --- a/debian/control +++ b/debian/control @@ -1,7 +1,7 @@ Source: nm-sshuttle Section: net Priority: optional -Maintainer: Dennis Klein +Maintainer: Dennis Klein Build-Depends: debhelper-compat (= 13), dh-python, diff --git a/packaging/nm-sshuttle-release/nm-sshuttle-release.spec b/packaging/nm-sshuttle-release/nm-sshuttle-release.spec index 8a7add2..c93cc67 100644 --- a/packaging/nm-sshuttle-release/nm-sshuttle-release.spec +++ b/packaging/nm-sshuttle-release/nm-sshuttle-release.spec @@ -31,5 +31,5 @@ install -Dpm 0644 %{SOURCE1} %{buildroot}%{_sysconfdir}/pki/rpm-gpg/RPM-GPG-KEY- %{_sysconfdir}/pki/rpm-gpg/RPM-GPG-KEY-nm-sshuttle %changelog -* Sun Oct 11 2026 Dennis Klein - 1-1 +* Sun Oct 11 2026 Dennis Klein - 1-1 - Initial package diff --git a/packaging/rpm/nm-sshuttle-gnome.spec b/packaging/rpm/nm-sshuttle-gnome.spec index 40f2a62..4420f47 100644 --- a/packaging/rpm/nm-sshuttle-gnome.spec +++ b/packaging/rpm/nm-sshuttle-gnome.spec @@ -53,5 +53,5 @@ xvfb-run -a %{__meson} test -C %{_vpath_builddir} --no-rebuild --print-errorlogs %{_libdir}/NetworkManager/libnm-vpn-plugin-sshuttle.so %changelog -* Sun Oct 11 2026 Dennis Klein - 0.1.0-1 +* Sun Oct 11 2026 Dennis Klein - 0.1.0-1 - Initial package diff --git a/packaging/rpm/nm-sshuttle.spec b/packaging/rpm/nm-sshuttle.spec index 5ca8fa2..ee50b74 100644 --- a/packaging/rpm/nm-sshuttle.spec +++ b/packaging/rpm/nm-sshuttle.spec @@ -82,5 +82,5 @@ fi %{_unitdir}/nm-sshuttle-tunnel@.service %changelog -* Sat Oct 10 2026 Dennis Klein - 0.1.0-1 +* Sat Oct 10 2026 Dennis Klein - 0.1.0-1 - Initial package diff --git a/scripts/signing-key.sh b/scripts/signing-key.sh index b78a078..f897b8d 100755 --- a/scripts/signing-key.sh +++ b/scripts/signing-key.sh @@ -35,11 +35,11 @@ # the next publish sign everything with the new key. # 3. After that publish, --retire removes the old key. # -# Env: NM_SSHUTTLE_SIGNING_UID key user ID (default: nm-sshuttle package signing ) +# Env: NM_SSHUTTLE_SIGNING_UID key user ID (default: nm-sshuttle package signing ) # NM_SSHUTTLE_REPO GitHub repository (default: dennisklein/nm-sshuttle) set -euo pipefail -uid=${NM_SSHUTTLE_SIGNING_UID:-nm-sshuttle package signing } +uid=${NM_SSHUTTLE_SIGNING_UID:-nm-sshuttle package signing } repo=${NM_SSHUTTLE_REPO:-dennisklein/nm-sshuttle} environment=rpm-signing secret=RPM_SIGNING_KEY