tstest/integration: add integration test for Tailnet Lock

This patch adds an integration test for Tailnet Lock, checking that a node can't
talk to peers in the tailnet until it becomes signed.

This patch also introduces a new package `tstest/tkatest`, which has some helpers
for constructing a mock control server that responds to TKA requests. This allows
us to reduce boilerplate in the IPN tests.

Updates tailscale/corp#33599

Signed-off-by: Alex Chan <alexc@tailscale.com>
This commit is contained in:
Alex Chan
2025-11-19 09:41:43 +00:00
committed by Alex Chan
parent 824027305a
commit b7658a4ad2
7 changed files with 574 additions and 287 deletions
+35
View File
@@ -32,6 +32,41 @@ type SyncOffer struct {
Ancestors []AUMHash
}
// ToSyncOffer creates a SyncOffer from the fields received in
// a [tailcfg.TKASyncOfferRequest].
func ToSyncOffer(head string, ancestors []string) (SyncOffer, error) {
var out SyncOffer
if err := out.Head.UnmarshalText([]byte(head)); err != nil {
return SyncOffer{}, fmt.Errorf("head.UnmarshalText: %v", err)
}
out.Ancestors = make([]AUMHash, len(ancestors))
for i, a := range ancestors {
if err := out.Ancestors[i].UnmarshalText([]byte(a)); err != nil {
return SyncOffer{}, fmt.Errorf("ancestor[%d].UnmarshalText: %v", i, err)
}
}
return out, nil
}
// FromSyncOffer marshals the fields of a SyncOffer so they can be
// sent in a [tailcfg.TKASyncOfferRequest].
func FromSyncOffer(offer SyncOffer) (head string, ancestors []string, err error) {
headBytes, err := offer.Head.MarshalText()
if err != nil {
return "", nil, fmt.Errorf("head.MarshalText: %v", err)
}
ancestors = make([]string, len(offer.Ancestors))
for i, ancestor := range offer.Ancestors {
hash, err := ancestor.MarshalText()
if err != nil {
return "", nil, fmt.Errorf("ancestor[%d].MarshalText: %v", i, err)
}
ancestors[i] = string(hash)
}
return string(headBytes), ancestors, nil
}
const (
// The starting number of AUMs to skip when listing
// ancestors in a SyncOffer.