package webingress import ( "context" "crypto/ed25519" "crypto/rand" "encoding/base64" "encoding/json" "errors" "net/http" "testing" ) func TestFabricRuntimeReceiverVerifiesEnvelopeAndReturnsRuntimeResponse(t *testing.T) { publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatalf("generate key: %v", err) } keyID := ed25519EnvelopeKeyID(publicKey) receiver := FabricRuntimeReceiver{ Config: ReceiverConfig{ServiceType: "global-admin-runtime", Scope: "platform", ServiceClasses: []string{"platform_admin"}}, Keys: StaticEnvelopeKeyResolver{keyID: publicKey}, Handler: recordingRuntimeHandler{response: FabricResponse{ StatusCode: http.StatusCreated, Headers: http.Header{"X-RAP-Runtime": []string{"ok"}, "Set-Cookie": []string{"blocked"}}, Body: []byte(`{"ok":true}`), }}, Now: fixedEnvelopeNow, } payload := signedReceiverEnvelope(t, privateKey, keyID, FabricServiceChannelEnvelope{ SchemaVersion: FabricServiceChannelEnvelopeSchema, RequestSchema: "rap.web_ingress.fabric_request.v1", Method: http.MethodPost, Path: "/platform-admin/root", Query: "tab=nodes", Host: "admin.example.test", ServiceType: "admin-ingress", Scope: "platform", ServiceClass: "platform_admin", Headers: map[string][]string{"X-Trace-Id": {"trace-1"}}, BodyBase64: base64.StdEncoding.EncodeToString([]byte(`{"hello":"world"}`)), ObservedAt: "2026-05-17T00:00:00Z", EnvelopedAt: "2026-05-17T00:00:01Z", }) responsePayload, err := receiver.Receive(context.Background(), payload) if err != nil { t.Fatalf("receive: %v", err) } var response struct { SchemaVersion string `json:"schema_version"` StatusCode int `json:"status_code"` Headers map[string][]string `json:"headers"` BodyBase64 string `json:"body_b64"` } if err := json.Unmarshal(responsePayload, &response); err != nil { t.Fatalf("decode response: %v", err) } if response.SchemaVersion != FabricRuntimeResponseSchema || response.StatusCode != http.StatusCreated || response.Headers["X-Rap-Runtime"][0] != "ok" || response.Headers["Set-Cookie"] != nil || response.BodyBase64 != "eyJvayI6dHJ1ZX0=" { t.Fatalf("response = %+v", response) } } func TestFabricRuntimeReceiverRejectsBadSignatureScopeClassAndStaleEnvelope(t *testing.T) { publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatalf("generate key: %v", err) } keyID := ed25519EnvelopeKeyID(publicKey) receiver := FabricRuntimeReceiver{ Config: ReceiverConfig{Scope: "platform", ServiceClasses: []string{"platform_admin"}}, Keys: StaticEnvelopeKeyResolver{keyID: publicKey}, Handler: recordingRuntimeHandler{}, Now: fixedEnvelopeNow, } base := FabricServiceChannelEnvelope{ SchemaVersion: FabricServiceChannelEnvelopeSchema, RequestSchema: "rap.web_ingress.fabric_request.v1", Method: http.MethodGet, Path: "/platform-admin/root", Scope: "platform", ServiceClass: "platform_admin", ObservedAt: "2026-05-17T00:00:00Z", EnvelopedAt: "2026-05-17T00:00:01Z", } badSignature := signedReceiverEnvelope(t, privateKey, keyID, base) badSignature[len(badSignature)-2] = 'x' if _, err := receiver.Receive(context.Background(), badSignature); !errors.Is(err, ErrFabricEnvelopeSignatureInvalid) { t.Fatalf("bad signature err = %v", err) } wrongScope := base wrongScope.Scope = "organization" if _, err := receiver.Receive(context.Background(), signedReceiverEnvelope(t, privateKey, keyID, wrongScope)); !errors.Is(err, ErrFabricEnvelopeUnauthorized) { t.Fatalf("wrong scope err = %v", err) } wrongClass := base wrongClass.ServiceClass = "cluster_admin" if _, err := receiver.Receive(context.Background(), signedReceiverEnvelope(t, privateKey, keyID, wrongClass)); !errors.Is(err, ErrFabricEnvelopeUnauthorized) { t.Fatalf("wrong class err = %v", err) } stale := base stale.EnvelopedAt = "2026-05-16T00:00:00Z" if _, err := receiver.Receive(context.Background(), signedReceiverEnvelope(t, privateKey, keyID, stale)); !errors.Is(err, ErrFabricEnvelopeUnauthorized) { t.Fatalf("stale err = %v", err) } } func TestFabricRuntimeReceiverRequiresTrustedKeyAndHandler(t *testing.T) { publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatalf("generate key: %v", err) } keyID := ed25519EnvelopeKeyID(publicKey) payload := signedReceiverEnvelope(t, privateKey, keyID, FabricServiceChannelEnvelope{ SchemaVersion: FabricServiceChannelEnvelopeSchema, Scope: "platform", ServiceClass: "platform_admin", ObservedAt: "2026-05-17T00:00:00Z", EnvelopedAt: "2026-05-17T00:00:01Z", }) _, err = (FabricRuntimeReceiver{Keys: StaticEnvelopeKeyResolver{keyID: publicKey}, Now: fixedEnvelopeNow}).Receive(context.Background(), payload) if !errors.Is(err, ErrFabricEnvelopeRuntimeRequired) { t.Fatalf("handler err = %v", err) } _, err = (FabricRuntimeReceiver{Handler: recordingRuntimeHandler{}, Now: fixedEnvelopeNow}).Receive(context.Background(), payload) if !errors.Is(err, ErrFabricEnvelopeSignatureInvalid) { t.Fatalf("key resolver err = %v", err) } _, otherPrivateKey, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatalf("generate other key: %v", err) } untrusted := signedReceiverEnvelope(t, otherPrivateKey, "other-key", FabricServiceChannelEnvelope{ SchemaVersion: FabricServiceChannelEnvelopeSchema, Scope: "platform", ServiceClass: "platform_admin", ObservedAt: "2026-05-17T00:00:00Z", EnvelopedAt: "2026-05-17T00:00:01Z", }) _, err = (FabricRuntimeReceiver{Keys: StaticEnvelopeKeyResolver{keyID: publicKey}, Handler: recordingRuntimeHandler{}, Now: fixedEnvelopeNow}).Receive(context.Background(), untrusted) if !errors.Is(err, ErrFabricEnvelopeUnauthorized) { t.Fatalf("untrusted key err = %v", err) } } func signedReceiverEnvelope(t *testing.T, privateKey ed25519.PrivateKey, keyID string, envelope FabricServiceChannelEnvelope) []byte { t.Helper() canonical, err := json.Marshal(envelope) if err != nil { t.Fatalf("marshal envelope: %v", err) } payload, err := json.Marshal(SignedFabricServiceChannelEnvelope{ SchemaVersion: SignedFabricServiceChannelEnvelopeSchema, Envelope: envelope, Signature: FabricEnvelopeSignature{ KeyID: keyID, Alg: "ed25519", Signature: base64.StdEncoding.EncodeToString(ed25519.Sign(privateKey, canonical)), SignedAt: "2026-05-17T00:00:01Z", }, }) if err != nil { t.Fatalf("marshal signed envelope: %v", err) } return payload } type recordingRuntimeHandler struct { request FabricRequest response FabricResponse err error } func (h recordingRuntimeHandler) HandleFabricRequest(_ context.Context, request FabricRequest) (FabricResponse, error) { h.request = request if h.err != nil { return FabricResponse{}, h.err } if h.response.StatusCode == 0 { h.response = FabricResponse{StatusCode: http.StatusOK, Body: []byte(`{"ready":true}`)} } return h.response, nil }