package web
import (
"os"
"regexp"
"strings"
"testing"
)
// The fleet is an administrator's view of the whole forge, and every
// route under it is supposed to be admin-only. The front page's listing
// refresh once lived at /fleet.frag and was mistaken for this panel; it
// is /explore.frag now, public like the page it serves, and answers as
// the reader (see TestTheFrontPageStaysOpenForAStranger).
//
// This is the third door-with-a-weaker-lock of its kind: an API gate
// that disagreed with the web gate, a sync path that never consulted
// the letters the page promised, and now a fragment that skipped the
// gate its page carries. Each was found by hand, one at a time, after
// shipping. The pattern underneath is always the same — a SECOND way
// in that nobody remembered to lock, because the lock lives in the
// handler rather than in the route.
//
// So this test refuses the class rather than the instance: a handler
// registered under /fleet must gate, whatever it is called and whoever
// adds it next. A source-level check rather than a request-level one
// because it has to hold for routes that do not exist yet — the point
// is to fail the day somebody adds the fourth door, not to re-prove
// the three we know about.
func TestFleetRoutesAreAdminGated(t *testing.T) {
src, err := os.ReadFile("web.go")
if err != nil {
t.Fatal(err)
}
// Each registration and the body that follows it, up to the next
// one. Good enough to see whether the gate is the first thing the
// handler does, which is the only place it is any use.
// EVERY registration, so a handler's body is bounded by the next
// route of any path. Bounding by the next /fleet route instead let
// the LAST one run to end-of-file and swallow some unrelated
// handler's gateAt — the guard passed while the hole was open,
// which is the same shape of mistake it exists to catch.
any := regexp.MustCompile(`mux\.Handle(?:Func)?\("(?:GET|POST) ([^"]*)"`)
all := any.FindAllSubmatchIndex(src, -1)
if len(all) == 0 {
t.Fatal("no routes found — this test has lost track of the file it guards")
}
var ungated []string
for i, loc := range all {
route := string(src[loc[2]:loc[3]])
if !strings.HasPrefix(route, "/fleet") {
continue
}
end := len(src)
if i+1 < len(all) {
end = all[i+1][0]
}
body := string(src[loc[1]:end])
if !strings.Contains(body, "gateAt(") {
ungated = append(ungated, route)
}
}
if len(ungated) > 0 {
t.Errorf("these /fleet routes do not gate, so a signed-out stranger reaches them:\n %s\n"+
"every route under /fleet is an admin view; add gateAt(verify, sessions, \"\", ops.Admin, w, req)",
strings.Join(ungated, "\n "))
}
}