Dashboard
Workloads
@@ -48,7 +48,7 @@
{{block "content" .}}{{end}}
From e8418d528eaa82ed6da58a35f021ceca9f31374a Mon Sep 17 00:00:00 2001
From: Shreyansh Sancheti <43677304+shreyanshjain7174@users.noreply.github.com>
Date: Tue, 14 Jul 2026 10:59:32 +0530
Subject: [PATCH 10/44] fix(ui): complete evidence console branding
Signed-off-by: Shreyansh Sancheti <43677304+shreyanshjain7174@users.noreply.github.com>
---
cmd/agentctl-web/demo_test.go | 147 +++++++++++++++++-
cmd/agentctl-web/static/style.css | 1 +
cmd/agentctl-web/templates/login.html | 9 +-
.../templates/partials/describe.html | 4 +-
.../templates/partials/workloads.html | 6 +-
5 files changed, 157 insertions(+), 10 deletions(-)
diff --git a/cmd/agentctl-web/demo_test.go b/cmd/agentctl-web/demo_test.go
index 72a8ccd..2519fac 100644
--- a/cmd/agentctl-web/demo_test.go
+++ b/cmd/agentctl-web/demo_test.go
@@ -1,6 +1,7 @@
package main
import (
+ "bytes"
"net/http"
"net/http/httptest"
"strings"
@@ -44,6 +45,8 @@ func TestHandleDemoRendersEvidenceConsole(t *testing.T) {
"No OPA evidence",
"No scheduled gVisor pod",
"No packet enforcement test",
+ "gVisor admission dry-run",
+ "NetworkPolicy object presence",
"Current workload generated no audit fixture",
"no pod or packet test",
"not generated by the current workload",
@@ -65,17 +68,159 @@ func TestHandleDemoRendersEvidenceConsole(t *testing.T) {
for _, stale := range []string{
"OPA checks tool scope",
+ "Policy gated",
"gpt-4o-mini",
"Secure Research Swarm",
+ "$0.0142",
"Audit trail",
- "Policy gated",
"Audit ready",
+ "Current audit trail",
+ "Current attestation",
+ "Attestation verified",
+ "3 agents",
+ "No external data egress",
+ "AgentWorkload running",
+ "Live agent graph",
+ "Agent graph",
"Agentic Operator",
} {
if strings.Contains(body, stale) {
t.Fatalf("demo body contains stale claim %q", stale)
}
}
+
+ for label, want := range map[string]int{
+ ">LIVE": 1,
+ ">CONFIG ONLY": 1,
+ ">PRIOR RUN": 1,
+ } {
+ if count := strings.Count(body, label); count != want {
+ t.Errorf("demo body contains %d %s labels, want %d", count, label, want)
+ }
+ }
+}
+
+func TestHandleLoginRendersClawdlinuxEvidenceConsoleBranding(t *testing.T) {
+ server, err := NewServer(nil, nil, TemplatesFS())
+ if err != nil {
+ t.Fatalf("NewServer() error = %v", err)
+ }
+
+ req := httptest.NewRequest(http.MethodGet, "/auth/login", nil)
+ res := httptest.NewRecorder()
+
+ server.handleLogin(res, req)
+
+ if res.Code != http.StatusOK {
+ t.Fatalf("status = %d, want %d", res.Code, http.StatusOK)
+ }
+
+ body := res.Body.String()
+ for _, want := range []string{
+ `href="/theme/clawdlinux-theme.css"`,
+ `href="/static/style.css"`,
+ `src="/theme/clawdlinux-wordmark.svg"`,
+ `alt="Clawdlinux"`,
+ "Governance evidence console",
+ `method="POST" action="/auth/login"`,
+ } {
+ if !strings.Contains(body, want) {
+ t.Errorf("login body missing %q", want)
+ }
+ }
+
+ sharedThemeIndex := strings.Index(body, `href="/theme/clawdlinux-theme.css"`)
+ localStyleIndex := strings.Index(body, `href="/static/style.css"`)
+ if sharedThemeIndex == -1 || localStyleIndex == -1 || sharedThemeIndex > localStyleIndex {
+ t.Error("shared theme must load before local styles on login")
+ }
+
+ for _, stale := range []string{"agentctl", "Agentic Operator Web UI", "⚙"} {
+ if strings.Contains(body, stale) {
+ t.Errorf("login body contains stale branding %q", stale)
+ }
+ }
+}
+
+func TestApprovalPartialsRenderTextControlsWithHTMXContracts(t *testing.T) {
+ server, err := NewServer(nil, nil, TemplatesFS())
+ if err != nil {
+ t.Fatalf("NewServer() error = %v", err)
+ }
+
+ workload := agentctl.WorkloadRow{
+ Name: "review-required",
+ Namespace: "regulated-team",
+ Status: "PendingApproval",
+ }
+ detail := agentctl.WorkloadDetail{
+ Name: workload.Name,
+ Namespace: workload.Namespace,
+ Phase: workload.Status,
+ }
+ tests := []struct {
+ name string
+ template string
+ data map[string]interface{}
+ wants []string
+ }{
+ {
+ name: "workload list",
+ template: "workloads.html",
+ data: map[string]interface{}{
+ "Workloads": []agentctl.WorkloadRow{workload},
+ "CSRFToken": "test-csrf",
+ },
+ wants: []string{
+ `action="/workloads/regulated-team/review-required/approve"`,
+ `hx-post="/workloads/regulated-team/review-required/approve"`,
+ `action="/workloads/' + ns + '/' + name + '/reject"`,
+ `hx-post="/workloads/' + ns + '/' + name + '/reject"`,
+ `hx-target="#workload-table"`,
+ `title="Approve">Approve`,
+ `title="Reject"`,
+ `Submit rejection`,
+ },
+ },
+ {
+ name: "workload detail",
+ template: "describe.html",
+ data: map[string]interface{}{
+ "Detail": detail,
+ "CSRFToken": "test-csrf",
+ },
+ wants: []string{
+ `action="/workloads/regulated-team/review-required/approve"`,
+ `hx-post="/workloads/regulated-team/review-required/approve"`,
+ `action="/workloads/regulated-team/review-required/reject"`,
+ `hx-post="/workloads/regulated-team/review-required/reject"`,
+ `hx-target="#workload-table"`,
+ `title="Approve">Approve`,
+ `title="Reject">Submit rejection`,
+ },
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ var rendered bytes.Buffer
+ if err := server.tmpl.ExecuteTemplate(&rendered, test.template, test.data); err != nil {
+ t.Fatalf("ExecuteTemplate(%q) error = %v", test.template, err)
+ }
+
+ body := rendered.String()
+ for _, want := range test.wants {
+ if !strings.Contains(body, want) {
+ t.Errorf("rendered partial missing %q", want)
+ }
+ }
+ for _, glyph := range []string{"✓", "✗"} {
+ if strings.Contains(body, glyph) {
+ t.Errorf("rendered partial contains forbidden glyph %q", glyph)
+ }
+ }
+ })
+ }
}
func TestHandleDemoRendersLiveWorkloadEvidence(t *testing.T) {
diff --git a/cmd/agentctl-web/static/style.css b/cmd/agentctl-web/static/style.css
index 1d41779..329566b 100644
--- a/cmd/agentctl-web/static/style.css
+++ b/cmd/agentctl-web/static/style.css
@@ -341,6 +341,7 @@ textarea:focus-visible {
text-align: center;
margin-bottom: 1.5rem;
}
+.login-header .brand-wordmark { margin: 0 auto; }
.login-header h1 { font-size: 1.5rem; margin-top: 0.5rem; }
.login-header p { color: var(--text-muted); font-size: 0.9rem; }
.login-hint {
diff --git a/cmd/agentctl-web/templates/login.html b/cmd/agentctl-web/templates/login.html
index f594e3c..e6d5558 100644
--- a/cmd/agentctl-web/templates/login.html
+++ b/cmd/agentctl-web/templates/login.html
@@ -3,15 +3,16 @@
-
Login — agentctl
+
Login | Clawdlinux
+
{{if .Error}}
diff --git a/cmd/agentctl-web/templates/partials/describe.html b/cmd/agentctl-web/templates/partials/describe.html
index fbb88e9..eac31b4 100644
--- a/cmd/agentctl-web/templates/partials/describe.html
+++ b/cmd/agentctl-web/templates/partials/describe.html
@@ -15,7 +15,7 @@
{{.Detail.Name}}
hx-target="#workload-table" hx-swap="innerHTML"
style="display:inline">
- ✓ Approve
+ Approve
{{end}}
diff --git a/cmd/agentctl-web/templates/partials/workloads.html b/cmd/agentctl-web/templates/partials/workloads.html
index c90b3da..0d5ae87 100644
--- a/cmd/agentctl-web/templates/partials/workloads.html
+++ b/cmd/agentctl-web/templates/partials/workloads.html
@@ -35,11 +35,11 @@
hx-target="#workload-table" hx-swap="innerHTML"
style="display:inline">
-
✓ Approve
+
Approve
- ✗ Reject
+ Reject
{{else}}
—
@@ -69,7 +69,7 @@
'
' +
'
' +
'
' +
- '
Submit Rejection ' +
+ '
Submit rejection ' +
'
Cancel ' +
'';
row.parentNode.insertBefore(newRow, row.nextSibling);
From a0fdf57b993d1802303fc031ceb47b7a8e3c9179 Mon Sep 17 00:00:00 2001
From: Shreyansh Sancheti <43677304+shreyanshjain7174@users.noreply.github.com>
Date: Tue, 14 Jul 2026 11:11:24 +0530
Subject: [PATCH 11/44] fix(ui): preserve console evidence provenance
Signed-off-by: Shreyansh Sancheti <43677304+shreyanshjain7174@users.noreply.github.com>
---
cmd/agentctl-web/demo_test.go | 268 +++++++++++++++++++++-----
cmd/agentctl-web/handlers.go | 64 +++---
cmd/agentctl-web/static/style.css | 26 ++-
cmd/agentctl-web/templates/demo.html | 71 ++++---
cmd/agentctl-web/templates/login.html | 3 +
5 files changed, 335 insertions(+), 97 deletions(-)
diff --git a/cmd/agentctl-web/demo_test.go b/cmd/agentctl-web/demo_test.go
index 2519fac..a15cd14 100644
--- a/cmd/agentctl-web/demo_test.go
+++ b/cmd/agentctl-web/demo_test.go
@@ -2,6 +2,7 @@ package main
import (
"bytes"
+ "errors"
"net/http"
"net/http/httptest"
"strings"
@@ -16,6 +17,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
dynamicfake "k8s.io/client-go/dynamic/fake"
"k8s.io/client-go/kubernetes/fake"
+ k8stesting "k8s.io/client-go/testing"
)
func TestHandleDemoRendersEvidenceConsole(t *testing.T) {
@@ -39,17 +41,15 @@ func TestHandleDemoRendersEvidenceConsole(t *testing.T) {
`src="/theme/clawdlinux-wordmark.svg"`,
`alt="Clawdlinux"`,
"Governance evidence console",
- ">LIVE",
">CONFIG ONLY",
">PRIOR RUN",
"No OPA evidence",
- "No scheduled gVisor pod",
+ "Runtime pod state unavailable",
"No packet enforcement test",
"gVisor admission dry-run",
"NetworkPolicy object presence",
- "Current workload generated no audit fixture",
+ "The audit receipt is a prior-run fixture. This console does not query current-run audit generation.",
"no pod or packet test",
- "not generated by the current workload",
`hx-trigger="every 5s"`,
} {
if !strings.Contains(body, want) {
@@ -77,6 +77,8 @@ func TestHandleDemoRendersEvidenceConsole(t *testing.T) {
"Current audit trail",
"Current attestation",
"Attestation verified",
+ "Current workload generated no audit fixture",
+ "not generated by the current workload",
"3 agents",
"No external data egress",
"AgentWorkload running",
@@ -90,7 +92,7 @@ func TestHandleDemoRendersEvidenceConsole(t *testing.T) {
}
for label, want := range map[string]int{
- ">LIVE": 1,
+ ">LIVE": 0,
">CONFIG ONLY": 1,
">PRIOR RUN": 1,
} {
@@ -123,6 +125,8 @@ func TestHandleLoginRendersClawdlinuxEvidenceConsoleBranding(t *testing.T) {
`alt="Clawdlinux"`,
"Governance evidence console",
`method="POST" action="/auth/login"`,
+ `