Files
privatae-bastion/client-go/pair_anchor_test.go
T
Privatae 48899b41a9
ci / personal-data (push) Successful in 4s
ci / test (push) Successful in 4m58s
ci / fuzz (push) Successful in 3m33s
bastion 0.63.1
2026-11-03 22:56:18 +00:00

123 lines
3.9 KiB
Go

//go:build !windows
package main
import (
"path/filepath"
"testing"
)
// TestPairAnchorsANetworkedMachineToItsFirstHost: on a networked machine with
// no anchor, the first pairing anchors it (as claim-anchor with no token
// would), so a server is not left refusing everything until claim-anchor is
// run by hand. A local machine,
// an already anchored one, a second pairing, or a caller without machine
// authority are left as they were.
func TestPairAnchorsANetworkedMachineToItsFirstHost(t *testing.T) {
held := true
old := machineAuthorityHeld
machineAuthorityHeld = func() bool { return held }
t.Cleanup(func() { machineAuthorityHeld = old })
box := func(t *testing.T, networked bool) {
t.Helper()
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
withMarkerAt(t, filepath.Join(t.TempDir(), "machine.json"))
if networked {
if err := setBoxMode(modeNetworked); err != nil {
t.Fatal(err)
}
}
}
only := func(t *testing.T, host string) (*Config, []*Config) {
t.Helper()
all, err := loadPairings()
if err != nil {
t.Fatal(err)
}
return pairingFor(all, host), all
}
t.Run("networked, no anchor, first pairing: anchored and active", func(t *testing.T) {
held = true
box(t, true)
writePairingState(t, tMember, pairingPending)
cfg, all := only(t, tMember)
anchored, err := anchoredAfterPair(cfg, all)
if err != nil || !anchored {
t.Fatalf("the first pairing on a networked box must anchor it: anchored=%v err=%v", anchored, err)
}
if a := currentAnchor(); a == nil || a.AnchorHost != tMember {
t.Fatalf("anchor = %+v, want %s", a, tMember)
}
if got := loadState(t, tMember); got != pairingActive {
t.Fatalf("the anchor never waits on itself: state %q", got)
}
// The installer's claim-anchor after it finds the work done.
if err := cmdClaimAnchor("", false, "", ""); err != nil {
t.Fatalf("claim-anchor after pair must succeed: %v", err)
}
})
t.Run("local machine: not anchored", func(t *testing.T) {
held = true
box(t, false)
writePairing(t, tMember)
cfg, all := only(t, tMember)
if anchored, err := anchoredAfterPair(cfg, all); anchored || err != nil {
t.Fatalf("a local machine must not be anchored: %v %v", anchored, err)
}
if currentAnchor() != nil {
t.Fatal("a local machine has no anchor")
}
})
t.Run("already anchored: a new pairing stays pending", func(t *testing.T) {
held = true
box(t, true)
writePairing(t, tAnchor)
if err := writeAnchor("Acme", tAnchor); err != nil {
t.Fatal(err)
}
writePairingState(t, tMember, pairingPending)
cfg, all := only(t, tMember)
if anchored, err := anchoredAfterPair(cfg, all); anchored || err != nil {
t.Fatalf("an anchored machine must not be re-anchored: %v %v", anchored, err)
}
if a := currentAnchor(); a == nil || a.AnchorHost != tAnchor {
t.Fatalf("anchor moved: %+v", a)
}
if got := loadState(t, tMember); got != pairingPending {
t.Fatalf("a later host waits for the anchor's approval: state %q", got)
}
})
t.Run("a second pairing on an unanchored machine: left for claim-anchor --host", func(t *testing.T) {
held = true
box(t, true)
writePairing(t, tAnchor)
writePairingState(t, tMember, pairingPending)
cfg, all := only(t, tMember)
if anchored, err := anchoredAfterPair(cfg, all); anchored || err != nil {
t.Fatalf("with two pairings the person picks the anchor: %v %v", anchored, err)
}
})
t.Run("no machine authority: not anchored", func(t *testing.T) {
held = true
box(t, true) // set-mode networked itself needs machine authority
writePairingState(t, tMember, pairingPending)
held = false
cfg, all := only(t, tMember)
if anchored, err := anchoredAfterPair(cfg, all); anchored || err != nil {
t.Fatalf("without machine authority nothing is anchored: %v %v", anchored, err)
}
})
}
// anchoredAfterPair is anchorAfterPair's yes or no.
func anchoredAfterPair(cfg *Config, all []*Config) (bool, error) {
t, err := anchorAfterPair(cfg, all)
return t.Taken, err
}