mirror of
https://github.com/juanfont/headscale.git
synced 2026-10-10 08:40:07 +09:00
state: stop tag approval sorting the reported RequestTags
nodeToRegister.Tags aliased Hostinfo.RequestTags, so sort/compact rewrote the stored Hostinfo ([b a a] became [a b ""]).
This commit is contained in:
committed by
Kristoffer Dalby
parent
a99c8a030c
commit
9c34c0c90d
@@ -270,6 +270,42 @@ func TestRegistrationRejectsNodeKeyClaimedByAnotherMachine(t *testing.T) {
|
||||
"registering a NodeKey already bound to another machine must be rejected")
|
||||
}
|
||||
|
||||
// TestRegistrationKeepsRequestTagsIntact guards the node's reported
|
||||
// Hostinfo.RequestTags against the in-place sort/compact that derives the
|
||||
// approved tag set: the two must not share a backing array.
|
||||
func TestRegistrationKeepsRequestTagsIntact(t *testing.T) {
|
||||
dbPath := t.TempDir() + "/headscale.db"
|
||||
cfg := persistTestConfig(dbPath)
|
||||
|
||||
database, err := db.NewHeadscaleDatabase(cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
user := database.CreateUserForTest("tagger")
|
||||
require.NoError(t, database.Close())
|
||||
|
||||
s, err := NewState(cfg)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { _ = s.Close() })
|
||||
|
||||
_, err = s.SetPolicy([]byte(`{"tagOwners":{"tag:a":["tagger@"],"tag:b":["tagger@"]}}`))
|
||||
require.NoError(t, err)
|
||||
|
||||
node, err := s.createAndSaveNewNode(newNodeParams{
|
||||
User: *user,
|
||||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
DiscoKey: key.NewDisco().Public(),
|
||||
Hostname: "node",
|
||||
Hostinfo: &tailcfg.Hostinfo{RequestTags: []string{"tag:b", "tag:a", "tag:a"}},
|
||||
RegisterMethod: util.RegisterMethodCLI,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, []string{"tag:a", "tag:b"}, node.Tags().AsSlice())
|
||||
assert.Equal(t, []string{"tag:b", "tag:a", "tag:a"}, node.Hostinfo().RequestTags().AsSlice(),
|
||||
"reported RequestTags rewritten by tag approval")
|
||||
}
|
||||
|
||||
// TestReauthRejectsNodeKeyClaimedByAnotherMachine proves the re-auth/update
|
||||
// path enforces the same 1:1 NodeKey<->MachineKey binding as the create path
|
||||
// (TestRegistrationRejectsNodeKeyClaimedByAnotherMachine) and the poll path
|
||||
|
||||
@@ -2114,9 +2114,8 @@ func (s *State) createAndSaveNewNode(params newNodeParams) (types.NodeView, erro
|
||||
// All tags are approved - apply them
|
||||
approvedTags := params.Hostinfo.RequestTags
|
||||
if len(approvedTags) > 0 {
|
||||
nodeToRegister.Tags = approvedTags
|
||||
slices.Sort(nodeToRegister.Tags)
|
||||
nodeToRegister.Tags = slices.Compact(nodeToRegister.Tags)
|
||||
// Sort a copy: approvedTags is the node's reported Hostinfo.
|
||||
nodeToRegister.Tags = slices.Compact(slices.Sorted(slices.Values(approvedTags)))
|
||||
|
||||
// Node is now tagged, so clear user ownership.
|
||||
// Tagged nodes are owned by their tags, not a user.
|
||||
|
||||
Reference in New Issue
Block a user