mesh/merge-gate pass: builds netcheck → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery delivered
On novox the tool runner runs as the operator's account, and wg show answered 'Operation not permitted'. Root is the module's concern: the command runs as given when the process is root, else through sudo -n, which the sudo module allows the runtime's account, as nftables does.
91 lines
3.2 KiB
Go
91 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
const privateKey = "aPRIVATEkeyThatMustNeverBeSaidAAAAAAAAAAAA="
|
|
|
|
func dump(now time.Time) string {
|
|
fresh := now.Add(-40 * time.Second).Unix()
|
|
old := now.Add(-10 * time.Minute).Unix()
|
|
return privateKey + "\tPUBkeyOfTheHubAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\t51820\toff\n" +
|
|
"PUBkeyAceAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\t(none)\t84.193.151.6:40122\t10.10.0.2/32\t" + itoa(old) + "\t1000\t2000\t25\n" +
|
|
"PUBkeyShanksAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\t(none)\t84.193.151.6:51820\t10.10.0.3/32\t" + itoa(fresh) + "\t3000\t4000\toff\n" +
|
|
"PUBkeyNewAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\t(none)\t(none)\t10.10.0.9/32\t0\t0\t0\toff\n"
|
|
}
|
|
|
|
func itoa(n int64) string { b, _ := json.Marshal(n); return string(b) }
|
|
|
|
func TestTheDumpIsReadAndNoKeyIsSaid(t *testing.T) {
|
|
now := time.Date(2026, 10, 11, 22, 0, 0, 0, time.UTC)
|
|
tun, err := parseDump(dump(now), now)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
raw, _ := json.Marshal(tun)
|
|
if strings.Contains(string(raw), "PRIVATE") || strings.Contains(string(raw), "PUBkey") {
|
|
t.Fatalf("a key is said: %s", raw)
|
|
}
|
|
if tun.ListenPort != 51820 || len(tun.Peers) != 3 {
|
|
t.Fatalf("got %+v", tun)
|
|
}
|
|
ace, shanks, fresh := tun.Peers[0], tun.Peers[1], tun.Peers[2]
|
|
if ace.Endpoint != "84.193.151.6:40122" || ace.HandshakeAge != 600 || !ace.Stale || ace.Keepalive != "25s" || ace.Sent != 2000 {
|
|
t.Errorf("ace %+v", ace)
|
|
}
|
|
if shanks.Stale || shanks.HandshakeAge != 40 || shanks.Keepalive != "" {
|
|
t.Errorf("shanks %+v", shanks)
|
|
}
|
|
if fresh.Endpoint != "" || fresh.HandshakeAge != -1 || !fresh.Stale || fresh.Handshake != "" {
|
|
t.Errorf("a peer never heard from %+v", fresh)
|
|
}
|
|
}
|
|
|
|
func TestADumpOfAnotherShapeIsRefused(t *testing.T) {
|
|
if _, err := parseDump("", time.Now()); err == nil {
|
|
t.Error("an empty answer was taken")
|
|
}
|
|
if _, err := parseDump("a\tb\t1\toff\nshort\tline\n", time.Now()); err == nil {
|
|
t.Error("a short peer line was taken")
|
|
}
|
|
}
|
|
|
|
func TestEndpointsAndHandshakesAreSaidWhenTheyChange(t *testing.T) {
|
|
var said []string
|
|
emit := func(event string, body any) error {
|
|
b := body.(map[string]any)
|
|
said = append(said, event+":"+b["endpoint"].(string)+":"+asString(b["from"]))
|
|
return nil
|
|
}
|
|
p := func(endpoint string, stale bool) Tunnel {
|
|
return Tunnel{Peers: []Peer{{AllowedIPs: []string{"10.10.0.2/32"}, Endpoint: endpoint, Stale: stale}}}
|
|
}
|
|
var w tunnelWatch
|
|
w.look(p("1.2.3.4:1", true), emit) // silent: the first look
|
|
w.look(p("1.2.3.4:1", true), emit)
|
|
w.look(p("1.2.3.4:2", false), emit)
|
|
w.look(p("1.2.3.4:2", true), emit)
|
|
want := "tunnel.endpoint-changed:1.2.3.4:2:1.2.3.4:1,tunnel.handshake-fresh:1.2.3.4:2:,tunnel.handshake-stale:1.2.3.4:2:"
|
|
if strings.Join(said, ",") != want {
|
|
t.Errorf("said %v", said)
|
|
}
|
|
}
|
|
|
|
func asString(v any) string {
|
|
s, _ := v.(string)
|
|
return s
|
|
}
|
|
|
|
func TestTheTunnelIsReadAsRootOrThroughSudo(t *testing.T) {
|
|
if p, a := escalated("wg", []string{"show", "mesh0", "dump"}, 0); p != "wg" || strings.Join(a, " ") != "show mesh0 dump" {
|
|
t.Errorf("as root: %s %v", p, a)
|
|
}
|
|
if p, a := escalated("wg", []string{"show", "mesh0", "dump"}, 1000); p != "sudo" || strings.Join(a, " ") != "-n wg show mesh0 dump" {
|
|
t.Errorf("as an account: %s %v", p, a)
|
|
}
|
|
}
|