package main // What this machine has given away, driven through the real handler. // // NOT tagged !windows, for the same reason ui_test.go and uiauth_test.go are // not: this whole UI exists because of a Windows desktop, and a page about what // a host may do to your machine has to be proven on the machine it was built // for. That constraint is why nothing here borrows setupBox / signTerms / // grantTerms / tAnchor / tMember from anchor_test.go — those live behind // //go:build !windows and would take this file with them (buildtags_test.go // checks exactly that and prints the fix). The fixtures below are local and // platform-neutral: writeAnchor, pinAnchorVerifyKey, savePairingGrant and // dcnSaveFile are all ordinary package functions with no build tag. import ( "crypto/ed25519" "encoding/base64" "encoding/json" "fmt" "net/http" "net/http/httptest" "net/url" "os" "path/filepath" "regexp" "strings" "testing" "time" ) const ( gAnchorHost = "anchor.host.privatae.ai" gMemberHost = "member.host.privatae.ai" ) // givenPairing writes one pairing file the way `pair` does, with its DCN dir // pinned to a temp path so a test can put a real grants.json where the page // will look for it. func givenPairing(t *testing.T, host, state string) string { t.Helper() d, err := pairingsDir() if err != nil { t.Fatalf("pairingsDir: %v", err) } dcn := filepath.Join(t.TempDir(), "dcn") if err := os.MkdirAll(dcn, 0o700); err != nil { t.Fatal(err) } b, err := json.Marshal(&Config{ HostName: host, // Loopback and nothing listening, exactly as ui_test.go writes it: a // pairing's control port IS loopback-only by design (config.go:39) and // this one is deliberately dead, so liveness reads "not answering". ListenAddr: "127.0.0.1:59999", BastionTunnelIP: "fd00:9::a:1", DCNDir: dcn, State: state, FirstSeen: "2026-09-01T00:00:00Z", }) if err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(d, host+".json"), b, 0o600); err != nil { t.Fatalf("write pairing: %v", err) } return dcn } // givenAnchoredBox is a NETWORKED, ANCHORED machine with the anchor host's // signing key pinned — the shape in which a caps grant means anything at all. // Returns the key the "anchor host" signs its grants with. func givenAnchoredBox(t *testing.T) ed25519.PrivateKey { t.Helper() uiTestConfigDir(t) p, err := modePath() if err != nil { t.Fatal(err) } if err := os.WriteFile(p, []byte(`{"mode":"networked"}`), 0o600); err != nil { t.Fatal(err) } givenPairing(t, gAnchorHost, pairingActive) if err := writeAnchor("Acme IT", gAnchorHost); err != nil { t.Fatalf("writeAnchor: %v", err) } pub, priv, err := ed25519.GenerateKey(nil) if err != nil { t.Fatal(err) } if err := pinAnchorVerifyKey(base64.StdEncoding.EncodeToString(pub)); err != nil { t.Fatalf("pinAnchorVerifyKey: %v", err) } return priv } // givenSignedGrant installs the anchor's signed pairing grant for host. The // canonical bytes are a marshalled map, which is what the host side sends and // what verifyAnchorRecord parses (anchor.go:280). func givenSignedGrant(t *testing.T, priv ed25519.PrivateKey, host string, caps []string) { t.Helper() hn, _ := os.Hostname() canonical, err := json.Marshal(map[string]any{ "kind": "pairing_grant", "server": hn, "anchor": gAnchorHost, "subject": host, "subject_handle": handleOf(host), "caps": caps, "issued_at": time.Now().UTC().Format(time.RFC3339), }) if err != nil { t.Fatal(err) } if err := savePairingGrant(host, &pairingGrantFile{ TermsCanonical: base64.StdEncoding.EncodeToString(canonical), Signature: base64.StdEncoding.EncodeToString(ed25519.Sign(priv, canonical)), SyncedAt: time.Now().UTC().Format(time.RFC3339), }); err != nil { t.Fatalf("savePairingGrant: %v", err) } } // givenStoreGrants writes a grants.json holding one signed store grant per // terms map, keyed by store id, under a freshly generated pinned key. func givenStoreGrants(t *testing.T, dir string, stores map[string]map[string]any) ed25519.PrivateKey { t.Helper() pub, priv, err := ed25519.GenerateKey(nil) if err != nil { t.Fatal(err) } f := &dcnGrantFile{ VerifyPubkey: base64.StdEncoding.EncodeToString(pub), Stores: map[string]dcnGrantRec{}, } for id, terms := range stores { canonical, err := json.Marshal(terms) if err != nil { t.Fatal(err) } f.Stores[id] = dcnGrantRec{ TermsCanonical: base64.StdEncoding.EncodeToString(canonical), Signature: base64.StdEncoding.EncodeToString(ed25519.Sign(priv, canonical)), } } if err := dcnSaveFile(dir, f); err != nil { t.Fatalf("dcnSaveFile: %v", err) } return priv } // givenMachineStore is the shape of a real machine-store grant, so a test only // has to say the part it is about. func givenMachineStore(root string, mask, excludes []string, expires string) map[string]any { hn, _ := os.Hostname() m := map[string]any{ "kind": "dcn_store_grant", "class": "machine", "server": hn, "root": root, "mask": mask, "expires": expires, } if excludes != nil { m["excludes"] = excludes } return m } // givenPage drives a signed-in GET through the whole mux — the Host check, the // Origin check, the session check and the template — and returns the body. func givenPage(t *testing.T, path string) string { t.Helper() u := uiTestServer(t) tok, err := u.sessions.mint() if err != nil { t.Fatal(err) } r := uiReq(http.MethodGet, path) r.Header.Set("Cookie", uiCookieName+"="+tok) w := httptest.NewRecorder() u.handler().ServeHTTP(w, r) if w.Code != http.StatusOK { t.Fatalf("%s = %d: %s", path, w.Code, w.Body.String()) } return w.Body.String() } // givenCapsFor slices out ONE host's capability section. The page lists every // pairing, so an assertion on the whole body would pass on the wrong host's // row — which is the only mistake this page could make that would be worse // than not existing. func givenCapsFor(t *testing.T, body, host string) string { t.Helper() open := "What " + host + " may do to this machine" shut := "Folders of yours that " + host + " can reach" i := strings.Index(body, open) if i < 0 { t.Fatalf("the page has no capability section for %s", host) } j := strings.Index(body[i:], shut) if j < 0 { t.Fatalf("the capability section for %s is not closed by its folder section", host) } return body[i : i+j] } // givenFoldersFor slices out ONE host's folder list: from its own heading to // the next host's capability heading, or to the end of the page. func givenFoldersFor(t *testing.T, body, host string) string { t.Helper() open := "Folders of yours that " + host + " can reach" i := strings.Index(body, open) if i < 0 { t.Fatalf("the page has no folder section for %s", host) } rest := body[i+len(open):] if j := strings.Index(rest, "may do to this machine"); j >= 0 { // Back up past the next host's

, which carries that host's name. if k := strings.LastIndex(rest[:j], "

"); k >= 0 { return rest[:k] } return rest[:j] } return rest } func givenHolds(t *testing.T, section, host string, families ...string) { t.Helper() for _, f := range families { row := givenRow(t, section, f) if !strings.Contains(row, "granted") || strings.Contains(row, "refused here") { t.Errorf("%s: %q must read as GRANTED and does not:\n%s", host, f, row) } } } func givenRefuses(t *testing.T, section, host string, families ...string) { t.Helper() for _, f := range families { row := givenRow(t, section, f) if !strings.Contains(row, "refused here") || strings.Contains(row, ">granted<") { t.Errorf("%s: %q must read as REFUSED and does not:\n%s", host, f, row) } } } // givenRow is one family's card. The family id is the last thing in the card // (the ops line), so a card runs from the previous card boundary to it. func givenRow(t *testing.T, section, family string) string { t.Helper() marker := `

` + family + "\n" i := strings.Index(section, marker) if i < 0 { t.Fatalf("no card for the %q family on this page", family) } start := strings.LastIndex(section[:i], `

and