mirror of
https://github.com/juanfont/headscale.git
synced 2026-10-03 21:33:36 +09:00
policy/v2: compare peer CapMap against SaaS route captures
SaaS stamps suggest-exit-node on approved exit peers without nodeAttrs. Updates #3415
This commit is contained in:
committed by
Kristoffer Dalby
parent
e48bc46cc6
commit
0e8a3bba54
@@ -1506,6 +1506,76 @@ func TestRoutesCompatPeerAllowedIPs(t *testing.T) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestRoutesCompatPeerCapMap validates the peer-view CapMap against SaaS
|
||||||
|
// for route scenarios, whose policies carry no nodeAttrs. SaaS stamps
|
||||||
|
// suggest-exit-node on approved exit peers regardless of policy; the
|
||||||
|
// Apple 1.102+ GUI hides the exit-node list without it (issue #3415).
|
||||||
|
func TestRoutesCompatPeerCapMap(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
files, err := filepath.Glob(
|
||||||
|
filepath.Join("testdata", "routes_results", "routes-*.hujson"),
|
||||||
|
)
|
||||||
|
require.NoError(t, err, "failed to glob test files")
|
||||||
|
require.NotEmpty(t, files)
|
||||||
|
|
||||||
|
issue3212, err := filepath.Glob(
|
||||||
|
filepath.Join("testdata", "issue_3212", "routes-*.hujson"),
|
||||||
|
)
|
||||||
|
require.NoError(t, err, "failed to glob issue_3212 files")
|
||||||
|
require.NotEmpty(t, issue3212)
|
||||||
|
|
||||||
|
files = append(files, issue3212...)
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
tf := loadRoutesTestFile(t, file)
|
||||||
|
if tf.Error {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run(tf.TestID, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
users, nodes := buildRoutesUsersAndNodes(t, tf.Topology)
|
||||||
|
policyJSON := convertPolicyUserEmails(tf.Input.FullPolicy)
|
||||||
|
|
||||||
|
pm, err := NewPolicyManager(policyJSON, users, nodes.ViewSlice())
|
||||||
|
require.NoError(t, err, "%s: failed to create policy manager", tf.TestID)
|
||||||
|
|
||||||
|
capMaps := pm.NodeCapMaps()
|
||||||
|
|
||||||
|
for viewerName, capture := range tf.Captures {
|
||||||
|
if capture.Netmap == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, nmPeer := range capture.Netmap.Peers {
|
||||||
|
peerName, _, _ := strings.Cut(nmPeer.Name(), ".")
|
||||||
|
|
||||||
|
peer := findNodeByGivenName(nodes, peerName)
|
||||||
|
if peer == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
got := stripUnmodelledTailnetStateCaps(
|
||||||
|
PeerCapMap(peer.View(), capMaps[peer.ID]),
|
||||||
|
)
|
||||||
|
want := stripUnmodelledTailnetStateCaps(
|
||||||
|
capMapFromView(nmPeer.CapMap()),
|
||||||
|
)
|
||||||
|
|
||||||
|
if diff := cmp.Diff(want, got, cmpopts.EquateEmpty()); diff != "" {
|
||||||
|
t.Errorf(
|
||||||
|
"%s/%s/peer=%s: Peer.CapMap mismatch (-tailscale +headscale):\n%s",
|
||||||
|
tf.TestID, viewerName, peerName, diff,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// testRoutesError verifies that an invalid policy produces the expected error.
|
// testRoutesError verifies that an invalid policy produces the expected error.
|
||||||
func testRoutesError(t *testing.T, tf *testcapture.Capture) {
|
func testRoutesError(t *testing.T, tf *testcapture.Capture) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|||||||
Reference in New Issue
Block a user