types/node, mapper, policy/v2: assemble self CapMap inside TailNode
types.NodeView.TailNode takes a selfPolicyCaps tailcfg.NodeCapMap parameter and merges it into the baseline. The mapper's WithSelfNode hands it the policy result via state.NodeCapMap; peer-path callers pass nil because peer-side CapMap is set downstream via policyv2.PeerCapMap. The nodeAttrs compat test now diffs the full TailNode self-view output against captured SaaS netmaps. Before this change the test compared compileNodeAttrs alone -- the policy-only output -- and needed a strip list to compensate for the missing baseline. With TailNode on the diff path, baseline emission is exercised end-to-end by every capture; a regression in TailNode breaks the suite. unmodelledTailnetStateCaps drops cap/ssh and cap/file-sharing now that both sides emit them identically. The file header is rewritten to read as 'caps SaaS emits where headscale has no equivalent yet' rather than the more confusing 'shape divergence' framing.
This commit is contained in:
parent
b3f795f0b4
commit
5ebc53c29e
5 changed files with 77 additions and 64 deletions
|
|
@ -3,6 +3,7 @@ package types
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"strconv"
|
||||
|
|
@ -1127,7 +1128,9 @@ func TailNodes(
|
|||
tNodes := make([]*tailcfg.Node, 0, nodes.Len())
|
||||
|
||||
for _, node := range nodes.All() {
|
||||
tNode, err := node.TailNode(capVer, primaryRouteFunc, cfg)
|
||||
// nil selfPolicyCaps: this batch builds peer views; the caller
|
||||
// sets each peer's CapMap from [policyv2.PeerCapMap].
|
||||
tNode, err := node.TailNode(capVer, primaryRouteFunc, cfg, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -1139,10 +1142,17 @@ func TailNodes(
|
|||
}
|
||||
|
||||
// TailNode converts a NodeView into a Tailscale tailcfg.Node.
|
||||
//
|
||||
// selfPolicyCaps is the per-node CapMap from [policy.PolicyManager.NodeCapMap]
|
||||
// and is merged into the baseline. Pass it when building the self view of the
|
||||
// requesting node; pass nil when building peer views (peer-side
|
||||
// [tailcfg.Node.CapMap] is set by the caller from
|
||||
// [policyv2.PeerCapMap]).
|
||||
func (nv NodeView) TailNode(
|
||||
capVer tailcfg.CapabilityVersion,
|
||||
primaryRouteFunc RouteFunc,
|
||||
cfg *Config,
|
||||
selfPolicyCaps tailcfg.NodeCapMap,
|
||||
) (*tailcfg.Node, error) {
|
||||
if !nv.Valid() {
|
||||
return nil, ErrInvalidNodeView
|
||||
|
|
@ -1204,6 +1214,10 @@ func (nv NodeView) TailNode(
|
|||
capMap[tailcfg.CapabilityFileSharing] = []tailcfg.RawMessage{}
|
||||
}
|
||||
|
||||
// Policy nodeAttrs overlay the baseline on the self view. Peers
|
||||
// pass nil; their CapMap is replaced downstream by [policyv2.PeerCapMap].
|
||||
maps.Copy(capMap, selfPolicyCaps)
|
||||
|
||||
tNode := tailcfg.Node{
|
||||
//nolint:gosec // G115: NodeID values are within int64 range
|
||||
ID: tailcfg.NodeID(nv.ID()),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue