From f9a8054dd8de2396daf64c1488894c32473466e9 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Sat, 16 May 2026 00:32:16 +0300 Subject: [PATCH] Support signed fabric session smoke headers --- agents/rap-node-agent/cmd/rap-host-agent/main.go | 16 +++++++++++++++- .../DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md | 4 +++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/agents/rap-node-agent/cmd/rap-host-agent/main.go b/agents/rap-node-agent/cmd/rap-host-agent/main.go index 3801454..1f75aaa 100644 --- a/agents/rap-node-agent/cmd/rap-host-agent/main.go +++ b/agents/rap-node-agent/cmd/rap-host-agent/main.go @@ -6,6 +6,7 @@ import ( "flag" "fmt" "log" + "net/http" "os" "os/signal" "runtime" @@ -122,10 +123,14 @@ func runFabricSessionSmoke(ctx context.Context, args []string) error { var token string var timeoutSeconds int var payload string + var authorityPayload string + var authoritySignature string fs.StringVar(&meshURL, "mesh-url", getenv("RAP_MESH_SMOKE_URL", ""), "Mesh base URL, for example http://node:19131.") fs.StringVar(&token, "token", getenv("RAP_FABRIC_SESSION_TOKEN", ""), "Fabric session token starting with rap_fsn_.") fs.IntVar(&timeoutSeconds, "timeout-seconds", getenvInt("RAP_FABRIC_SESSION_SMOKE_TIMEOUT_SECONDS", 5), "Smoke timeout in seconds.") fs.StringVar(&payload, "payload", getenv("RAP_FABRIC_SESSION_SMOKE_PAYLOAD", "rap-fabric-session-smoke"), "Ping payload.") + fs.StringVar(&authorityPayload, "authority-payload", getenv("RAP_FABRIC_SESSION_AUTHORITY_PAYLOAD", ""), "Base64 or JSON fabric session authority payload header.") + fs.StringVar(&authoritySignature, "authority-signature", getenv("RAP_FABRIC_SESSION_AUTHORITY_SIGNATURE", ""), "Base64 or JSON fabric session authority signature header.") if err := fs.Parse(args); err != nil { return err } @@ -140,9 +145,17 @@ func runFabricSessionSmoke(ctx context.Context, args []string) error { } smokeCtx, cancel := context.WithTimeout(ctx, time.Duration(timeoutSeconds)*time.Second) defer cancel() + header := make(http.Header) + if strings.TrimSpace(authorityPayload) != "" { + header.Set("X-RAP-Fabric-Session-Authority-Payload", strings.TrimSpace(authorityPayload)) + } + if strings.TrimSpace(authoritySignature) != "" { + header.Set("X-RAP-Fabric-Session-Authority-Signature", strings.TrimSpace(authoritySignature)) + } startedAt := time.Now() response, err := mesh.NewClient(meshURL).SendFabricSessionFrame(smokeCtx, mesh.FabricSessionDialOptions{ Token: token, + Header: header, Timeout: time.Duration(timeoutSeconds) * time.Second, }, fabricproto.Frame{ Type: fabricproto.FramePing, @@ -157,6 +170,7 @@ func runFabricSessionSmoke(ctx context.Context, args []string) error { "latency_ms": duration.Milliseconds(), "response_type": response.Type, "sequence": response.Sequence, + "authority": strings.TrimSpace(authorityPayload) != "" || strings.TrimSpace(authoritySignature) != "", } if err != nil { result["error"] = err.Error() @@ -914,7 +928,7 @@ func usage() { rap-host-agent update-host-agent-loop -backend-url URL -cluster-id ID -state-dir DIR rap-host-agent monitor-loop -backend-url URL -cluster-id ID -state-dir DIR --watch-container NAME rap-host-agent monitor-once -backend-url URL -cluster-id ID -state-dir DIR --watch-container NAME - rap-host-agent fabric-session-smoke -mesh-url URL -token rap_fsn_TOKEN + rap-host-agent fabric-session-smoke -mesh-url URL -token rap_fsn_TOKEN [-authority-payload VALUE -authority-signature VALUE] rap-host-agent update -backend-url URL -cluster-id ID -node-id ID [-container-name NAME] rap-host-agent update-loop -backend-url URL -cluster-id ID -node-id ID [-container-name NAME] rap-host-agent status [-container-name NAME]`) diff --git a/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md b/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md index 9bc2d1a..48682ea 100644 --- a/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md +++ b/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md @@ -259,7 +259,9 @@ Deliverables: Status: started with a transport-neutral `io.Reader`/`io.Writer` frame loop, WebSocket frame adapter in `agents/rap-node-agent/internal/fabricproto`, and a gated/authenticated mesh smoke endpoint/client at `/mesh/v1/fabric/session/ws`. -`rap-host-agent fabric-session-smoke` provides the first operator smoke command. +`rap-host-agent fabric-session-smoke` provides the first operator smoke command +and can pass signed fabric-session authority payload/signature headers for +authority-pinned nodes. Node-agent exposes the endpoint only when `RAP_MESH_FABRIC_SESSION_ENABLED` / `-mesh-fabric-session-enabled` is set, and reports the enabled endpoint in heartbeat metadata.