package engineeringdashboard import ( "net/http" "net/http/httptest" "strings" "testing" "time" ) func TestServer_RejectsNonGETAndBadHost(t *testing.T) { c := NewCollector(t.TempDir(), &FakeRunner{Map: map[string]FakeResult{}}) c.mu.Lock() c.current = &Snapshot{ SchemaVersion: SchemaVersion, GenerationID: "gen_1", RevisionID: "rev_1", GeneratedAt: time.Now().UTC(), Repository: RepositoryIdentity{Root: "/r"}, } c.mu.Unlock() srv, err := NewServer(c) if err != nil { t.Fatal(err) } h := srv.Handler() req := httptest.NewRequest(http.MethodPost, "/api/v1/snapshot", nil) req.Host = "127.0.0.1:8787" rr := httptest.NewRecorder() h.ServeHTTP(rr, req) if rr.Code != http.StatusMethodNotAllowed { t.Fatalf("POST: %d", rr.Code) } req = httptest.NewRequest(http.MethodGet, "/api/v1/snapshot", nil) req.Host = "evil.example" rr = httptest.NewRecorder() h.ServeHTTP(rr, req) if rr.Code != http.StatusForbidden { t.Fatalf("bad host: %d", rr.Code) } } func TestServer_SnapshotWithoutToken(t *testing.T) { c := NewCollector(t.TempDir(), &FakeRunner{Map: map[string]FakeResult{}}) snap := Snapshot{ SchemaVersion: SchemaVersion, GenerationID: "gen_9", RevisionID: "rev_abc", GeneratedAt: time.Now().UTC(), Repository: RepositoryIdentity{Root: "/repo", Branch: "dev", Head: "h"}, Tasks: []TaskState{SampleRDevTaskFixture()}, } c.mu.Lock() c.current = &snap c.mu.Unlock() srv, err := NewServer(c) if err != nil { t.Fatal(err) } h := srv.Handler() req := httptest.NewRequest(http.MethodGet, "/api/v1/snapshot", nil) req.Host = "127.0.0.1:8787" rr := httptest.NewRecorder() h.ServeHTTP(rr, req) if rr.Code != 200 { t.Fatalf("snapshot without token: %d %s", rr.Code, rr.Body.String()) } body := rr.Body.String() if !strings.Contains(body, `"generation_id": "gen_9"`) || !strings.Contains(body, `"revision_id": "rev_abc"`) { t.Fatalf("identity missing: %s", body) } if rr.Header().Get("ETag") != `"rev_abc"` { t.Fatalf("etag %q", rr.Header().Get("ETag")) } req = httptest.NewRequest(http.MethodGet, "/api/v1/snapshot", nil) req.Host = "127.0.0.1:8787" req.Header.Set("If-None-Match", `"rev_abc"`) rr = httptest.NewRecorder() h.ServeHTTP(rr, req) if rr.Code != http.StatusNotModified { t.Fatalf("etag: %d", rr.Code) } } func TestServer_DocPathTraversalDenied(t *testing.T) { root := t.TempDir() writeDoc(t, root, ".doc/ops/ok.md", "# ok\n") c := NewCollector(root, &FakeRunner{Map: map[string]FakeResult{}}) srv, err := NewServer(c) if err != nil { t.Fatal(err) } req := httptest.NewRequest(http.MethodGet, "/api/v1/doc/not-a-real.md", nil) req.Host = "127.0.0.1:8787" req.URL.Path = "/api/v1/doc/../../.env" rr := httptest.NewRecorder() srv.Handler().ServeHTTP(rr, req) if rr.Code != http.StatusForbidden { t.Fatalf("got %d body=%s", rr.Code, rr.Body.String()) } } func TestListenAndServe_RejectsNonLoopback(t *testing.T) { err := ListenAndServe("0.0.0.0:8787", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) if err == nil || !strings.Contains(err.Error(), "loopback") { t.Fatalf("expected loopback reject, got %v", err) } } func TestServer_CrossOriginDenied(t *testing.T) { c := NewCollector(t.TempDir(), &FakeRunner{}) c.mu.Lock() c.current = &Snapshot{RevisionID: "r", GenerationID: "g", GeneratedAt: time.Now().UTC()} c.mu.Unlock() srv, _ := NewServer(c) req := httptest.NewRequest(http.MethodGet, "/api/v1/snapshot", nil) req.Host = "127.0.0.1:8787" req.Header.Set("Origin", "https://evil.example") rr := httptest.NewRecorder() srv.Handler().ServeHTTP(rr, req) if rr.Code != http.StatusForbidden { t.Fatalf("got %d", rr.Code) } } func TestServer_IndexHasNoTokenMachinery(t *testing.T) { c := NewCollector(t.TempDir(), &FakeRunner{}) c.mu.Lock() c.current = &Snapshot{RevisionID: "r", GenerationID: "g", GeneratedAt: time.Now().UTC()} c.mu.Unlock() srv, err := NewServer(c) if err != nil { t.Fatal(err) } req := httptest.NewRequest(http.MethodGet, "/", nil) req.Host = "127.0.0.1:8787" rr := httptest.NewRecorder() srv.Handler().ServeHTTP(rr, req) if rr.Code != http.StatusOK { t.Fatalf("index: %d %s", rr.Code, rr.Body.String()) } body := rr.Body.String() for _, banned := range []string{"__DASHBOARD_TOKEN__", "engineering-dashboard-token", "?token="} { if strings.Contains(body, banned) { t.Fatalf("index still contains %q", banned) } } js, err := readAsset("assets/app.js") if err != nil { t.Fatal(err) } jsBody := string(js) if strings.Contains(jsBody, "token=") || strings.Contains(jsBody, "__DASHBOARD_TOKEN__") { t.Fatal("app.js still references token auth") } if !strings.Contains(rr.Header().Get("Content-Security-Policy"), "script-src 'self'") { t.Fatalf("unexpected CSP: %s", rr.Header().Get("Content-Security-Policy")) } }