diff --git a/cmd/servers/atenet/app/router/extproc.go b/cmd/servers/atenet/app/router/extproc.go index 834728f..1fe15a3 100644 --- a/cmd/servers/atenet/app/router/extproc.go +++ b/cmd/servers/atenet/app/router/extproc.go @@ -150,9 +150,11 @@ func (s *ExtProcServer) handleRequestHeaders( slog.InfoContext(ctx, "Route ok", slog.String("actorID", actorID), slog.String("targetAddr", targetAddr)) - // Route by rewriting the :authority header. + // Route by rewriting the :authority header, and inject the resolved actor + // ID so the workload can identify itself without inspecting :authority. mutation := &extprocv3.HeaderMutation{} addAuthorityMutation(targetAddr, mutation) + addSessionHeaderMutation(actorID, mutation) return &extprocv3.HeadersResponse{ Response: &extprocv3.CommonResponse{ diff --git a/cmd/servers/atenet/app/router/extproc_out.go b/cmd/servers/atenet/app/router/extproc_out.go index c7386c5..a560e81 100644 --- a/cmd/servers/atenet/app/router/extproc_out.go +++ b/cmd/servers/atenet/app/router/extproc_out.go @@ -43,6 +43,21 @@ func addAuthorityMutation(auth string, mut *extprocv3.HeaderMutation) { ) } +// sessionHeader is set on every successfully-routed request so that the +// workload can identify its own actor without parsing the rewritten :authority. +const sessionHeader = "x-agentset-session" + +func addSessionHeaderMutation(actorID string, mut *extprocv3.HeaderMutation) { + mut.SetHeaders = append(mut.SetHeaders, + &corev3.HeaderValueOption{ + Header: &corev3.HeaderValue{ + Key: sessionHeader, + RawValue: []byte(actorID), + }, + }, + ) +} + func immediateResponse(statusCode envoy_type.StatusCode, message string) *extproc.ProcessingResponse { return &extproc.ProcessingResponse{ Response: &extproc.ProcessingResponse_ImmediateResponse{ diff --git a/cmd/servers/atenet/app/router/extproc_test.go b/cmd/servers/atenet/app/router/extproc_test.go index d948184..cfd1f40 100644 --- a/cmd/servers/atenet/app/router/extproc_test.go +++ b/cmd/servers/atenet/app/router/extproc_test.go @@ -131,17 +131,20 @@ func TestExtProcHeadersEvaluation(t *testing.T) { } mutation := res.Response.GetHeaderMutation() - if len(mutation.GetSetHeaders()) != 1 { - t.Fatalf("expected exactly one Header option set, found: %v", mutation.GetSetHeaders()) + if len(mutation.GetSetHeaders()) != 2 { + t.Fatalf("expected exactly two Header options set, found: %v", mutation.GetSetHeaders()) } - headerOption := mutation.GetSetHeaders()[0] - if strings.ToLower(headerOption.Header.Key) != ":authority" { - t.Errorf("invalid resulting dynamic parameter key: %s", headerOption.Header.Key) + setHeaders := map[string]string{} + for _, h := range mutation.GetSetHeaders() { + setHeaders[strings.ToLower(h.Header.Key)] = string(h.Header.RawValue) } - if string(headerOption.Header.RawValue) != tc.expectedTarget { - t.Errorf("invalid destination mapping found: %s, expected: %s", headerOption.Header.RawValue, tc.expectedTarget) + if got := setHeaders[":authority"]; got != tc.expectedTarget { + t.Errorf("invalid :authority mutation: got %q, want %q", got, tc.expectedTarget) + } + if got := setHeaders["x-agentset-session"]; got != testUUID { + t.Errorf("invalid x-agentset-session mutation: got %q, want %q", got, testUUID) } // Confirm that query logs recorded metric trace details diff --git a/demos/agent-secret/README.md b/demos/agent-secret/README.md index 23c0f89..0467a60 100644 --- a/demos/agent-secret/README.md +++ b/demos/agent-secret/README.md @@ -40,7 +40,7 @@ Create a single actor and watch it automatically yield compute after use: ./kubectl-ate create actor my-agent --template ate-demo-secret-agent-v2/agent-secret # Send a request via the Substrate Router (Note the official DNS suffix) -curl -H "Host: my-agent.actors.resources.substrate.k8s.io" http://localhost:8000 +curl -H "Host: my-agent.actors.resources.substrate.ate.dev" http://localhost:8000 ``` **What to observe:** @@ -50,7 +50,7 @@ curl -H "Host: my-agent.actors.resources.substrate.k8s.io" http://localhost:8000 ### 2. Verify Identity Persistence Send another request to the same actor: ```bash -curl -H "Host: my-agent.actors.resources.substrate.k8s.io" http://localhost:8000 +curl -H "Host: my-agent.actors.resources.substrate.ate.dev" http://localhost:8000 ``` The "Identity" secret returned will be identical to the first response, even if the actor was resumed on a different physical pod. This proves the volatile RAM survived the hibernation cycle. @@ -71,7 +71,7 @@ for wave in 0 1 2; do echo "Triggering Wave $((wave + 1))..." for i in {1..8}; do num=$(printf "%03d" $((wave * 8 + i))) - curl -s -H "Host: session-$num.actors.resources.substrate.k8s.io" http://localhost:8000 & + curl -s -H "Host: session-$num.actors.resources.substrate.ate.dev" http://localhost:8000 & done sleep 8 # 7s linger + 1s buffer done diff --git a/demos/agent-secret/main.go b/demos/agent-secret/main.go index 44670b4..f1af0e4 100644 --- a/demos/agent-secret/main.go +++ b/demos/agent-secret/main.go @@ -60,7 +60,7 @@ func handleRequest(w http.ResponseWriter, r *http.Request) { log.Printf("DEBUG: Request received. Path=%s Host=%s", r.URL.Path, r.Host) // 1. Identify Actor (Robust extraction) - // New architecture uses Host: .actors.resources.substrate.k8s.io + // New architecture uses Host: .actors.resources.substrate.ate.dev actorID := r.Header.Get("X-AgentSet-Session") if actorID == "" { actorID = r.Header.Get("x-agentset-session") @@ -70,7 +70,7 @@ func handleRequest(w http.ResponseWriter, r *http.Request) { if host == "" { host = r.Header.Get("Host") } - // Extract prefix from .actors.resources.substrate.k8s.io + // Extract prefix from .actors.resources.substrate.ate.dev parts := strings.Split(host, ".") if len(parts) > 1 { actorID = parts[0]