feat: add control-plane identity and management console
Build web service image / build (push) Successful in 2m7s

This commit is contained in:
2026-09-27 20:27:31 +08:00
parent 083aeef18a
commit 8760fa49f0
40 changed files with 4827 additions and 2431 deletions
+32 -3
View File
@@ -13,7 +13,7 @@ import (
)
func TestReactFrontendIsEmbedded(t *testing.T) {
server, err := NewServer(ServerConfig{DataFile: filepath.Join(t.TempDir(), "state.json")})
server, err := NewServer(ServerConfig{DataFile: filepath.Join(t.TempDir(), "state.json"), WebUsers: map[string]string{"admin": "test-password"}})
if err != nil {
t.Fatal(err)
}
@@ -32,8 +32,23 @@ func TestReactFrontendIsEmbedded(t *testing.T) {
if response.StatusCode != http.StatusOK || !strings.Contains(string(body), "<div id=\"root\"></div>") || !strings.Contains(string(body), "/assets/") {
t.Fatalf("React index was not served: status=%d body=%s", response.StatusCode, body)
}
if strings.Contains(response.Header.Get("Content-Security-Policy"), "unsafe-inline") {
t.Fatal("React frontend still permits inline scripts")
csp := response.Header.Get("Content-Security-Policy")
if strings.Contains(csp, "script-src 'self' 'unsafe-inline'") || !strings.Contains(csp, "style-src-attr 'unsafe-inline'") {
t.Fatalf("frontend CSP should keep scripts strict while permitting component style attributes: %q", csp)
}
nonceMarker := `<meta name="csp-nonce" content="`
nonceStart := strings.Index(string(body), nonceMarker)
if nonceStart < 0 {
t.Fatal("React index is missing its CSP nonce")
}
nonceStart += len(nonceMarker)
nonceEnd := strings.Index(string(body)[nonceStart:], `"`)
if nonceEnd < 1 {
t.Fatal("React CSP nonce is malformed")
}
nonce := string(body)[nonceStart : nonceStart+nonceEnd]
if strings.Contains(string(body), "__WX_CSP_NONCE__") || !strings.Contains(csp, "style-src 'self' 'nonce-"+nonce+"'") || response.Header.Get("Cache-Control") != "no-store" {
t.Fatalf("frontend CSP nonce is not applied consistently: policy=%q cache=%q", csp, response.Header.Get("Cache-Control"))
}
marker := `src="/assets/`
start := strings.Index(string(body), marker)
@@ -54,6 +69,20 @@ func TestReactFrontendIsEmbedded(t *testing.T) {
if asset.StatusCode != http.StatusOK {
t.Fatalf("React asset status = %d", asset.StatusCode)
}
for _, route := range []string{"/overview", "/users", "/messages"} {
page, err := http.Get(httpServer.URL + route)
if err != nil {
t.Fatal(err)
}
pageBody, err := io.ReadAll(page.Body)
page.Body.Close()
if err != nil {
t.Fatal(err)
}
if page.StatusCode != http.StatusOK || !strings.Contains(string(pageBody), "<div id=\"root\"></div>") {
t.Fatalf("React route %s was not served: status=%d", route, page.StatusCode)
}
}
}
func TestNodeWebTaskAndEventFlow(t *testing.T) {