@@ -748,11 +748,13 @@ def test_user_can_be_assigned_to_multiple_wireguard_interfaces(access_token):
748748 # Get the auto-allocated peer IPs
749749 peer_ips = user ["proxy_settings" ]["wireguard" ]["peer_ips" ]
750750
751- # peer_ips should be empty in user settings (dynamically generated during subscription)
751+ # peer_ips should be persisted in user settings for node sync
752752 assert isinstance (peer_ips , list )
753- assert len (peer_ips ) == 0
753+ assert len (peer_ips ) == 1
754+ assert peer_ips [0 ].startswith ("10." )
755+ assert peer_ips [0 ].endswith ("/32" )
754756
755- # Verify that peer IPs are dynamically generated during subscription
757+ # Verify that WireGuard links use the persisted peer IPs
756758 links_response = client .get (f"{ user ['subscription_url' ]} /links" )
757759 assert links_response .status_code == status .HTTP_200_OK
758760
@@ -763,29 +765,22 @@ def test_user_can_be_assigned_to_multiple_wireguard_interfaces(access_token):
763765 parsed = urlsplit (line .strip ())
764766 links_by_endpoint [f"{ parsed .hostname } :{ parsed .port } " ] = parse_qs (parsed .query )
765767
766- # Both endpoints should have peer IPs generated from interface addresses
767- # User ID 17 with first_interface address "10.30.10.1/24" should get "10.30.10.18/32"
768- # User ID 17 with second_interface address "10.40.10.1/24" should get "10.40.10.18/32"
768+ # Both endpoints should have the same persisted peer IPs
769769 first_address = links_by_endpoint [f"{ first_endpoint } :51820" ]["address" ][0 ]
770770 second_address = links_by_endpoint [f"{ second_endpoint } :51821" ]["address" ][0 ]
771-
772- # Verify IPs are from correct ranges
773- assert first_address .startswith ("10.30.10." )
774- assert second_address .startswith ("10.40.10." )
775- assert first_address .endswith ("/32" )
776- assert second_address .endswith ("/32" )
771+ expected_address = "," .join (peer_ips )
772+ assert first_address == expected_address
773+ assert second_address == expected_address
777774
778775 # Verify WireGuard subscription contains the peer IPs
779776 wireguard_response = client .get (f"{ user ['subscription_url' ]} /wireguard" )
780777 assert wireguard_response .status_code == status .HTTP_200_OK
781778 config_bodies = extract_wireguard_config_bodies (wireguard_response )
782779 assert len (config_bodies ) == 2
783780
784- # Verify each config has correct Address from respective interface
781+ # Verify each config has the same persisted Address
785782 for body in config_bodies :
786- # Should have Address from one of the interfaces
787- assert "Address = 10.30.10." in body or "Address = 10.40.10." in body
788- assert "/32" in body
783+ assert f"Address = { ', ' .join (peer_ips )} " in body
789784
790785 expected_endpoints = {f"Endpoint = { first_endpoint } :51820" , f"Endpoint = { second_endpoint } :51821" }
791786 actual_endpoints = set ()
@@ -797,14 +792,14 @@ def test_user_can_be_assigned_to_multiple_wireguard_interfaces(access_token):
797792
798793 assert actual_endpoints == expected_endpoints
799794
800- # Test no-op update preserves empty peer_ips
795+ # Test no-op update preserves allocated peer_ips
801796 update_response = client .put (
802797 f"/api/user/{ user ['username' ]} " ,
803798 headers = auth_headers (access_token ),
804799 json = {"note" : "keep existing wireguard allocations" },
805800 )
806801 assert update_response .status_code == status .HTTP_200_OK
807- assert update_response .json ()["proxy_settings" ]["wireguard" ]["peer_ips" ] == []
802+ assert update_response .json ()["proxy_settings" ]["wireguard" ]["peer_ips" ] == peer_ips
808803 finally :
809804 delete_user (access_token , user ["username" ])
810805 delete_group (access_token , group ["id" ])
@@ -1668,32 +1663,32 @@ def test_wireguard_peer_ip_global_pool_and_validation(access_token):
16681663 assert response .status_code == status .HTTP_400_BAD_REQUEST
16691664 assert "reserved for the server" in response .json ()["detail" ]
16701665
1671- # Test 2: Create user without specifying peer IPs - should get IP dynamically during subscription
1666+ # Test 2: Create user without specifying peer IPs - should get persisted auto-allocation
16721667 user1 = create_user (
16731668 access_token ,
16741669 group_ids = [group ["id" ]],
16751670 payload = {"username" : unique_name ("wg_auto_ip_user1" )},
16761671 )
1677- # peer_ips should be empty in user settings
1678- assert user1 ["proxy_settings" ]["wireguard" ]["peer_ips" ] == []
1679-
1680- # But subscription should work with dynamically allocated IP from global pool
1672+ peer_ips1 = user1 ["proxy_settings" ]["wireguard" ]["peer_ips" ]
1673+ assert isinstance (peer_ips1 , list )
1674+ assert len (peer_ips1 ) == 1
1675+ assert peer_ips1 [0 ].startswith ("10." )
1676+ assert peer_ips1 [0 ].endswith ("/32" )
1677+ assert peer_ips1 [0 ] != "10.0.0.1/32" # Should not be the reserved server IP
1678+
1679+ # Subscription should use persisted allocation
16811680 links_response = client .get (f"{ user1 ['subscription_url' ]} /links" )
16821681 assert links_response .status_code == status .HTTP_200_OK
16831682
1684- # Should have a wireguard link with an IP from global pool (10.0.0.0/8)
1683+ # Should have a wireguard link with the persisted IP
16851684 link = links_response .text .strip ()
16861685 assert link .startswith ("wireguard://" )
16871686 parsed = urlsplit (link )
16881687 query = parse_qs (parsed .query )
16891688 peer_ip1 = query .get ("address" , ["" ])[0 ]
1690- # Should be an IP from 10.0.0.0/8 pool
1691- assert peer_ip1 .startswith ("10." )
1692- assert peer_ip1 .endswith ("/32" )
1693- assert peer_ip1 != "10.0.0.1/32" # Should not be the reserved server IP
1689+ assert peer_ip1 == peer_ips1 [0 ]
16941690
1695- # Test 3: Manual peer_ip is validated only against stored/manual peer_ips.
1696- # Dynamic subscription-generated addresses are not persisted in user proxy settings.
1691+ # Test 3: Manual peer_ip is validated against stored peer_ips, including auto-allocated ones.
16971692 response = client .post (
16981693 "/api/user" ,
16991694 headers = auth_headers (access_token ),
@@ -1707,28 +1702,28 @@ def test_wireguard_peer_ip_global_pool_and_validation(access_token):
17071702 "group_ids" : [group ["id" ]],
17081703 },
17091704 )
1710- assert response .status_code == status .HTTP_201_CREATED
1711- duplicate_user = response .json ()
1705+ assert response .status_code == status .HTTP_400_BAD_REQUEST
1706+ assert "already in use" in response .json ()[ "detail" ]
17121707
1713- # Test 4: Create another user without specifying peer IPs - should get different IP dynamically
1708+ # Test 4: Create another user without specifying peer IPs - should get different persisted IP
17141709 user2 = create_user (
17151710 access_token ,
17161711 group_ids = [group ["id" ]],
17171712 payload = {"username" : unique_name ("wg_auto_ip_user2" )},
17181713 )
1719- # peer_ips should be empty in user settings
1720- assert user2 ["proxy_settings" ]["wireguard" ]["peer_ips" ] == []
1714+ peer_ips2 = user2 ["proxy_settings" ]["wireguard" ]["peer_ips" ]
1715+ assert isinstance (peer_ips2 , list )
1716+ assert len (peer_ips2 ) == 1
17211717
1722- # Get dynamically allocated IP from subscription
1718+ # Get allocated IP from subscription
17231719 links_response2 = client .get (f"{ user2 ['subscription_url' ]} /links" )
17241720 assert links_response2 .status_code == status .HTTP_200_OK
17251721 link2 = links_response2 .text .strip ()
17261722 assert link2 .startswith ("wireguard://" )
17271723 parsed2 = urlsplit (link2 )
17281724 query2 = parse_qs (parsed2 .query )
17291725 peer_ip2 = query2 .get ("address" , ["" ])[0 ]
1730- assert peer_ip2 .startswith ("10." )
1731- assert peer_ip2 .endswith ("/32" )
1726+ assert peer_ip2 == peer_ips2 [0 ]
17321727 # Different users should get different IPs
17331728 assert peer_ip2 != peer_ip1
17341729
0 commit comments