Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package netbird for openSUSE:Factory checked in at 2026-07-06 12:29:32 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/netbird (Old) and /work/SRC/openSUSE:Factory/.netbird.new.1982 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "netbird" Mon Jul 6 12:29:32 2026 rev:36 rq:1363740 version:0.74.2 Changes: -------- --- /work/SRC/openSUSE:Factory/netbird/netbird.changes 2026-07-02 20:14:01.922897679 +0200 +++ /work/SRC/openSUSE:Factory/.netbird.new.1982/netbird.changes 2026-07-06 12:31:08.316903492 +0200 @@ -1,0 +2,15 @@ +Fri Jul 3 18:47:18 UTC 2026 - Marcus Rueckert <[email protected]> + +- Update to 0.74.2 + - [management] Add vLLM e2e test by @braginini in #6649 + - [misc] Fix GHCR image push after dockers_v2 migration by + @mlsmaycon in #6653 + - [client] Increase management client gRPC receive limit default + to 16MB by @riccardomanfrin in #6641 + - [client] Fix slow wg operations by @pappz in #6633 + - [client] backport enforce a single selected exit node by @pappz + in #6640 + - [client] Fix backoff.Ticker goroutine leak in reconnect guard + by @theodorsm in #6663 + +------------------------------------------------------------------- Old: ---- netbird-0.74.1.obscpio New: ---- netbird-0.74.2.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ netbird.spec ++++++ --- /var/tmp/diff_new_pack.DWhuTn/_old 2026-07-06 12:31:10.736987484 +0200 +++ /var/tmp/diff_new_pack.DWhuTn/_new 2026-07-06 12:31:10.740987623 +0200 @@ -32,7 +32,7 @@ %bcond_with stub_config Name: netbird -Version: 0.74.1 +Version: 0.74.2 Release: 0 Summary: Mesh VPN based on WireGuard License: AGPL-3.0-only AND BSD-3-Clause ++++++ _service ++++++ --- /var/tmp/diff_new_pack.DWhuTn/_old 2026-07-06 12:31:10.784989150 +0200 +++ /var/tmp/diff_new_pack.DWhuTn/_new 2026-07-06 12:31:10.788989289 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/netbirdio/netbird.git</param> <param name="scm">git</param> <param name="package-meta">yes</param> - <param name="revision">refs/tags/v0.74.1</param> + <param name="revision">refs/tags/v0.74.2</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">disable</param> ++++++ netbird-0.74.1.obscpio -> netbird-0.74.2.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/FETCH_HEAD new/netbird-0.74.2/.git/FETCH_HEAD --- old/netbird-0.74.1/.git/FETCH_HEAD 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/FETCH_HEAD 2026-07-03 12:23:11.000000000 +0200 @@ -1,4 +1,4 @@ -1e0e04d65fdbe2afb5e4a301f0f81840bf833f37 not-for-merge branch '0.75.0-branch' of https://github.com/netbirdio/netbird +d099534dca0151c0f9d2ca4c18ffeef14e3f6bfd not-for-merge branch '0.75.0-branch' of https://github.com/netbirdio/netbird 1e24916daca9d8315064f0047b10cb47297ae16d not-for-merge branch 'account-refactoring' of https://github.com/netbirdio/netbird 3945d2b170f84b90a9997df77bd7c8889c061de2 not-for-merge branch 'add-account-onboarding' of https://github.com/netbirdio/netbird 7fbe2946ef59b3070e46f102802f4457627c53f6 not-for-merge branch 'add-arm-to-ci' of https://github.com/netbirdio/netbird @@ -12,7 +12,6 @@ b3cf615e51c8c130f36783682bbfb61556a74275 not-for-merge branch 'add-steamos-support' of https://github.com/netbirdio/netbird c2180e4bb2881455d7f721e5d7659d97ea83faae not-for-merge branch 'add/race-test' of https://github.com/netbirdio/netbird 11d1ca6fbc0b2f3b55dcf3d2036e47d2ce94608b not-for-merge branch 'apply-routes-early' of https://github.com/netbirdio/netbird -415eb59ef53b4ec953cc2b5a4fb7b99457049497 not-for-merge branch 'backport/single-exit-node' of https://github.com/netbirdio/netbird 036a3020fe8a2a06bee2959c0d802e96f7b54a41 not-for-merge branch 'batch-wg-ops' of https://github.com/netbirdio/netbird 3d4ddd53f30cb563556e63c4cfc316f7108f0f8c not-for-merge branch 'bind-ipv6' of https://github.com/netbirdio/netbird 0aa5eaaf5b50878924dd280d04595adeb29f3c4b not-for-merge branch 'braginini/wasm' of https://github.com/netbirdio/netbird @@ -53,8 +52,8 @@ 0cf6ece217c3d2dcf9a05351679b3d71dc081904 not-for-merge branch 'debug-keycloak-idp' of https://github.com/netbirdio/netbird 26ed186111c9d177488900f8237a93bc45a1f281 not-for-merge branch 'debug-local-records' of https://github.com/netbirdio/netbird 24053750d90dbfc381fcbca9c9925443f51a4d8b not-for-merge branch 'debug-user-role' of https://github.com/netbirdio/netbird -9dec2bcdcdaa175208a7b95da99a17b02df6fc1f not-for-merge branch 'dependabot/github_actions/actions-1fec7beb7c' of https://github.com/netbirdio/netbird -3d59ab9730ba0c2662901eab4c947e4dcfda0474 not-for-merge branch 'dependabot/go_modules/aws-sdk-8f849ebaed' of https://github.com/netbirdio/netbird +8c5a20b04546e1e6a1bc896118334276a1a26987 not-for-merge branch 'dependabot/github_actions/actions-c97fa3f10c' of https://github.com/netbirdio/netbird +a721675b11767b2771121760ae2dbdc00e67e300 not-for-merge branch 'dependabot/go_modules/aws-sdk-8f849ebaed' of https://github.com/netbirdio/netbird 52c7822e40bbd23b65921586453531a6034098d1 not-for-merge branch 'dependabot/go_modules/github.com/Azure/go-ntlmssp-0.1.1' of https://github.com/netbirdio/netbird d9bf8cfa6db5615b767b734576deb5c2c133d66c not-for-merge branch 'dependabot/go_modules/github.com/aws/aws-sdk-go-v2/service/s3-1.104.2' of https://github.com/netbirdio/netbird e26b4808d51e4294d8c673a2a0fb86d5cd270546 not-for-merge branch 'dependabot/go_modules/github.com/coreos/go-oidc/v3-3.19.0' of https://github.com/netbirdio/netbird @@ -69,11 +68,11 @@ 47e7b1203e023fdd8754bba64c23443450f2712c not-for-merge branch 'dependabot/go_modules/goauthentik.io/api/v3-3.2026050.3' of https://github.com/netbirdio/netbird cab5bba7f59ab68fe3e8d4459ed37a1dd191f7ce not-for-merge branch 'dependabot/go_modules/golang.org/x/image-0.38.0' of https://github.com/netbirdio/netbird 1827b75f9f3987f2c475540701b462223a5fb2d5 not-for-merge branch 'dependabot/go_modules/golang.org/x/sys-0.46.0' of https://github.com/netbirdio/netbird -1d7a2a5ace003824e2cea472b9c815f901b0c15c not-for-merge branch 'dependabot/go_modules/gorm-2271c8195b' of https://github.com/netbirdio/netbird -92a949ef5a935af8485de0361c32a682a9c06770 not-for-merge branch 'dependabot/go_modules/otel-e34c790afd' of https://github.com/netbirdio/netbird -d8e98f4fb51f476cccbe0e771ea0041954b0bd5d not-for-merge branch 'dependabot/go_modules/pion-5f703e1eca' of https://github.com/netbirdio/netbird -f14100f1ab2a1a502a7bfd3b19af6ff6bb8faf1f not-for-merge branch 'dependabot/go_modules/testcontainers-de325c0dd6' of https://github.com/netbirdio/netbird -af04a89eee82e2b02bd4ae09d41677b89426cd28 not-for-merge branch 'dependabot/go_modules/wireguard-dbd6b95108' of https://github.com/netbirdio/netbird +d77d78720c57ac6e1ae613f1f171bc9911e45549 not-for-merge branch 'dependabot/go_modules/gorm-2271c8195b' of https://github.com/netbirdio/netbird +94e6c40446f8ba80930319cd25fbf15d554272a7 not-for-merge branch 'dependabot/go_modules/otel-e34c790afd' of https://github.com/netbirdio/netbird +5a2660e796bf697dd0c00c09bc0c2338e93c4695 not-for-merge branch 'dependabot/go_modules/pion-5f703e1eca' of https://github.com/netbirdio/netbird +75ac15c52e36877590418a260f31880b75a412a9 not-for-merge branch 'dependabot/go_modules/testcontainers-de325c0dd6' of https://github.com/netbirdio/netbird +479a88ca9f58cdd095beb7d05bcc393d3d1b7cb1 not-for-merge branch 'dependabot/go_modules/wireguard-dbd6b95108' of https://github.com/netbirdio/netbird c714b9129a373d87a79c859bc66cab4e5e200f7c not-for-merge branch 'dependabot/npm_and_yarn/proxy/web/npm_and_yarn-2f40f34922' of https://github.com/netbirdio/netbird 8c44187900ec87c8d484881d4e25ad253d73a168 not-for-merge branch 'deploy/peer-performance' of https://github.com/netbirdio/netbird 93c0172c8afca58da00823e8a0b3ee831e746832 not-for-merge branch 'deploy/permissions-account' of https://github.com/netbirdio/netbird @@ -103,7 +102,7 @@ 98f3012fb3c2e5605b24387ddd8c2c7e187164a7 not-for-merge branch 'fake-addr' of https://github.com/netbirdio/netbird 7474432bea4fdb8b8d05e701c352c7a08ef23a38 not-for-merge branch 'feat-client-side-acl' of https://github.com/netbirdio/netbird 4246138e4145846c24a435326954a2abf97a71e4 not-for-merge branch 'feat-groups-from-jwt' of https://github.com/netbirdio/netbird -520370a8b0723d9fd819590646cce5d0a2d6bc57 not-for-merge branch 'feat/admin-cli' of https://github.com/netbirdio/netbird +f25011f9ca520ec3c97c909ca2201f149af0c4f6 not-for-merge branch 'feat/admin-cli' of https://github.com/netbirdio/netbird 74eebeb95a3ef2e065cbda37cbde2e289a50c4e6 not-for-merge branch 'feat/auto-update-2' of https://github.com/netbirdio/netbird bdf22d0d1f33e24bb0fe79ff2a5595b41a1cd157 not-for-merge branch 'feat/auto-upgrade' of https://github.com/netbirdio/netbird de0dc9bf935d7732acd037a7047df9388f8ab610 not-for-merge branch 'feat/aws-integration' of https://github.com/netbirdio/netbird @@ -241,9 +240,9 @@ 4b5e39c574f874969abbb484423fb72d093bbf24 not-for-merge branch 'fix/remove-otel-units' of https://github.com/netbirdio/netbird e3c66ced13de40333962f4a1e738b32b4335d2f2 not-for-merge branch 'fix/revert-ice-filter' of https://github.com/netbirdio/netbird 9be7e33a07b501799581d77949a2607fab5bb7c9 not-for-merge branch 'fix/route' of https://github.com/netbirdio/netbird +e22976a89e7f2d6c2a5fa4583be9a24b01c63dbf not-for-merge branch 'fix/routeselector-atomic-exit-node' of https://github.com/netbirdio/netbird 4a4d506221da3a6929a8bc2c96c541e37bec6a9f not-for-merge branch 'fix/signal-watchdog-sync-stop' of https://github.com/netbirdio/netbird 4642233b839ee228b9c5898e087bede8511997cb not-for-merge branch 'fix/skip-restart-unchanged-route' of https://github.com/netbirdio/netbird -e55b252765179383444c746343b4b41ef2ec63e8 not-for-merge branch 'fix/slow-wg-operations' of https://github.com/netbirdio/netbird dde4693fdd2d24090d26768f23bd2f03cff61f3c not-for-merge branch 'fix/sync-peer-race' of https://github.com/netbirdio/netbird 782a8cb13036db0a5eecf8296d8cb5ef51a8760f not-for-merge branch 'fix/systemd-service-logs' of https://github.com/netbirdio/netbird e59223c81f2e16ab4fe7cc6c86ef227d0e7a0f8d not-for-merge branch 'fix/test-freebsd' of https://github.com/netbirdio/netbird @@ -269,18 +268,17 @@ 97ad3307ddb9e07f40a71eaa9489ca74947a6791 not-for-merge branch 'log/conn-disconn' of https://github.com/netbirdio/netbird a69dc29e7e7e24cf6cf7746632d7b8046c0a70e7 not-for-merge branch 'log/getaccount-by-peer' of https://github.com/netbirdio/netbird 0886b67ce951e5827d87571ac079b6f516027915 not-for-merge branch 'logs/peerlogs-addpeer' of https://github.com/netbirdio/netbird -1dfa85a917eb47e23e4dc4c142056e67966a1c03 not-for-merge branch 'main' of https://github.com/netbirdio/netbird +3aa6c02b932db503e82f9530dddfe95d5ea212c4 not-for-merge branch 'main' of https://github.com/netbirdio/netbird b03343bc4d249af295a4833161289d8339a0052a not-for-merge branch 'manual-peer-logout' of https://github.com/netbirdio/netbird b2c5732847ae5c22ab8f526204d9f121df72869e not-for-merge branch 'mdm_integration' of https://github.com/netbirdio/netbird 6efc1a61fe8568c3ae0704329aa2589c537e801b not-for-merge branch 'merged-fixes' of https://github.com/netbirdio/netbird -9799cc7fedd7b58a087a7b5d78f3b802ff1948c5 not-for-merge branch 'mgmt_buff_16MB' of https://github.com/netbirdio/netbird 82cec5fb1d4c2127be0b7590481aceec508c7c4f not-for-merge branch 'mlsmaycon-patch-1' of https://github.com/netbirdio/netbird 24b66fb406f790082a9871d366c3848e29d1b65b not-for-merge branch 'move-licensed-code' of https://github.com/netbirdio/netbird 3988a8c356ba703f9779f29477b118ecf62d593a not-for-merge branch 'multi-price' of https://github.com/netbirdio/netbird 083063f51d7e7492bafae84938a036abc1a6164c not-for-merge branch 'nb-client-k8s-statefulset' of https://github.com/netbirdio/netbird 417fa6e833b12b62acd8d3940428e87024845d96 not-for-merge branch 'nb-interface-default' of https://github.com/netbirdio/netbird 840b07c7840411a009d5cfc17cab629d2d1b13ee not-for-merge branch 'netmap' of https://github.com/netbirdio/netbird -7673067605cc0d9610e90bdf846ecee801640d2d not-for-merge branch 'netmap_progressive_alignment' of https://github.com/netbirdio/netbird +9d613189f6eb59df0ceaee193e8a71d4e0c4e079 not-for-merge branch 'netmap_progressive_alignment' of https://github.com/netbirdio/netbird 9124832651f370375f0282f4cccbd8bf4c6b48eb not-for-merge branch 'nmap/combined-deploy' of https://github.com/netbirdio/netbird ca432ff681d38df2ca63375ae91f46e2d3cadd8b not-for-merge branch 'nmap/compaction' of https://github.com/netbirdio/netbird f357db6ffad1a1c92b1f2ec1cc43e36d64a4988f not-for-merge branch 'nmap/compaction-deploy' of https://github.com/netbirdio/netbird @@ -428,6 +426,7 @@ 485a38a4a86b595bbc3afc2973610d1c61f6c8fe not-for-merge branch 'wasmbuild-test' of https://github.com/netbirdio/netbird 940367e1c64cb6ebe280c8e35bf182ce6fed4d3a not-for-merge branch 'wg_bind_parallel_processing' of https://github.com/netbirdio/netbird d66b425bb674eb69050d27d45a72db049db3de34 not-for-merge branch 'wg_conn_fix' of https://github.com/netbirdio/netbird +5740dd22e6c0ce4d5a27504685bc61709f23be20 not-for-merge branch 'wg_watcher_debounce' of https://github.com/netbirdio/netbird dd13b8f27eabb649952754071e5165515887d3ee not-for-merge branch 'wgwatcher-test' of https://github.com/netbirdio/netbird 9157b749459ad64620c36178fb26eac40e9ca805 not-for-merge branch 'windows-dns-firewall' of https://github.com/netbirdio/netbird e3d1b9ca880ff4f1e6624e306b6957aa6c30e5c1 not-for-merge branch 'windows-search-domains' of https://github.com/netbirdio/netbird diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/HEAD new/netbird-0.74.2/.git/HEAD --- old/netbird-0.74.1/.git/HEAD 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/HEAD 2026-07-03 12:23:11.000000000 +0200 @@ -1 +1 @@ -859fe19fff6661ed0ba7904b42ed8b12d72c36f5 +3aa6c02b932db503e82f9530dddfe95d5ea212c4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/ORIG_HEAD new/netbird-0.74.2/.git/ORIG_HEAD --- old/netbird-0.74.1/.git/ORIG_HEAD 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/ORIG_HEAD 2026-07-03 12:23:11.000000000 +0200 @@ -1 +1 @@ -859fe19fff6661ed0ba7904b42ed8b12d72c36f5 +3aa6c02b932db503e82f9530dddfe95d5ea212c4 Binary files old/netbird-0.74.1/.git/index and new/netbird-0.74.2/.git/index differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/HEAD new/netbird-0.74.2/.git/logs/HEAD --- old/netbird-0.74.1/.git/logs/HEAD 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/HEAD 2026-07-03 12:23:11.000000000 +0200 @@ -33,3 +33,4 @@ 58c79f587878511c478c21638c42376f9c5c401f 2ebf26006a6c6be1c9b824012a57224d6eb53c96 Marcus Rückert <[email protected]> 1782156901 +0200 checkout: moving from 58c79f587878511c478c21638c42376f9c5c401f to v0.73.2 2ebf26006a6c6be1c9b824012a57224d6eb53c96 7d4736de5579fecbef172e203ec7f6a424ac2885 Marcus Rückert <[email protected]> 1782940258 +0200 checkout: moving from 2ebf26006a6c6be1c9b824012a57224d6eb53c96 to v0.74.0 7d4736de5579fecbef172e203ec7f6a424ac2885 859fe19fff6661ed0ba7904b42ed8b12d72c36f5 Marcus Rückert <[email protected]> 1783000611 +0200 checkout: moving from 7d4736de5579fecbef172e203ec7f6a424ac2885 to v0.74.1 +859fe19fff6661ed0ba7904b42ed8b12d72c36f5 3aa6c02b932db503e82f9530dddfe95d5ea212c4 Marcus Rückert <[email protected]> 1783104338 +0200 checkout: moving from 859fe19fff6661ed0ba7904b42ed8b12d72c36f5 to v0.74.2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/0.75.0-branch new/netbird-0.74.2/.git/logs/refs/remotes/origin/0.75.0-branch --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/0.75.0-branch 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/0.75.0-branch 2026-07-03 12:23:11.000000000 +0200 @@ -1,2 +1,3 @@ 0000000000000000000000000000000000000000 27616ff0045cf31e34ce0c7d8bf980b920a4625f Marcus Rückert <[email protected]> 1781886792 +0200 pull: storing head 27616ff0045cf31e34ce0c7d8bf980b920a4625f 1e0e04d65fdbe2afb5e4a301f0f81840bf833f37 Marcus Rückert <[email protected]> 1782940252 +0200 pull: fast-forward +1e0e04d65fdbe2afb5e4a301f0f81840bf833f37 d099534dca0151c0f9d2ca4c18ffeef14e3f6bfd Marcus Rückert <[email protected]> 1783104333 +0200 pull: fast-forward diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/backport/single-exit-node new/netbird-0.74.2/.git/logs/refs/remotes/origin/backport/single-exit-node --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/backport/single-exit-node 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/backport/single-exit-node 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -0000000000000000000000000000000000000000 415eb59ef53b4ec953cc2b5a4fb7b99457049497 Marcus Rückert <[email protected]> 1783000602 +0200 pull: storing head diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/github_actions/actions-1fec7beb7c new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/github_actions/actions-1fec7beb7c --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/github_actions/actions-1fec7beb7c 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/github_actions/actions-1fec7beb7c 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -0000000000000000000000000000000000000000 9dec2bcdcdaa175208a7b95da99a17b02df6fc1f Marcus Rückert <[email protected]> 1783000602 +0200 pull: storing head diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/github_actions/actions-c97fa3f10c new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/github_actions/actions-c97fa3f10c --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/github_actions/actions-c97fa3f10c 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/github_actions/actions-c97fa3f10c 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 8c5a20b04546e1e6a1bc896118334276a1a26987 Marcus Rückert <[email protected]> 1783104333 +0200 pull: storing head diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/go_modules/aws-sdk-8f849ebaed new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/go_modules/aws-sdk-8f849ebaed --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/go_modules/aws-sdk-8f849ebaed 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/go_modules/aws-sdk-8f849ebaed 2026-07-03 12:23:11.000000000 +0200 @@ -1,2 +1,3 @@ 0000000000000000000000000000000000000000 a140118f95e46fc93eb8ed87cfc139d969e012b5 Marcus Rückert <[email protected]> 1782940252 +0200 pull: storing head a140118f95e46fc93eb8ed87cfc139d969e012b5 3d59ab9730ba0c2662901eab4c947e4dcfda0474 Marcus Rückert <[email protected]> 1783000602 +0200 pull: forced-update +3d59ab9730ba0c2662901eab4c947e4dcfda0474 a721675b11767b2771121760ae2dbdc00e67e300 Marcus Rückert <[email protected]> 1783104333 +0200 pull: forced-update diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/go_modules/gorm-2271c8195b new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/go_modules/gorm-2271c8195b --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/go_modules/gorm-2271c8195b 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/go_modules/gorm-2271c8195b 2026-07-03 12:23:11.000000000 +0200 @@ -6,3 +6,4 @@ 8ce6254a5b9474f46654c3b27c2d222a992b795e 3d8f621621e1708d484411e571439eea1eca095d Marcus Rückert <[email protected]> 1782156893 +0200 pull: forced-update 3d8f621621e1708d484411e571439eea1eca095d aeddd23377f9ee1dce17b93b82c9cfcecdaa36c7 Marcus Rückert <[email protected]> 1782940252 +0200 pull: forced-update aeddd23377f9ee1dce17b93b82c9cfcecdaa36c7 1d7a2a5ace003824e2cea472b9c815f901b0c15c Marcus Rückert <[email protected]> 1783000602 +0200 pull: forced-update +1d7a2a5ace003824e2cea472b9c815f901b0c15c d77d78720c57ac6e1ae613f1f171bc9911e45549 Marcus Rückert <[email protected]> 1783104333 +0200 pull: forced-update diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/go_modules/otel-e34c790afd new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/go_modules/otel-e34c790afd --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/go_modules/otel-e34c790afd 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/go_modules/otel-e34c790afd 2026-07-03 12:23:11.000000000 +0200 @@ -6,3 +6,4 @@ 3775bf5f8a7d208dc861d178b4a402409c231012 91d0307c8bf1a57dab78d017039c6563e37cd9be Marcus Rückert <[email protected]> 1782156893 +0200 pull: forced-update 91d0307c8bf1a57dab78d017039c6563e37cd9be 78742ed52ba37848c8188cd5f5e139a6baf4a0e6 Marcus Rückert <[email protected]> 1782940252 +0200 pull: forced-update 78742ed52ba37848c8188cd5f5e139a6baf4a0e6 92a949ef5a935af8485de0361c32a682a9c06770 Marcus Rückert <[email protected]> 1783000602 +0200 pull: forced-update +92a949ef5a935af8485de0361c32a682a9c06770 94e6c40446f8ba80930319cd25fbf15d554272a7 Marcus Rückert <[email protected]> 1783104333 +0200 pull: forced-update diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/go_modules/pion-5f703e1eca new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/go_modules/pion-5f703e1eca --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/go_modules/pion-5f703e1eca 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/go_modules/pion-5f703e1eca 2026-07-03 12:23:11.000000000 +0200 @@ -1,2 +1,3 @@ 0000000000000000000000000000000000000000 dc13f107d86595bd1cd181bb4c2990cc898cc4eb Marcus Rückert <[email protected]> 1782940252 +0200 pull: storing head dc13f107d86595bd1cd181bb4c2990cc898cc4eb d8e98f4fb51f476cccbe0e771ea0041954b0bd5d Marcus Rückert <[email protected]> 1783000602 +0200 pull: forced-update +d8e98f4fb51f476cccbe0e771ea0041954b0bd5d 5a2660e796bf697dd0c00c09bc0c2338e93c4695 Marcus Rückert <[email protected]> 1783104333 +0200 pull: forced-update diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/go_modules/testcontainers-de325c0dd6 new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/go_modules/testcontainers-de325c0dd6 --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/go_modules/testcontainers-de325c0dd6 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/go_modules/testcontainers-de325c0dd6 2026-07-03 12:23:11.000000000 +0200 @@ -1,2 +1,3 @@ 0000000000000000000000000000000000000000 06cf216e345f7e380a65a7f1c853cf75747e70a1 Marcus Rückert <[email protected]> 1782940252 +0200 pull: storing head 06cf216e345f7e380a65a7f1c853cf75747e70a1 f14100f1ab2a1a502a7bfd3b19af6ff6bb8faf1f Marcus Rückert <[email protected]> 1783000602 +0200 pull: forced-update +f14100f1ab2a1a502a7bfd3b19af6ff6bb8faf1f 75ac15c52e36877590418a260f31880b75a412a9 Marcus Rückert <[email protected]> 1783104333 +0200 pull: forced-update diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/go_modules/wireguard-dbd6b95108 new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/go_modules/wireguard-dbd6b95108 --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/dependabot/go_modules/wireguard-dbd6b95108 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/dependabot/go_modules/wireguard-dbd6b95108 2026-07-03 12:23:11.000000000 +0200 @@ -6,3 +6,4 @@ f4c7e8651f9deeaa0c3a373d5610eb1504589f3d 7fbd847325cbb9b7af6f7db04b7d942eca29c179 Marcus Rückert <[email protected]> 1782156893 +0200 pull: forced-update 7fbd847325cbb9b7af6f7db04b7d942eca29c179 52a25c1ce51c8d68661623ba33747b3f5ae128d2 Marcus Rückert <[email protected]> 1782940252 +0200 pull: forced-update 52a25c1ce51c8d68661623ba33747b3f5ae128d2 af04a89eee82e2b02bd4ae09d41677b89426cd28 Marcus Rückert <[email protected]> 1783000602 +0200 pull: forced-update +af04a89eee82e2b02bd4ae09d41677b89426cd28 479a88ca9f58cdd095beb7d05bcc393d3d1b7cb1 Marcus Rückert <[email protected]> 1783104333 +0200 pull: forced-update diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/feat/admin-cli new/netbird-0.74.2/.git/logs/refs/remotes/origin/feat/admin-cli --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/feat/admin-cli 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/feat/admin-cli 2026-07-03 12:23:11.000000000 +0200 @@ -1 +1,2 @@ 0000000000000000000000000000000000000000 520370a8b0723d9fd819590646cce5d0a2d6bc57 Marcus Rückert <[email protected]> 1782156893 +0200 pull: storing head +520370a8b0723d9fd819590646cce5d0a2d6bc57 f25011f9ca520ec3c97c909ca2201f149af0c4f6 Marcus Rückert <[email protected]> 1783104333 +0200 pull: fast-forward diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/fix/routeselector-atomic-exit-node new/netbird-0.74.2/.git/logs/refs/remotes/origin/fix/routeselector-atomic-exit-node --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/fix/routeselector-atomic-exit-node 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/fix/routeselector-atomic-exit-node 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 e22976a89e7f2d6c2a5fa4583be9a24b01c63dbf Marcus Rückert <[email protected]> 1783104333 +0200 pull: storing head diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/fix/slow-wg-operations new/netbird-0.74.2/.git/logs/refs/remotes/origin/fix/slow-wg-operations --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/fix/slow-wg-operations 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/fix/slow-wg-operations 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -0000000000000000000000000000000000000000 e55b252765179383444c746343b4b41ef2ec63e8 Marcus Rückert <[email protected]> 1782940252 +0200 pull: storing head diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/main new/netbird-0.74.2/.git/logs/refs/remotes/origin/main --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/main 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/main 2026-07-03 12:23:11.000000000 +0200 @@ -30,3 +30,4 @@ 58c79f587878511c478c21638c42376f9c5c401f 2ebf26006a6c6be1c9b824012a57224d6eb53c96 Marcus Rückert <[email protected]> 1782156893 +0200 pull: fast-forward 2ebf26006a6c6be1c9b824012a57224d6eb53c96 7d4736de5579fecbef172e203ec7f6a424ac2885 Marcus Rückert <[email protected]> 1782940252 +0200 pull: fast-forward 7d4736de5579fecbef172e203ec7f6a424ac2885 1dfa85a917eb47e23e4dc4c142056e67966a1c03 Marcus Rückert <[email protected]> 1783000602 +0200 pull: fast-forward +1dfa85a917eb47e23e4dc4c142056e67966a1c03 3aa6c02b932db503e82f9530dddfe95d5ea212c4 Marcus Rückert <[email protected]> 1783104333 +0200 pull: fast-forward diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/mgmt_buff_16MB new/netbird-0.74.2/.git/logs/refs/remotes/origin/mgmt_buff_16MB --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/mgmt_buff_16MB 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/mgmt_buff_16MB 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -0000000000000000000000000000000000000000 9799cc7fedd7b58a087a7b5d78f3b802ff1948c5 Marcus Rückert <[email protected]> 1783000602 +0200 pull: storing head diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/netmap_progressive_alignment new/netbird-0.74.2/.git/logs/refs/remotes/origin/netmap_progressive_alignment --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/netmap_progressive_alignment 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/netmap_progressive_alignment 2026-07-03 12:23:11.000000000 +0200 @@ -1,2 +1,3 @@ 0000000000000000000000000000000000000000 79567fe347acf86a3838b785359d197204c161a9 Marcus Rückert <[email protected]> 1782940252 +0200 pull: storing head 79567fe347acf86a3838b785359d197204c161a9 7673067605cc0d9610e90bdf846ecee801640d2d Marcus Rückert <[email protected]> 1783000602 +0200 pull: fast-forward +7673067605cc0d9610e90bdf846ecee801640d2d 9d613189f6eb59df0ceaee193e8a71d4e0c4e079 Marcus Rückert <[email protected]> 1783104333 +0200 pull: fast-forward diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/logs/refs/remotes/origin/wg_watcher_debounce new/netbird-0.74.2/.git/logs/refs/remotes/origin/wg_watcher_debounce --- old/netbird-0.74.1/.git/logs/refs/remotes/origin/wg_watcher_debounce 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/.git/logs/refs/remotes/origin/wg_watcher_debounce 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 5740dd22e6c0ce4d5a27504685bc61709f23be20 Marcus Rückert <[email protected]> 1783104333 +0200 pull: storing head Binary files old/netbird-0.74.1/.git/objects/pack/pack-0dbb339f0a1e73a1534da27fdb2a16d944478a53.idx and new/netbird-0.74.2/.git/objects/pack/pack-0dbb339f0a1e73a1534da27fdb2a16d944478a53.idx differ Binary files old/netbird-0.74.1/.git/objects/pack/pack-0dbb339f0a1e73a1534da27fdb2a16d944478a53.pack and new/netbird-0.74.2/.git/objects/pack/pack-0dbb339f0a1e73a1534da27fdb2a16d944478a53.pack differ Binary files old/netbird-0.74.1/.git/objects/pack/pack-0dbb339f0a1e73a1534da27fdb2a16d944478a53.rev and new/netbird-0.74.2/.git/objects/pack/pack-0dbb339f0a1e73a1534da27fdb2a16d944478a53.rev differ Binary files old/netbird-0.74.1/.git/objects/pack/pack-42f83e0d24e8208f0e974f626edac7584acc1434.idx and new/netbird-0.74.2/.git/objects/pack/pack-42f83e0d24e8208f0e974f626edac7584acc1434.idx differ Binary files old/netbird-0.74.1/.git/objects/pack/pack-42f83e0d24e8208f0e974f626edac7584acc1434.pack and new/netbird-0.74.2/.git/objects/pack/pack-42f83e0d24e8208f0e974f626edac7584acc1434.pack differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/objects/pack/pack-42f83e0d24e8208f0e974f626edac7584acc1434.promisor new/netbird-0.74.2/.git/objects/pack/pack-42f83e0d24e8208f0e974f626edac7584acc1434.promisor --- old/netbird-0.74.1/.git/objects/pack/pack-42f83e0d24e8208f0e974f626edac7584acc1434.promisor 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/.git/objects/pack/pack-42f83e0d24e8208f0e974f626edac7584acc1434.promisor 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1 @@ +426078a149161b2d04b1e9fcf4ef6f752bdcd8d0 426078a149161b2d04b1e9fcf4ef6f752bdcd8d0 Binary files old/netbird-0.74.1/.git/objects/pack/pack-42f83e0d24e8208f0e974f626edac7584acc1434.rev and new/netbird-0.74.2/.git/objects/pack/pack-42f83e0d24e8208f0e974f626edac7584acc1434.rev differ Binary files old/netbird-0.74.1/.git/objects/pack/pack-ca049b5473021acadd91874add78701ca0dff1e1.idx and new/netbird-0.74.2/.git/objects/pack/pack-ca049b5473021acadd91874add78701ca0dff1e1.idx differ Binary files old/netbird-0.74.1/.git/objects/pack/pack-ca049b5473021acadd91874add78701ca0dff1e1.pack and new/netbird-0.74.2/.git/objects/pack/pack-ca049b5473021acadd91874add78701ca0dff1e1.pack differ Binary files old/netbird-0.74.1/.git/objects/pack/pack-ca049b5473021acadd91874add78701ca0dff1e1.rev and new/netbird-0.74.2/.git/objects/pack/pack-ca049b5473021acadd91874add78701ca0dff1e1.rev differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/packed-refs new/netbird-0.74.2/.git/packed-refs --- old/netbird-0.74.1/.git/packed-refs 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/packed-refs 2026-07-03 12:23:11.000000000 +0200 @@ -237,7 +237,6 @@ 9be7e33a07b501799581d77949a2607fab5bb7c9 refs/remotes/origin/fix/route 4a4d506221da3a6929a8bc2c96c541e37bec6a9f refs/remotes/origin/fix/signal-watchdog-sync-stop 4642233b839ee228b9c5898e087bede8511997cb refs/remotes/origin/fix/skip-restart-unchanged-route -e55b252765179383444c746343b4b41ef2ec63e8 refs/remotes/origin/fix/slow-wg-operations dde4693fdd2d24090d26768f23bd2f03cff61f3c refs/remotes/origin/fix/sync-peer-race 782a8cb13036db0a5eecf8296d8cb5ef51a8760f refs/remotes/origin/fix/systemd-service-logs e59223c81f2e16ab4fe7cc6c86ef227d0e7a0f8d refs/remotes/origin/fix/test-freebsd diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/0.75.0-branch new/netbird-0.74.2/.git/refs/remotes/origin/0.75.0-branch --- old/netbird-0.74.1/.git/refs/remotes/origin/0.75.0-branch 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/.git/refs/remotes/origin/0.75.0-branch 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1 @@ +d099534dca0151c0f9d2ca4c18ffeef14e3f6bfd diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/backport/single-exit-node new/netbird-0.74.2/.git/refs/remotes/origin/backport/single-exit-node --- old/netbird-0.74.1/.git/refs/remotes/origin/backport/single-exit-node 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/refs/remotes/origin/backport/single-exit-node 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -415eb59ef53b4ec953cc2b5a4fb7b99457049497 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/github_actions/actions-1fec7beb7c new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/github_actions/actions-1fec7beb7c --- old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/github_actions/actions-1fec7beb7c 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/github_actions/actions-1fec7beb7c 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -9dec2bcdcdaa175208a7b95da99a17b02df6fc1f diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/github_actions/actions-c97fa3f10c new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/github_actions/actions-c97fa3f10c --- old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/github_actions/actions-c97fa3f10c 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/github_actions/actions-c97fa3f10c 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1 @@ +8c5a20b04546e1e6a1bc896118334276a1a26987 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/go_modules/aws-sdk-8f849ebaed new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/go_modules/aws-sdk-8f849ebaed --- old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/go_modules/aws-sdk-8f849ebaed 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/go_modules/aws-sdk-8f849ebaed 2026-07-03 12:23:11.000000000 +0200 @@ -1 +1 @@ -3d59ab9730ba0c2662901eab4c947e4dcfda0474 +a721675b11767b2771121760ae2dbdc00e67e300 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/go_modules/gorm-2271c8195b new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/go_modules/gorm-2271c8195b --- old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/go_modules/gorm-2271c8195b 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/go_modules/gorm-2271c8195b 2026-07-03 12:23:11.000000000 +0200 @@ -1 +1 @@ -1d7a2a5ace003824e2cea472b9c815f901b0c15c +d77d78720c57ac6e1ae613f1f171bc9911e45549 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/go_modules/otel-e34c790afd new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/go_modules/otel-e34c790afd --- old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/go_modules/otel-e34c790afd 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/go_modules/otel-e34c790afd 2026-07-03 12:23:11.000000000 +0200 @@ -1 +1 @@ -92a949ef5a935af8485de0361c32a682a9c06770 +94e6c40446f8ba80930319cd25fbf15d554272a7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/go_modules/pion-5f703e1eca new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/go_modules/pion-5f703e1eca --- old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/go_modules/pion-5f703e1eca 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/go_modules/pion-5f703e1eca 2026-07-03 12:23:11.000000000 +0200 @@ -1 +1 @@ -d8e98f4fb51f476cccbe0e771ea0041954b0bd5d +5a2660e796bf697dd0c00c09bc0c2338e93c4695 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/go_modules/testcontainers-de325c0dd6 new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/go_modules/testcontainers-de325c0dd6 --- old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/go_modules/testcontainers-de325c0dd6 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/go_modules/testcontainers-de325c0dd6 2026-07-03 12:23:11.000000000 +0200 @@ -1 +1 @@ -f14100f1ab2a1a502a7bfd3b19af6ff6bb8faf1f +75ac15c52e36877590418a260f31880b75a412a9 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/go_modules/wireguard-dbd6b95108 new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/go_modules/wireguard-dbd6b95108 --- old/netbird-0.74.1/.git/refs/remotes/origin/dependabot/go_modules/wireguard-dbd6b95108 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/refs/remotes/origin/dependabot/go_modules/wireguard-dbd6b95108 2026-07-03 12:23:11.000000000 +0200 @@ -1 +1 @@ -af04a89eee82e2b02bd4ae09d41677b89426cd28 +479a88ca9f58cdd095beb7d05bcc393d3d1b7cb1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/feat/admin-cli new/netbird-0.74.2/.git/refs/remotes/origin/feat/admin-cli --- old/netbird-0.74.1/.git/refs/remotes/origin/feat/admin-cli 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/.git/refs/remotes/origin/feat/admin-cli 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1 @@ +f25011f9ca520ec3c97c909ca2201f149af0c4f6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/fix/routeselector-atomic-exit-node new/netbird-0.74.2/.git/refs/remotes/origin/fix/routeselector-atomic-exit-node --- old/netbird-0.74.1/.git/refs/remotes/origin/fix/routeselector-atomic-exit-node 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/.git/refs/remotes/origin/fix/routeselector-atomic-exit-node 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1 @@ +e22976a89e7f2d6c2a5fa4583be9a24b01c63dbf diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/main new/netbird-0.74.2/.git/refs/remotes/origin/main --- old/netbird-0.74.1/.git/refs/remotes/origin/main 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/refs/remotes/origin/main 2026-07-03 12:23:11.000000000 +0200 @@ -1 +1 @@ -1dfa85a917eb47e23e4dc4c142056e67966a1c03 +3aa6c02b932db503e82f9530dddfe95d5ea212c4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/mgmt_buff_16MB new/netbird-0.74.2/.git/refs/remotes/origin/mgmt_buff_16MB --- old/netbird-0.74.1/.git/refs/remotes/origin/mgmt_buff_16MB 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/refs/remotes/origin/mgmt_buff_16MB 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -9799cc7fedd7b58a087a7b5d78f3b802ff1948c5 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/netmap_progressive_alignment new/netbird-0.74.2/.git/refs/remotes/origin/netmap_progressive_alignment --- old/netbird-0.74.1/.git/refs/remotes/origin/netmap_progressive_alignment 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.git/refs/remotes/origin/netmap_progressive_alignment 2026-07-03 12:23:11.000000000 +0200 @@ -1 +1 @@ -7673067605cc0d9610e90bdf846ecee801640d2d +9d613189f6eb59df0ceaee193e8a71d4e0c4e079 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/remotes/origin/wg_watcher_debounce new/netbird-0.74.2/.git/refs/remotes/origin/wg_watcher_debounce --- old/netbird-0.74.1/.git/refs/remotes/origin/wg_watcher_debounce 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/.git/refs/remotes/origin/wg_watcher_debounce 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1 @@ +5740dd22e6c0ce4d5a27504685bc61709f23be20 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/tags/v0.74.2 new/netbird-0.74.2/.git/refs/tags/v0.74.2 --- old/netbird-0.74.1/.git/refs/tags/v0.74.2 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/.git/refs/tags/v0.74.2 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1 @@ +3aa6c02b932db503e82f9530dddfe95d5ea212c4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.git/refs/tags/v0.75.0-rc.5 new/netbird-0.74.2/.git/refs/tags/v0.75.0-rc.5 --- old/netbird-0.74.1/.git/refs/tags/v0.75.0-rc.5 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/.git/refs/tags/v0.75.0-rc.5 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1 @@ +d099534dca0151c0f9d2ca4c18ffeef14e3f6bfd diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.github/workflows/release.yml new/netbird-0.74.2/.github/workflows/release.yml --- old/netbird-0.74.1/.github/workflows/release.yml 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.github/workflows/release.yml 2026-07-03 12:23:11.000000000 +0200 @@ -293,8 +293,11 @@ ${{ steps.goreleaser.outputs.artifacts }} JSON + # dockers_v2 artifacts have no top-level goarch field, so match the + # per-platform -amd64 tag suffix instead; it works for both the old + # dockers and the new dockers_v2 image naming. mapfile -t src_images < <( - jq -r '.[] | select(.type == "Docker Image") | select(.goarch == "amd64") | .name | select(startswith("ghcr.io/"))' /tmp/goreleaser-artifacts.json + jq -r '.[] | select(.type == "Docker Image") | .name | select(startswith("ghcr.io/") and endswith("-amd64"))' /tmp/goreleaser-artifacts.json ) for src in "${src_images[@]}"; do diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/.gitignore new/netbird-0.74.2/.gitignore --- old/netbird-0.74.1/.gitignore 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/.gitignore 2026-07-03 12:23:11.000000000 +0200 @@ -1,3 +1,4 @@ +.claude .idea .run *.iml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/client/iface/configurer/kernel_unix.go new/netbird-0.74.2/client/iface/configurer/kernel_unix.go --- old/netbird-0.74.1/client/iface/configurer/kernel_unix.go 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/client/iface/configurer/kernel_unix.go 2026-07-03 12:23:11.000000000 +0200 @@ -17,12 +17,15 @@ type KernelConfigurer struct { deviceName string + statsCache *statsCache } func NewKernelConfigurer(deviceName string) *KernelConfigurer { - return &KernelConfigurer{ + c := &KernelConfigurer{ deviceName: deviceName, } + c.statsCache = newStatsCache(statsCacheTTL, c.fetchStats) + return c } func (c *KernelConfigurer) ConfigureInterface(privateKey string, port int) error { @@ -246,12 +249,6 @@ } }() - // validate if device with name exists - _, err = wg.Device(c.deviceName) - if err != nil { - return err - } - return wg.ConfigureDevice(c.deviceName, config) } @@ -300,6 +297,14 @@ } func (c *KernelConfigurer) GetStats() (map[string]WGStats, error) { + return c.statsCache.get() +} + +func (c *KernelConfigurer) LastActivities() map[string]monotime.Time { + return nil +} + +func (c *KernelConfigurer) fetchStats() (map[string]WGStats, error) { stats := make(map[string]WGStats) wg, err := wgctrl.New() if err != nil { @@ -326,7 +331,3 @@ } return stats, nil } - -func (c *KernelConfigurer) LastActivities() map[string]monotime.Time { - return nil -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/client/iface/configurer/stats_cache.go new/netbird-0.74.2/client/iface/configurer/stats_cache.go --- old/netbird-0.74.1/client/iface/configurer/stats_cache.go 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/client/iface/configurer/stats_cache.go 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1,52 @@ +package configurer + +import ( + "sync" + "time" + + "golang.org/x/sync/singleflight" +) + +const statsCacheTTL = 1 * time.Second + +type statsCache struct { + ttl time.Duration + fetch func() (map[string]WGStats, error) + + mu sync.RWMutex + value map[string]WGStats + expireAt time.Time + + sf singleflight.Group +} + +func newStatsCache(ttl time.Duration, fetch func() (map[string]WGStats, error)) *statsCache { + return &statsCache{ttl: ttl, fetch: fetch} +} + +func (c *statsCache) get() (map[string]WGStats, error) { + c.mu.RLock() + if c.value != nil && time.Now().Before(c.expireAt) { + value := c.value + c.mu.RUnlock() + return value, nil + } + c.mu.RUnlock() + + value, err, _ := c.sf.Do("stats", func() (interface{}, error) { + res, err := c.fetch() + if err != nil { + return nil, err + } + + c.mu.Lock() + c.value = res + c.expireAt = time.Now().Add(c.ttl) + c.mu.Unlock() + return res, nil + }) + if err != nil { + return nil, err + } + return value.(map[string]WGStats), nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/client/iface/configurer/stats_cache_test.go new/netbird-0.74.2/client/iface/configurer/stats_cache_test.go --- old/netbird-0.74.1/client/iface/configurer/stats_cache_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/client/iface/configurer/stats_cache_test.go 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1,70 @@ +package configurer + +import ( + "errors" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestStatsCache_CachesWithinTTL(t *testing.T) { + var calls atomic.Int64 + c := newStatsCache(50*time.Millisecond, func() (map[string]WGStats, error) { + calls.Add(1) + return map[string]WGStats{"p": {}}, nil + }) + + for i := 0; i < 10; i++ { + _, err := c.get() + require.NoError(t, err) + } + require.Equal(t, int64(1), calls.Load(), "within TTL only one underlying fetch") + + time.Sleep(60 * time.Millisecond) + _, err := c.get() + require.NoError(t, err) + require.Equal(t, int64(2), calls.Load(), "after TTL expiry a fresh fetch happens") +} + +func TestStatsCache_SingleFlight(t *testing.T) { + var calls atomic.Int64 + release := make(chan struct{}) + c := newStatsCache(time.Minute, func() (map[string]WGStats, error) { + calls.Add(1) + <-release + return map[string]WGStats{}, nil + }) + + const n = 50 + var wg sync.WaitGroup + wg.Add(n) + for i := 0; i < n; i++ { + go func() { + defer wg.Done() + _, _ = c.get() + }() + } + time.Sleep(20 * time.Millisecond) + close(release) + wg.Wait() + + require.Equal(t, int64(1), calls.Load(), "concurrent misses collapse into one fetch") +} + +func TestStatsCache_ErrorNotCached(t *testing.T) { + var calls atomic.Int64 + wantErr := errors.New("dump failed") + c := newStatsCache(time.Minute, func() (map[string]WGStats, error) { + calls.Add(1) + return nil, wantErr + }) + + _, err := c.get() + require.ErrorIs(t, err, wantErr) + _, err = c.get() + require.ErrorIs(t, err, wantErr) + require.Equal(t, int64(2), calls.Load(), "errors are not cached; each call retries") +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/client/iface/configurer/usp.go new/netbird-0.74.2/client/iface/configurer/usp.go --- old/netbird-0.74.1/client/iface/configurer/usp.go 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/client/iface/configurer/usp.go 2026-07-03 12:23:11.000000000 +0200 @@ -40,6 +40,7 @@ device *device.Device deviceName string activityRecorder *bind.ActivityRecorder + statsCache *statsCache uapiListener net.Listener } @@ -50,16 +51,19 @@ deviceName: deviceName, activityRecorder: activityRecorder, } + wgCfg.statsCache = newStatsCache(statsCacheTTL, wgCfg.fetchStats) wgCfg.startUAPI() return wgCfg } func NewUSPConfigurerNoUAPI(device *device.Device, deviceName string, activityRecorder *bind.ActivityRecorder) *WGUSPConfigurer { - return &WGUSPConfigurer{ + wgCfg := &WGUSPConfigurer{ device: device, deviceName: deviceName, activityRecorder: activityRecorder, } + wgCfg.statsCache = newStatsCache(statsCacheTTL, wgCfg.fetchStats) + return wgCfg } func (c *WGUSPConfigurer) ConfigureInterface(privateKey string, port int) error { @@ -348,6 +352,10 @@ } func (t *WGUSPConfigurer) GetStats() (map[string]WGStats, error) { + return t.statsCache.get() +} + +func (t *WGUSPConfigurer) fetchStats() (map[string]WGStats, error) { ipc, err := t.device.IpcGet() if err != nil { return nil, fmt.Errorf("ipc get: %w", err) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/client/internal/peer/guard/guard.go new/netbird-0.74.2/client/internal/peer/guard/guard.go --- old/netbird-0.74.1/client/internal/peer/guard/guard.go 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/client/internal/peer/guard/guard.go 2026-07-03 12:23:11.000000000 +0200 @@ -85,7 +85,11 @@ defer g.srWatcher.RemoveListener(srReconnectedChan) ticker := g.initialTicker(ctx) - defer ticker.Stop() + defer func() { + // If backoff.Ticker.send is blocked, context.Done will not close the Ticker goroutine. + // We have to explicitly call Stop, even if we use backoff.WithContext. + ticker.Stop() + }() tickerChannel := ticker.C diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/client/internal/peer/guard/guard_leak_test.go new/netbird-0.74.2/client/internal/peer/guard/guard_leak_test.go --- old/netbird-0.74.1/client/internal/peer/guard/guard_leak_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/client/internal/peer/guard/guard_leak_test.go 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1,92 @@ +package guard + +import ( + "context" + "runtime" + "strings" + "sync" + "testing" + "time" + + log "github.com/sirupsen/logrus" + + "github.com/netbirdio/netbird/client/internal/peer/ice" +) + +func newTestGuard(status connStatusFunc) *Guard { + srw := NewSRWatcher(nil, nil, nil, ice.Config{}) + return NewGuard(log.WithField("test", "guard"), status, 50*time.Millisecond, srw) +} + +// countBackoffTickerGoroutines returns how many goroutines are currently sitting +// in backoff/v4.(*Ticker).run (a ticker goroutine that has not exited). +func countBackoffTickerGoroutines() int { + buf := make([]byte, 1<<25) // 32MB + n := runtime.Stack(buf, true) + return strings.Count(string(buf[:n]), "backoff/v4.(*Ticker).run") +} + +// TestGuard_ReconnectTicker_NoGoroutineLeakOnShutdown reproduces a observed +// leak: after a shutdown burst, ticker run/send goroutines stay parked +// forever even though every reconnect loop has exited. +func TestGuard_ReconnectTicker_NoGoroutineLeakOnShutdown(t *testing.T) { + before := countBackoffTickerGoroutines() + + const peers = 6000 + cancels := make([]context.CancelFunc, 0, peers) + var wg sync.WaitGroup + + // A status check slower than the tick cadence. This models the real + // isConnectedOnAllWay/callback doing work: while the loop is busy in the + // handler, the ticker fires the next tick and parks in send(), because + // send() never selects on ctx. + slowStatus := func() ConnStatus { + time.Sleep(70 * time.Millisecond) + return ConnStatusConnected + } + + for range peers { + g := newTestGuard(slowStatus) + ctx, cancel := context.WithCancel(context.Background()) + cancels = append(cancels, cancel) + wg.Add(1) + go func() { + defer wg.Done() + g.Start(ctx, func() {}) + }() + // Force the live ticker to be a newReconnectTicker. + g.SetRelayedConnDisconnected() + } + + // Let the replacement tickers get past their 800ms initial interval, so + // many are parked in send() waiting on the (slow) consumer when we tear + // everything down. + time.Sleep(1500 * time.Millisecond) + + // Shutdown burst: cancel every peer at once, like engine teardown. + for _, c := range cancels { + c() + } + + // Every reconnect loop must return + waitCh := make(chan struct{}) + go func() { wg.Wait(); close(waitCh) }() + select { + case <-waitCh: + case <-time.After(30 * time.Second): + t.Fatal("not all reconnect loops returned after ctx cancel") + } + + // Give any correctly-stopped ticker goroutines time to unwind. + for range 50 { + runtime.Gosched() + time.Sleep(10 * time.Millisecond) + } + + leaked := countBackoffTickerGoroutines() - before + t.Logf("backoff Ticker.run goroutines still parked after teardown of %d peers: %d", peers, leaked) + if leaked > 0 { + t.Errorf("LEAK: %d backoff ticker goroutines parked after all reconnect loops exited "+ + "(defer ticker.Stop() stops the initial ticker, not the live replacement)", leaked) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/client/internal/routemanager/exit_node_selection_test.go new/netbird-0.74.2/client/internal/routemanager/exit_node_selection_test.go --- old/netbird-0.74.1/client/internal/routemanager/exit_node_selection_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/client/internal/routemanager/exit_node_selection_test.go 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1,191 @@ +package routemanager + +import ( + "net/netip" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/netbirdio/netbird/client/internal/routeselector" + "github.com/netbirdio/netbird/route" +) + +func newExitNodeTestManager() *DefaultManager { + return &DefaultManager{routeSelector: routeselector.NewRouteSelector()} +} + +func exitRoute(netID, peer string, skipAutoApply bool) *route.Route { + return &route.Route{ + NetID: route.NetID(netID), + Network: netip.MustParsePrefix("0.0.0.0/0"), + Peer: peer, + SkipAutoApply: skipAutoApply, + } +} + +func TestPickPreferredExitNode(t *testing.T) { + tests := []struct { + name string + info exitNodeInfo + want route.NetID + }{ + { + name: "persisted user selection wins over management", + info: exitNodeInfo{ + allIDs: []route.NetID{"a", "b", "c"}, + userSelected: []route.NetID{"b"}, + selectedByManagement: []route.NetID{"a"}, + }, + want: "b", + }, + { + name: "multiple user-selected self-heal to deterministic min", + info: exitNodeInfo{ + allIDs: []route.NetID{"a", "b", "c"}, + userSelected: []route.NetID{"c", "a"}, + }, + want: "a", + }, + { + name: "explicit opt-out keeps none", + info: exitNodeInfo{ + allIDs: []route.NetID{"a", "b"}, + userDeselected: []route.NetID{"a", "b"}, + }, + want: "", + }, + { + name: "fresh defaults to management auto-apply pick", + info: exitNodeInfo{ + allIDs: []route.NetID{"a", "b", "c"}, + selectedByManagement: []route.NetID{"b"}, + }, + want: "b", + }, + { + name: "no user pick and no management auto-apply selects none", + info: exitNodeInfo{ + allIDs: []route.NetID{"c", "a", "b"}, + }, + want: "", + }, + { + name: "user-deselect does not block a management auto-apply sibling", + info: exitNodeInfo{ + allIDs: []route.NetID{"a", "b"}, + userDeselected: []route.NetID{"a"}, + selectedByManagement: []route.NetID{"b"}, + }, + want: "b", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, pickPreferredExitNode(tt.info), "preferred exit node") + }) + } +} + +func TestEnforceSingleExitNode(t *testing.T) { + m := newExitNodeTestManager() + all := []route.NetID{"a", "b", "c"} + + m.enforceSingleExitNode("b", all) + assert.False(t, m.routeSelector.IsSelected("a"), "a should be deselected") + assert.True(t, m.routeSelector.IsSelected("b"), "b should be the only selected exit node") + assert.False(t, m.routeSelector.IsSelected("c"), "c should be deselected") + + // Switching the preferred node moves the single selection. + m.enforceSingleExitNode("c", all) + assert.False(t, m.routeSelector.IsSelected("a"), "a stays deselected") + assert.False(t, m.routeSelector.IsSelected("b"), "b should now be deselected") + assert.True(t, m.routeSelector.IsSelected("c"), "c should now be selected") + + // Empty preferred turns every exit node off. + m.enforceSingleExitNode("", all) + for _, id := range all { + assert.False(t, m.routeSelector.IsSelected(id), "no exit node should be selected") + } +} + +func TestEnforceSingleExitNode_RespectsDeselectAll(t *testing.T) { + m := newExitNodeTestManager() + m.routeSelector.DeselectAllRoutes() + + m.enforceSingleExitNode("b", []route.NetID{"a", "b"}) + + assert.True(t, m.routeSelector.IsDeselectAll(), "global deselect-all must stay in effect") + assert.False(t, m.routeSelector.IsSelected("b"), "no exit node should be forced on while deselect-all is set") +} + +func TestUpdateRouteSelectorFromManagement_FreshSelectsOne(t *testing.T) { + m := newExitNodeTestManager() + routes := route.HAMap{ + "exitA|0.0.0.0/0": {exitRoute("exitA", "p1", false)}, + "exitB|0.0.0.0/0": {exitRoute("exitB", "p2", false)}, + "lan|192.168.1.0/24": {{NetID: "lan", Network: netip.MustParsePrefix("192.168.1.0/24"), Peer: "p3"}}, + "exitC|0.0.0.0/0": {exitRoute("exitC", "p4", false)}, + } + + m.updateRouteSelectorFromManagement(routes) + + // Exactly one exit node (the deterministic first) is selected. + assert.True(t, m.routeSelector.IsSelected("exitA"), "exitA is the deterministic default") + assert.False(t, m.routeSelector.IsSelected("exitB"), "exitB must not also be selected") + assert.False(t, m.routeSelector.IsSelected("exitC"), "exitC must not also be selected") + // Non-exit routes are left at their default-on state. + assert.True(t, m.routeSelector.IsSelected("lan"), "non-exit route selection is untouched") +} + +func TestUpdateRouteSelectorFromManagement_HonorsPersistedPick(t *testing.T) { + m := newExitNodeTestManager() + routes := route.HAMap{ + "exitA|0.0.0.0/0": {exitRoute("exitA", "p1", false)}, + "exitB|0.0.0.0/0": {exitRoute("exitB", "p2", false)}, + } + all := []route.NetID{"exitA", "exitB"} + + // Simulate the state the runtime select path leaves behind: exactly one + // exit node explicitly selected, its sibling deselected. + require.NoError(t, m.routeSelector.SelectRoutes([]route.NetID{"exitB"}, true, all)) + require.NoError(t, m.routeSelector.DeselectRoutes([]route.NetID{"exitA"}, all)) + + m.updateRouteSelectorFromManagement(routes) + + assert.True(t, m.routeSelector.IsSelected("exitB"), "persisted pick must stay selected") + assert.False(t, m.routeSelector.IsSelected("exitA"), "the other exit node stays deselected") +} + +func TestUpdateRouteSelectorFromManagement_OptOutKeepsNone(t *testing.T) { + m := newExitNodeTestManager() + routes := route.HAMap{ + "exitA|0.0.0.0/0": {exitRoute("exitA", "p1", false)}, + "exitB|0.0.0.0/0": {exitRoute("exitB", "p2", false)}, + } + all := []route.NetID{"exitA", "exitB"} + + // User deselected exit nodes and selected none. + require.NoError(t, m.routeSelector.DeselectRoutes(all, all)) + + m.updateRouteSelectorFromManagement(routes) + + assert.False(t, m.routeSelector.IsSelected("exitA"), "opt-out keeps exitA off") + assert.False(t, m.routeSelector.IsSelected("exitB"), "opt-out keeps exitB off") +} + +func TestUpdateRouteSelectorFromManagement_NoAutoApplySelectsNone(t *testing.T) { + m := newExitNodeTestManager() + // SkipAutoApply=true: management offers the exit nodes but doesn't request + // auto-activation, so none should be selected until the user picks one. + routes := route.HAMap{ + "exitA|0.0.0.0/0": {exitRoute("exitA", "p1", true)}, + "exitB|0.0.0.0/0": {exitRoute("exitB", "p2", true)}, + } + + m.updateRouteSelectorFromManagement(routes) + + assert.False(t, m.routeSelector.IsSelected("exitA"), "no auto-apply keeps exitA off") + assert.False(t, m.routeSelector.IsSelected("exitB"), "no auto-apply keeps exitB off") +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/client/internal/routemanager/manager.go new/netbird-0.74.2/client/internal/routemanager/manager.go --- old/netbird-0.74.1/client/internal/routemanager/manager.go 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/client/internal/routemanager/manager.go 2026-07-03 12:23:11.000000000 +0200 @@ -701,7 +701,13 @@ return ips } -// updateRouteSelectorFromManagement updates the route selector based on the isSelected status from the management server +// updateRouteSelectorFromManagement reconciles exit-node selection on every +// network map: it keeps at most one exit node selected — the user's persisted +// pick, else whatever management marks for auto-apply (SkipAutoApply=false), +// else none. We never auto-activate an exit node the map doesn't request; it +// stays off until the user picks it. Exit nodes are mutually exclusive, but the +// RouteSelector stores routes with default-on semantics, so without this every +// available exit node would report selected at once. func (m *DefaultManager) updateRouteSelectorFromManagement(clientRoutes route.HAMap) { m.mirrorV6ExitPairSelections(clientRoutes) @@ -712,13 +718,14 @@ return } - exitNodeInfo := m.collectExitNodeInfo(clientRoutes) - if len(exitNodeInfo.allIDs) == 0 { + info := m.collectExitNodeInfo(clientRoutes) + if len(info.allIDs) == 0 { return } - m.updateExitNodeSelections(exitNodeInfo) - m.logExitNodeUpdate(exitNodeInfo) + preferred := pickPreferredExitNode(info) + m.enforceSingleExitNode(preferred, info.allIDs) + m.logExitNodeUpdate(info, preferred) } // mirrorV6ExitPairSelections keeps every synthesized "-v6" exit route's selection @@ -746,6 +753,10 @@ userDeselected []route.NetID } +// collectExitNodeInfo categorises the available exit nodes by their persisted +// selection state. It keys on the base (v4) NetID and skips the synthesized +// "-v6" partner, which inherits its base's selection through the RouteSelector +// — counting it separately would double-count the pair. func (m *DefaultManager) collectExitNodeInfo(clientRoutes route.HAMap) exitNodeInfo { var info exitNodeInfo @@ -755,6 +766,9 @@ } netID := haID.NetID() + if strings.HasSuffix(string(netID), route.V6ExitSuffix) { + continue + } info.allIDs = append(info.allIDs, netID) if m.routeSelector.HasUserSelectionForRoute(netID) { @@ -791,45 +805,52 @@ } } -func (m *DefaultManager) updateExitNodeSelections(info exitNodeInfo) { - routesToDeselect := m.getRoutesToDeselect(info.allIDs) - m.deselectExitNodes(routesToDeselect) - m.selectExitNodesByManagement(info.selectedByManagement, info.allIDs) -} - -func (m *DefaultManager) getRoutesToDeselect(allIDs []route.NetID) []route.NetID { - var routesToDeselect []route.NetID - for _, netID := range allIDs { - if !m.routeSelector.HasUserSelectionForRoute(netID) { - routesToDeselect = append(routesToDeselect, netID) +// pickPreferredExitNode chooses the single exit node to keep selected. In order: +// - a persisted user selection wins (deterministic if several survive from +// legacy state, so the set self-heals down to one); +// - otherwise activate only what management marks for auto-apply +// (SkipAutoApply=false); the lexicographically first if it marks several. +// +// Returns "" when neither holds — we never force an arbitrary exit node on. A +// route the map doesn't auto-apply stays off until the user selects it. +// info.userDeselected is informational only: an explicit deselect simply keeps +// that route out of both lists above, so it can't be picked. +func pickPreferredExitNode(info exitNodeInfo) route.NetID { + if len(info.userSelected) > 0 { + return minNetID(info.userSelected) + } + if len(info.selectedByManagement) > 0 { + return minNetID(info.selectedByManagement) + } + return "" +} + +// enforceSingleExitNode makes preferred the only selected exit node: every other +// available exit node is deselected and preferred (if any) is selected, without +// disturbing non-exit route selections. The whole reconciliation runs under a +// single RouteSelector lock (SetExclusiveExitNode) so a concurrent deselect-all +// cannot interleave and get undone; a global deselect-all is left untouched so +// the user's "all off" stays in effect. +func (m *DefaultManager) enforceSingleExitNode(preferred route.NetID, allIDs []route.NetID) { + m.routeSelector.SetExclusiveExitNode(preferred, allIDs) +} + +func (m *DefaultManager) logExitNodeUpdate(info exitNodeInfo, preferred route.NetID) { + log.Debugf("Exit node selection: %d available, preferred=%q (%d user-selected, %d user-deselected, %d management-selected)", + len(info.allIDs), preferred, len(info.userSelected), len(info.userDeselected), len(info.selectedByManagement)) +} + +// minNetID returns the lexicographically smallest NetID, for a deterministic +// default pick that stays stable across restarts. +func minNetID(ids []route.NetID) route.NetID { + if len(ids) == 0 { + return "" + } + best := ids[0] + for _, id := range ids[1:] { + if id < best { + best = id } } - return routesToDeselect -} - -func (m *DefaultManager) deselectExitNodes(routesToDeselect []route.NetID) { - if len(routesToDeselect) == 0 { - return - } - - err := m.routeSelector.DeselectRoutes(routesToDeselect, routesToDeselect) - if err != nil { - log.Warnf("Failed to deselect exit nodes: %v", err) - } -} - -func (m *DefaultManager) selectExitNodesByManagement(selectedByManagement []route.NetID, allIDs []route.NetID) { - if len(selectedByManagement) == 0 { - return - } - - err := m.routeSelector.SelectRoutes(selectedByManagement, true, allIDs) - if err != nil { - log.Warnf("Failed to select exit nodes: %v", err) - } -} - -func (m *DefaultManager) logExitNodeUpdate(info exitNodeInfo) { - log.Debugf("Updated route selector: %d exit nodes available, %d selected by management, %d user-selected, %d user-deselected", - len(info.allIDs), len(info.selectedByManagement), len(info.userSelected), len(info.userDeselected)) + return best } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/client/internal/routeselector/routeselector.go new/netbird-0.74.2/client/internal/routeselector/routeselector.go --- old/netbird-0.74.1/client/internal/routeselector/routeselector.go 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/client/internal/routeselector/routeselector.go 2026-07-03 12:23:11.000000000 +0200 @@ -115,7 +115,38 @@ clear(rs.selectedRoutes) } -// IsDeselectAll reports whether the user has explicitly deselected all routes. +// SetExclusiveExitNode atomically makes preferred the only selected exit node +// among exitIDs: every other ID in exitIDs is deselected and preferred (when +// non-empty) is selected, all under a single lock. Holding the lock across the +// whole reconciliation prevents a concurrent DeselectAllRoutes from interleaving +// between the deselect and select steps and being silently undone. A global +// deselect-all is left untouched so the user's "all off" stays in effect; +// non-exit routes are never referenced, so their selection is preserved. +func (rs *RouteSelector) SetExclusiveExitNode(preferred route.NetID, exitIDs []route.NetID) { + rs.mu.Lock() + defer rs.mu.Unlock() + + if rs.deselectAll { + return + } + + for _, id := range exitIDs { + if id == preferred { + continue + } + rs.deselectedRoutes[id] = struct{}{} + delete(rs.selectedRoutes, id) + } + + if preferred != "" { + delete(rs.deselectedRoutes, preferred) + rs.selectedRoutes[preferred] = struct{}{} + } +} + +// IsDeselectAll reports whether the global "deselect all" flag is set, i.e. the +// user explicitly disabled every route. Callers enforcing per-route invariants +// (e.g. single exit node) should leave the selection untouched when it is. func (rs *RouteSelector) IsDeselectAll() bool { rs.mu.RLock() defer rs.mu.RUnlock() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/e2e/agentnetwork/vllm_test.go new/netbird-0.74.2/e2e/agentnetwork/vllm_test.go --- old/netbird-0.74.1/e2e/agentnetwork/vllm_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/e2e/agentnetwork/vllm_test.go 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1,171 @@ +//go:build e2e + +package agentnetwork + +import ( + "context" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/netbirdio/netbird/e2e/harness" + "github.com/netbirdio/netbird/shared/management/http/api" +) + +// TestVLLMProvider proves the proxy supports a self-hosted vLLM backend. vLLM is +// OpenAI-compatible, so it uses the "vllm" catalog entry (KindCustom) and is +// reached over plain HTTP — no TLS anywhere on the path: +// +// client --tunnel--> netbird proxy --http--> vllm (:8000, OpenAI-compatible) +// +// The mock vLLM server answers /v1/chat/completions with an OpenAI-shaped +// completion carrying a non-zero usage block. The test asserts the chat returns +// 200 with the completion, that the request is recorded in the access log by its +// session id, and that vLLM's usage block is metered into a consumption row — +// which together prove request routing, response parsing, and token accounting +// all work for a self-hosted OpenAI-compatible provider. +// +// It needs no external credentials (the mock ignores auth), so it always runs. +func TestVLLMProvider(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) + defer cancel() + + vllm, err := harness.StartVLLM(ctx, srv) + require.NoError(t, err, "start mock vLLM server") + t.Cleanup(func() { _ = vllm.Terminate(context.Background()) }) + + grp, err := srv.API().Groups.Create(ctx, api.PostApiGroupsJSONRequestBody{Name: "e2e-vllm"}) + require.NoError(t, err, "create group") + t.Cleanup(func() { _ = srv.API().Groups.Delete(context.Background(), grp.Id) }) + + ephemeral := false + sk, err := srv.API().SetupKeys.Create(ctx, api.PostApiSetupKeysJSONRequestBody{ + Name: "e2e-vllm-client", + Type: "reusable", + ExpiresIn: 86400, + UsageLimit: 0, + AutoGroups: []string{grp.Id}, + Ephemeral: &ephemeral, + }) + require.NoError(t, err, "mint setup key") + require.NotEmpty(t, sk.Key, "setup key plaintext") + + // vLLM provider pointed at the mock over plain HTTP. The mock ignores auth, + // so a dummy key satisfies the "Bearer ${API_KEY}" template. The served model + // is enumerated so the router dispatches this model string to this provider. + dummyKey := "sk-vllm-e2e" + prov, err := srv.CreateProvider(ctx, api.AgentNetworkProviderRequest{ + Name: "vllm", + ProviderId: "vllm", + UpstreamUrl: vllm.URL, + ApiKey: &dummyKey, + Enabled: ptr(true), + BootstrapCluster: ptr(harness.AgentNetworkCluster), + Models: &[]api.AgentNetworkProviderModel{ + {Id: harness.VLLMModel, InputPer1k: 0.001, OutputPer1k: 0.002}, + }, + }) + require.NoError(t, err, "create vllm provider") + t.Cleanup(func() { _ = srv.DeleteProvider(context.Background(), prov.Id) }) + + // Token limit far above the handful of tokens this test drives, so it never + // blocks but switches on usage metering — the switch that makes consumption + // rows get recorded. + enabled := true + pol, err := srv.CreatePolicy(ctx, api.AgentNetworkPolicyRequest{ + Name: "e2e-vllm-allow", + Enabled: &enabled, + SourceGroups: []string{grp.Id}, + DestinationProviderIds: []string{prov.Id}, + Limits: &api.AgentNetworkPolicyLimits{ + TokenLimit: api.AgentNetworkPolicyTokenLimit{ + Enabled: true, + GroupCap: 10_000_000, + UserCap: 10_000_000, + WindowSeconds: 60, + }, + }, + }) + require.NoError(t, err, "create policy") + t.Cleanup(func() { _ = srv.DeletePolicy(context.Background(), pol.Id) }) + + settings, err := srv.GetSettings(ctx) + require.NoError(t, err, "read settings") + require.NotEmpty(t, settings.Endpoint, "endpoint must be assigned") + + proxyToken, err := srv.CreateProxyTokenCLI(ctx, "e2e-vllm-proxy") + require.NoError(t, err, "mint proxy token") + px, err := harness.StartProxy(ctx, srv, proxyToken) + require.NoError(t, err, "start proxy") + t.Cleanup(func() { _ = px.Terminate(context.Background()) }) + + cl, err := harness.StartClient(ctx, srv, sk.Key) + require.NoError(t, err, "start client") + t.Cleanup(func() { _ = cl.Terminate(context.Background()) }) + + require.NoError(t, cl.WaitConnected(ctx, 90*time.Second), "client must connect to management") + if err := cl.WaitProxyPeer(ctx, 180*time.Second); err != nil { + t.Fatalf("client did not see the proxy peer: %v\n=== proxy logs ===\n%s", err, px.Logs(context.Background())) + } + proxyIP, err := cl.ResolveProxyIP(ctx, settings.Endpoint) + require.NoError(t, err, "resolve endpoint to proxy IP") + + before, _ := srv.ListAccessLogs(ctx) + sessionID := "e2e-session-vllm" + + // Retry to absorb tunnel/DNS jitter on the first call. + var code int + var body string + deadline := time.Now().Add(90 * time.Second) + for time.Now().Before(deadline) { + c, b, cerr := cl.Chat(ctx, settings.Endpoint, proxyIP, harness.WireChat, harness.VLLMModel, "Reply with exactly: pong", sessionID) + if cerr == nil { + code, body = c, b + if code == 200 { + break + } + } + time.Sleep(5 * time.Second) + } + require.Equal(t, 200, code, + "chat through the vLLM provider must return 200; body: %s\n=== vllm logs ===\n%s\n=== proxy logs ===\n%s", + body, vllm.Logs(context.Background()), px.Logs(context.Background())) + require.True(t, strings.Contains(body, "chat.completion"), + "body should be an OpenAI-compatible chat completion; got: %s", body) + + // The request must surface as an access-log row carrying our session id. + require.Eventually(t, func() bool { + logs, lerr := srv.ListAccessLogs(ctx) + return lerr == nil && logs.TotalRecords > before.TotalRecords + }, 30*time.Second, 2*time.Second, "an access-log row should be ingested for the vLLM provider") + + require.Eventually(t, func() bool { + logs, lerr := srv.ListAccessLogs(ctx) + if lerr != nil { + return false + } + for _, r := range logs.Data { + if r.SessionId != nil && *r.SessionId == sessionID { + return true + } + } + return false + }, 30*time.Second, 2*time.Second, "session id %q must be recorded in an access-log row", sessionID) + + // vLLM's usage block (prompt_tokens=11, completion_tokens=2) must be parsed + // and metered into a consumption row with positive token counts. + require.Eventually(t, func() bool { + rows, lerr := srv.ListConsumption(ctx) + if lerr != nil { + return false + } + for _, r := range rows { + if r.TokensInput > 0 && r.TokensOutput > 0 { + return true + } + } + return false + }, 60*time.Second, 3*time.Second, "vLLM usage must be metered into a consumption row") +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/e2e/harness/vllm.go new/netbird-0.74.2/e2e/harness/vllm.go --- old/netbird-0.74.1/e2e/harness/vllm.go 1970-01-01 01:00:00.000000000 +0100 +++ new/netbird-0.74.2/e2e/harness/vllm.go 2026-07-03 12:23:11.000000000 +0200 @@ -0,0 +1,113 @@ +//go:build e2e + +package harness + +import ( + "context" + "fmt" + "os" + "path/filepath" + "time" + + "github.com/docker/docker/api/types/container" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" +) + +const ( + vllmImage = "nginx:alpine" + vllmAlias = "vllm" + vllmPort = "8000/tcp" + // VLLMModel is the served model id the mock advertises and echoes back. It + // matches a real small model commonly served by vLLM so the provider's + // enumerated model and the client's request line up. + VLLMModel = "Qwen/Qwen2.5-0.5B-Instruct" +) + +// vllmNginxConf emulates a vLLM OpenAI-compatible server over plain HTTP (vLLM's +// default: no TLS, port 8000). It answers /v1/models with a one-model list and +// any chat/completions path with a canned OpenAI-shaped chat completion carrying +// a non-zero usage block, so the proxy's OpenAI parser records real token +// consumption. Running actual vLLM in CI is infeasible (GPU + multi-GB model +// download), so this stands in for the wire contract the proxy depends on. +const vllmNginxConf = `pid /tmp/nginx.pid; +events {} +http { + server { + listen 8000; + location = /v1/models { + default_type application/json; + return 200 '{"object":"list","data":[{"id":"Qwen/Qwen2.5-0.5B-Instruct","object":"model","owned_by":"vllm"}]}'; + } + location / { + default_type application/json; + return 200 '{"id":"chatcmpl-e2e-vllm","object":"chat.completion","created":1700000000,"model":"Qwen/Qwen2.5-0.5B-Instruct","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":11,"completion_tokens":2,"total_tokens":13}}'; + } + } +} +` + +// VLLM is a mock vLLM OpenAI-compatible server on the combined server's network, +// reachable at http://vllm:8000. A "vllm" provider points at it to exercise the +// proxy's support for self-hosted OpenAI-compatible backends. +type VLLM struct { + container testcontainers.Container + workDir string + // URL is the upstream URL the vllm provider points at (http://<alias>:8000). + URL string +} + +// StartVLLM runs the mock vLLM server on the shared network over plain HTTP. +func StartVLLM(ctx context.Context, c *Combined) (*VLLM, error) { + workDir, err := os.MkdirTemp("/tmp", "nb-e2e-vllm-*") + if err != nil { + return nil, fmt.Errorf("create vllm work dir: %w", err) + } + // Widen so the (non-root worker) nginx container can traverse the bind mount. + if err := os.Chmod(workDir, 0o755); err != nil { //nolint:gosec // throwaway e2e config dir + return nil, fmt.Errorf("chmod vllm dir: %w", err) + } + if err := os.WriteFile(filepath.Join(workDir, "nginx.conf"), []byte(vllmNginxConf), 0o644); err != nil { //nolint:gosec // non-secret e2e config + return nil, fmt.Errorf("write nginx conf: %w", err) + } + + req := testcontainers.ContainerRequest{ + Image: vllmImage, + ExposedPorts: []string{vllmPort}, + Networks: []string{c.network.Name}, + NetworkAliases: map[string][]string{c.network.Name: {vllmAlias}}, + Cmd: []string{"nginx", "-c", "/conf/nginx.conf", "-g", "daemon off;"}, + HostConfigModifier: func(hc *container.HostConfig) { + hc.Binds = append(hc.Binds, workDir+":/conf:ro") + }, + WaitingFor: wait.ForListeningPort(vllmPort).WithStartupTimeout(60 * time.Second), + } + + ctr, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + _ = os.RemoveAll(workDir) + return nil, fmt.Errorf("start vllm container: %w", err) + } + + return &VLLM{container: ctr, workDir: workDir, URL: "http://" + vllmAlias + ":8000"}, nil +} + +// Logs returns the vLLM container logs, for diagnostics on failure. +func (v *VLLM) Logs(ctx context.Context) string { + return containerLogs(ctx, v.container) +} + +// Terminate stops the vLLM container and cleans its work dir. +func (v *VLLM) Terminate(ctx context.Context) error { + var err error + if v.container != nil { + err = v.container.Terminate(ctx) + } + if v.workDir != "" { + _ = os.RemoveAll(v.workDir) + } + return err +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/shared/management/client/grpc.go new/netbird-0.74.2/shared/management/client/grpc.go --- old/netbird-0.74.1/shared/management/client/grpc.go 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/shared/management/client/grpc.go 2026-07-03 12:23:11.000000000 +0200 @@ -33,10 +33,15 @@ const healthCheckTimeout = 5 * time.Second const ( - // EnvMaxRecvMsgSize overrides the default gRPC max receive message size (4 MB) + // EnvMaxRecvMsgSize overrides the default gRPC max receive message size // for the management client connection. Value is in bytes. EnvMaxRecvMsgSize = "NB_MANAGEMENT_GRPC_MAX_MSG_SIZE" + // defaultMaxRecvMsgSize is the max gRPC receive message size used for the + // management client connection when EnvMaxRecvMsgSize is unset or invalid. + // It overrides the gRPC library default of 4 MB. + defaultMaxRecvMsgSize = 1024 * 1024 * 16 + errMsgMgmtPublicKey = "failed getting Management Service public key: %s" errMsgNoMgmtConnection = "no connection to management" ) @@ -84,22 +89,22 @@ } // MaxRecvMsgSize returns the configured max gRPC receive message size from -// the environment, or 0 if unset (which uses the gRPC default of 4 MB). +// the environment, or defaultMaxRecvMsgSize (16 MB) if unset or invalid. func MaxRecvMsgSize() int { val := os.Getenv(EnvMaxRecvMsgSize) if val == "" { - return 0 + return defaultMaxRecvMsgSize } size, err := strconv.Atoi(val) if err != nil { log.Warnf("invalid %s value %q, using default: %v", EnvMaxRecvMsgSize, val, err) - return 0 + return defaultMaxRecvMsgSize } if size <= 0 { log.Warnf("invalid %s value %d, must be positive, using default", EnvMaxRecvMsgSize, size) - return 0 + return defaultMaxRecvMsgSize } return size diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netbird-0.74.1/shared/management/client/grpc_test.go new/netbird-0.74.2/shared/management/client/grpc_test.go --- old/netbird-0.74.1/shared/management/client/grpc_test.go 2026-07-02 14:55:55.000000000 +0200 +++ new/netbird-0.74.2/shared/management/client/grpc_test.go 2026-07-03 12:23:11.000000000 +0200 @@ -21,11 +21,11 @@ envValue string expected int }{ - {name: "unset returns 0", envValue: "", expected: 0}, + {name: "unset returns default", envValue: "", expected: defaultMaxRecvMsgSize}, {name: "valid value", envValue: "10485760", expected: 10485760}, - {name: "non-numeric returns 0", envValue: "abc", expected: 0}, - {name: "negative returns 0", envValue: "-1", expected: 0}, - {name: "zero returns 0", envValue: "0", expected: 0}, + {name: "non-numeric returns default", envValue: "abc", expected: defaultMaxRecvMsgSize}, + {name: "negative returns default", envValue: "-1", expected: defaultMaxRecvMsgSize}, + {name: "zero returns default", envValue: "0", expected: defaultMaxRecvMsgSize}, } for _, tt := range tests { ++++++ netbird.obsinfo ++++++ --- /var/tmp/diff_new_pack.DWhuTn/_old 2026-07-06 12:31:15.009135754 +0200 +++ /var/tmp/diff_new_pack.DWhuTn/_new 2026-07-06 12:31:15.013135893 +0200 @@ -1,5 +1,5 @@ name: netbird -version: 0.74.1 -mtime: 1782996955 -commit: 859fe19fff6661ed0ba7904b42ed8b12d72c36f5 +version: 0.74.2 +mtime: 1783074191 +commit: 3aa6c02b932db503e82f9530dddfe95d5ea212c4 ++++++ vendor.tar.zst ++++++ /work/SRC/openSUSE:Factory/netbird/vendor.tar.zst /work/SRC/openSUSE:Factory/.netbird.new.1982/vendor.tar.zst differ: char 7, line 1
