gates / gates (push) Successful in 6m44s
- Configuration → Access tokens: named, scoped (group read/write), expiring (≤365 d), shown once, stored SHA-256 only, every use logged by name. Bearer fhp_… on the web surface only; /api/v1 refuses it. - Route table = the code's single source (web/routes.go), pinned to ServeHTTP's switch; session-only: secrets shown/minted, deletes/resets, password, tokens. - R-952 closed: /api/v1 route table names each caller, pinned to the switch; no-credential refusal test. - Fail-open fixed: an empty operator password served the UI open (main skipped RequireAuth). Live hub never open. - 05 §17, 04 §6.2, 13, 09 §3 251; register 155→157 (+R-1054, R-1055, R-1056, −R-952); STATUS. - website: prowlarr-logo.svg (byte copy from felhom.eu-media) — the site gate refused every push. Not deployed — waits for the operator's yes. Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
46 lines
1.3 KiB
Go
46 lines
1.3 KiB
Go
package main
|
|
|
|
import (
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/token"
|
|
"strconv"
|
|
"testing"
|
|
)
|
|
|
|
// TestWebMountAlwaysAuthenticated (hub v0.152.0): main mounts the operator web surface at "/" ONLY as
|
|
// webServer.Handler() (RequireAuth in front, unconditionally). Before, an empty auth.password_hash mounted
|
|
// webServer.ServeHTTP bare — the whole operator UI with no login. RED-PROOF: put back
|
|
// `mux.Handle("/", http.HandlerFunc(webServer.ServeHTTP))` → FAIL.
|
|
func TestWebMountAlwaysAuthenticated(t *testing.T) {
|
|
f, err := parser.ParseFile(token.NewFileSet(), "main.go", nil, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var viaHandler, bare int
|
|
ast.Inspect(f, func(n ast.Node) bool {
|
|
c, ok := n.(*ast.CallExpr)
|
|
if !ok || len(c.Args) != 2 {
|
|
return true
|
|
}
|
|
sel, ok := c.Fun.(*ast.SelectorExpr)
|
|
if !ok || sel.Sel.Name != "Handle" {
|
|
return true
|
|
}
|
|
if bl, ok := c.Args[0].(*ast.BasicLit); !ok || func() string { v, _ := strconv.Unquote(bl.Value); return v }() != "/" {
|
|
return true
|
|
}
|
|
if call, ok := c.Args[1].(*ast.CallExpr); ok {
|
|
if s, ok := call.Fun.(*ast.SelectorExpr); ok && s.Sel.Name == "Handler" {
|
|
viaHandler++
|
|
return true
|
|
}
|
|
}
|
|
bare++
|
|
return true
|
|
})
|
|
if viaHandler != 1 || bare != 0 {
|
|
t.Fatalf(`mux.Handle("/", …): %d via webServer.Handler(), %d other — want exactly 1 and 0`, viaHandler, bare)
|
|
}
|
|
}
|