tka,ipn: reduce boilerplate in Tailnet Lock tests
The `CreateStateForTest` helper reduces boilerplate in cases where the test only cares about the trusted keys and not the disablement values (and makes it more obvious where the disablement values are meaningful). The `setupChonkStorage` helper reduces the boilerplate when creating on-disk TKA storage in tests. The `fakeLocalBackend` helper reduces the boilerplate when setting up a `LocalBackend` instance in the IPN tests. Updates #cleanup Change-Id: Iacfba1be5f7fab208eec11e4369d63c7d7519da5 Signed-off-by: Alex Chan <alexc@tailscale.com>
This commit is contained in:
+14
-28
@@ -27,12 +27,10 @@ func (s signer25519) SignAUM(sigHash tkatype.AUMSigHash) ([]tkatype.Signature, e
|
||||
func TestAuthorityBuilderAddKey(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
storage := ChonkMem()
|
||||
a, _, err := Create(storage, State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a, _, err := Create(storage, state, signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
@@ -61,12 +59,10 @@ func TestAuthorityBuilderAddKey(t *testing.T) {
|
||||
func TestAuthorityBuilderMaxKey(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
storage := ChonkMem()
|
||||
a, _, err := Create(storage, State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a, _, err := Create(storage, state, signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
@@ -108,12 +104,10 @@ func TestAuthorityBuilderRemoveKey(t *testing.T) {
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
pub2, _ := testingKey25519(t, 2)
|
||||
key2 := Key{Kind: Key25519, Public: pub2, Votes: 1}
|
||||
state := CreateStateForTest(key, key2)
|
||||
|
||||
storage := ChonkMem()
|
||||
a, _, err := Create(storage, State{
|
||||
Keys: []Key{key, key2},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a, _, err := Create(storage, state, signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
@@ -154,12 +148,10 @@ func TestAuthorityBuilderRemoveKey(t *testing.T) {
|
||||
func TestAuthorityBuilderSetKeyVote(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
storage := ChonkMem()
|
||||
a, _, err := Create(storage, State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a, _, err := Create(storage, state, signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
@@ -190,12 +182,10 @@ func TestAuthorityBuilderSetKeyVote(t *testing.T) {
|
||||
func TestAuthorityBuilderSetKeyMeta(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2, Meta: map[string]string{"a": "b"}}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
storage := ChonkMem()
|
||||
a, _, err := Create(storage, State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a, _, err := Create(storage, state, signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
@@ -226,12 +216,10 @@ func TestAuthorityBuilderSetKeyMeta(t *testing.T) {
|
||||
func TestAuthorityBuilderMultiple(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
storage := ChonkMem()
|
||||
a, _, err := Create(storage, State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a, _, err := Create(storage, state, signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
@@ -274,12 +262,10 @@ func TestAuthorityBuilderMultiple(t *testing.T) {
|
||||
func TestAuthorityBuilderCheckpointsAfterXUpdates(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
storage := ChonkMem()
|
||||
a, _, err := Create(storage, State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a, _, err := Create(storage, state, signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -321,10 +321,8 @@ func optTemplate(name string, template AUM) testchainOpt {
|
||||
}
|
||||
|
||||
func genesisTemplate(key Key) testchainOpt {
|
||||
return optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}})
|
||||
state := CreateStateForTest(key)
|
||||
return optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &state})
|
||||
}
|
||||
|
||||
func checkpointTemplate() testchainOpt {
|
||||
|
||||
+2
-4
@@ -72,10 +72,8 @@ func TestNLPrivate(t *testing.T) {
|
||||
// Test that key.NLPrivate implements Signer by making a new
|
||||
// authority.
|
||||
k := Key{Kind: Key25519, Public: pub.Verifier(), Votes: 1}
|
||||
_, aum, err := Create(ChonkMem(), State{
|
||||
Keys: []Key{k},
|
||||
DisablementValues: [][]byte{bytes.Repeat([]byte{1}, 32)},
|
||||
}, p)
|
||||
state := CreateStateForTest(k)
|
||||
_, aum, err := Create(ChonkMem(), state, p)
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"golang.org/x/crypto/argon2"
|
||||
"tailscale.com/types/tkatype"
|
||||
"tailscale.com/util/testenv"
|
||||
)
|
||||
|
||||
// ErrNoSuchKey is returned if the key referenced by a KeyID does not exist.
|
||||
@@ -313,3 +314,18 @@ func (s *State) staticValidateCheckpoint() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateStateForTest creates a [State] that marks the given keys as trusted
|
||||
// with an arbitrary disablement value.
|
||||
//
|
||||
// This is only for use in tests, and will panic if called outside a test.
|
||||
func CreateStateForTest(keys ...Key) State {
|
||||
testenv.AssertInTest()
|
||||
|
||||
disablementSecret := bytes.Repeat([]byte{0xa5}, 32)
|
||||
|
||||
return State{
|
||||
Keys: keys,
|
||||
DisablementValues: [][]byte{DisablementKDF(disablementSecret)},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,12 +597,10 @@ func TestCompactLongButYoung(t *testing.T) {
|
||||
ourPriv := key.NewNLPrivate()
|
||||
ourKey := Key{Kind: Key25519, Public: ourPriv.Public().Verifier(), Votes: 1}
|
||||
someOtherKey := Key{Kind: Key25519, Public: key.NewNLPrivate().Public().Verifier(), Votes: 1}
|
||||
state := CreateStateForTest(ourKey, someOtherKey)
|
||||
|
||||
storage := ChonkMem()
|
||||
auth, _, err := Create(storage, State{
|
||||
Keys: []Key{ourKey, someOtherKey},
|
||||
DisablementValues: [][]byte{DisablementKDF(bytes.Repeat([]byte{0xa5}, 32))},
|
||||
}, ourPriv)
|
||||
auth, _, err := Create(storage, state, ourPriv)
|
||||
if err != nil {
|
||||
t.Fatalf("tka.Create() failed: %v", err)
|
||||
}
|
||||
|
||||
+20
-29
@@ -197,6 +197,7 @@ func TestComputeStateAt(t *testing.T) {
|
||||
// for tests you want one AUM to be 'lower' than another, so that
|
||||
// that chain is taken based on fork resolution rules).
|
||||
func fakeAUM(t *testing.T, template any, parent *AUMHash) (AUM, AUMHash) {
|
||||
t.Helper()
|
||||
if seed, ok := template.(int); ok {
|
||||
a := AUM{MessageKind: AUMNoOp, KeyID: []byte{byte(seed)}}
|
||||
if parent != nil {
|
||||
@@ -299,12 +300,17 @@ func TestAuthorityHead(t *testing.T) {
|
||||
func TestAuthorityValidDisablement(t *testing.T) {
|
||||
pub, _ := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
disablementSecret := []byte{1, 2, 3}
|
||||
state := State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF(disablementSecret)},
|
||||
}
|
||||
c := newTestchain(t, `
|
||||
G1 -> L1
|
||||
|
||||
G1.template = genesis
|
||||
`,
|
||||
genesisTemplate(key),
|
||||
optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &state}),
|
||||
)
|
||||
|
||||
a, _ := Open(c.Chonk())
|
||||
@@ -317,10 +323,7 @@ func TestCreateBootstrapAuthority(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
|
||||
a1, genesisAUM, err := Create(ChonkMem(), State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a1, genesisAUM, err := Create(ChonkMem(), CreateStateForTest(key), signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
@@ -349,10 +352,7 @@ func TestBootstrapChonkMustBeEmpty(t *testing.T) {
|
||||
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
state := State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
// Bootstrap our chonk for the first time, which should succeed.
|
||||
_, _, err := Create(chonk, state, signer25519(priv))
|
||||
@@ -412,7 +412,7 @@ func TestAuthorityInformNonLinear(t *testing.T) {
|
||||
| -> L4 -> L5
|
||||
|
||||
G1.template = genesis
|
||||
L1.hashSeed = 3
|
||||
L1.hashSeed = 2
|
||||
L2.hashSeed = 2
|
||||
L4.hashSeed = 2
|
||||
`,
|
||||
@@ -445,6 +445,8 @@ func TestAuthorityInformNonLinear(t *testing.T) {
|
||||
}
|
||||
|
||||
if a.Head() != c.AUMHashes["L3"] {
|
||||
t.Logf("a.Head() = %s", a.Head())
|
||||
t.Logf("auMHashes = %v", c.AUMHashes)
|
||||
t.Fatal("authority did not converge to correct AUM")
|
||||
}
|
||||
}
|
||||
@@ -495,21 +497,12 @@ func TestInteropWithNLKey(t *testing.T) {
|
||||
pub2 := key.NewNLPrivate().Public()
|
||||
pub3 := key.NewNLPrivate().Public()
|
||||
|
||||
a, _, err := Create(ChonkMem(), State{
|
||||
Keys: []Key{
|
||||
{
|
||||
Kind: Key25519,
|
||||
Votes: 1,
|
||||
Public: pub1.KeyID(),
|
||||
},
|
||||
{
|
||||
Kind: Key25519,
|
||||
Votes: 1,
|
||||
Public: pub2.KeyID(),
|
||||
},
|
||||
},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, priv1)
|
||||
state := CreateStateForTest(
|
||||
Key{Kind: Key25519, Votes: 1, Public: pub1.KeyID()},
|
||||
Key{Kind: Key25519, Votes: 1, Public: pub2.KeyID()},
|
||||
)
|
||||
|
||||
a, _, err := Create(ChonkMem(), state, priv1)
|
||||
if err != nil {
|
||||
t.Errorf("tka.Create: %v", err)
|
||||
return
|
||||
@@ -529,6 +522,7 @@ func TestInteropWithNLKey(t *testing.T) {
|
||||
func TestAuthorityCompact(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
c := newTestchain(t, `
|
||||
G -> A -> B -> C -> D -> E
|
||||
@@ -537,10 +531,7 @@ func TestAuthorityCompact(t *testing.T) {
|
||||
C.template = checkpoint2
|
||||
`,
|
||||
genesisTemplate(key),
|
||||
optTemplate("checkpoint2", AUM{MessageKind: AUMCheckpoint, State: &State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}}),
|
||||
optTemplate("checkpoint2", AUM{MessageKind: AUMCheckpoint, State: &state}),
|
||||
optKey("key", key, priv),
|
||||
optSignAllUsing("key"))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user