Add loopback-only HTTP server with startup token, Host/Origin/CSP guards, embedded live UI, CLI serve/export, and safe single-file HTML. Co-authored-by: Cursor <cursoragent@cursor.com>
57 lines
1.6 KiB
Go
57 lines
1.6 KiB
Go
package engineeringdashboard
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestExport_OfflineReadableAndSafe(t *testing.T) {
|
|
dir := t.TempDir()
|
|
out := filepath.Join(dir, "snap.html")
|
|
snap := Snapshot{
|
|
SchemaVersion: SchemaVersion,
|
|
GenerationID: "gen_export",
|
|
RevisionID: "rev_export",
|
|
GeneratedAt: time.Date(2026, 9, 17, 10, 0, 0, 0, time.UTC),
|
|
Repository: RepositoryIdentity{Root: "/repo", Branch: "dev", Head: "deadbeef"},
|
|
Tasks: []TaskState{SampleRDevTaskFixture()},
|
|
Conflicts: []Conflict{NewConflict("env:main", "health", ConflictDeclaredVsObserved, []string{"a", "b"}, "no aggregate green")},
|
|
Documents: []DocumentNode{{
|
|
ID: ".doc/ops/note.md", Path: ".doc/ops/note.md", Title: "Note",
|
|
Body: "hello </script><script>alert(1)</script> and more",
|
|
}},
|
|
Environments: []EnvironmentState{SampleMainEventsForkFixture()},
|
|
Git: []GitBranchView{SampleDevAheadGitFixture()},
|
|
}
|
|
if err := ExportHTML(snap, out); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
fi, err := os.Stat(out)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if fi.Mode().Perm() != 0o600 {
|
|
t.Fatalf("perm %o", fi.Mode().Perm())
|
|
}
|
|
raw, err := os.ReadFile(out)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
html := string(raw)
|
|
if !strings.Contains(html, "gen_export") || !strings.Contains(html, "rev_export") {
|
|
t.Fatal("missing snapshot identity")
|
|
}
|
|
if strings.Contains(html, "</script><script>alert") {
|
|
t.Fatal("script breakout in data")
|
|
}
|
|
if !strings.Contains(html, "hello") {
|
|
t.Fatal("body missing")
|
|
}
|
|
if strings.Contains(html, "http://") && strings.Contains(html, "src=\"http") {
|
|
t.Fatal("unexpected remote resource")
|
|
}
|
|
}
|