package main import ( "context" "testing" "time" "github.com/novox/mesh-controller/internal/inventory" ) // aMachineJoining is a machine with a live token issued for a tunnel key, given its address — what // `token issue --overlay-key` records before it pushes the hub (novox/hq ADR 0169). func aMachineJoining(t *testing.T, ctx context.Context, inv *inventory.Inventory, name string, validFor time.Duration) string { t.Helper() record, err := inv.AddNode(ctx, name) if err != nil { t.Fatal(err) } if _, err := inv.IssueToken(ctx, name, validFor); err != nil { t.Fatal(err) } key := aPublicKey(t) if err := inv.RecordOverlayKey(ctx, record.ID, key); err != nil { t.Fatal(err) } if err := inv.BindTokenToKey(ctx, record.ID, key); err != nil { t.Fatal(err) } cidr, err := overlayRange(ctx, inv) if err != nil { t.Fatal(err) } if _, err := inv.AssignAddress(ctx, record.ID, cidr); err != nil { t.Fatal(err) } return key } // hubPeers are the keys the hub's composed tunnel carries. func hubPeers(t *testing.T, ctx context.Context, inv *inventory.Inventory) map[string]bool { t.Helper() g, err := network(ctx, inv, map[string]bool{"anchor": true, "laptop": true}, nil) if err != nil { t.Fatal(err) } out := map[string]bool{} for _, p := range g.Graph()["anchor"] { out[p.Key] = true } return out } // **A machine joining is a peer of the hub while its token can be used, and not after** (novox/hq // ADR 0169): the hub's composed tunnel carries a machine whose token was issued for its key, so the // tunnel answers the first time it knocks; a token that expired unused takes the peer with it at the // hub's next composition. func TestAMachineJoiningIsAPeerOfTheHubUntilItsTokenExpires(t *testing.T) { open := aMesh(t) ctx := t.Context() inv := open.inventory joining := aMachineJoining(t, ctx, inv, "joiner", time.Hour) expired := aMachineJoining(t, ctx, inv, "late", 2*time.Second) time.Sleep(2100 * time.Millisecond) peers := hubPeers(t, ctx, inv) if !peers[joining] { t.Fatalf("the hub does not carry the machine its live token was issued for: %v", peers) } if peers[expired] { t.Fatalf("the hub still carries a machine whose token expired unused: %v", peers) } // A token issued without a key gives the hub nothing to carry: there is no key to carry. if _, err := inv.AddNode(ctx, "keyless"); err != nil { t.Fatal(err) } if _, err := inv.IssueToken(ctx, "keyless", time.Hour); err != nil { t.Fatal(err) } if after := hubPeers(t, ctx, inv); len(after) != len(peers) { t.Fatalf("a token issued without a key changed the hub's peers: %v, was %v", after, peers) } } // **A tunnel key that is not one is refused before anything is recorded** (novox/hq ADR 0169): a // token issued for it would be a tunnel the hub could never answer. func TestATokenIsNotIssuedForSomethingThatIsNotATunnelKey(t *testing.T) { open := aMesh(t) ctx := t.Context() record, err := open.inventory.AddNode(ctx, "joiner") if err != nil { t.Fatal(err) } if _, _, err := throughTheTunnel(ctx, open, record, "not-a-key", "10.77.0.1:4222"); err == nil { t.Fatal("a token was issued for something that is not a tunnel key") } if held := placementOf(t, ctx, open.inventory, "joiner"); held.Key != "" || held.Address != "" { t.Fatalf("a refused key left a record behind: %+v", held) } }