Files
galaxy-game/integration/gateway_edge_test.go
T
2026-05-06 10:14:55 +03:00

191 lines
6.5 KiB
Go

package integration_test
import (
"context"
"crypto/sha256"
"strings"
"testing"
"time"
"galaxy/integration/testenv"
usermodel "galaxy/model/user"
"galaxy/transcoder"
"github.com/google/uuid"
)
// TestGatewayEdge_PublicBodyTooLarge tightens the public body size
// limit and asserts that the gateway rejects an oversize public auth
// payload before reaching backend.
func TestGatewayEdge_PublicBodyTooLarge(t *testing.T) {
plat := testenv.Bootstrap(t, testenv.BootstrapOptions{
GatewayExtra: map[string]string{
"GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_AUTH_MAX_BODY_BYTES": "256",
},
})
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
huge := strings.Repeat("x", 4096)
public := testenv.NewPublicRESTClient(plat.Gateway.HTTPURL)
_, _, err := public.SendEmailCode(ctx, huge+"@example.com", "")
if err == nil {
t.Fatalf("expected error for oversize public payload, got nil")
}
if !strings.Contains(err.Error(), "413") && !strings.Contains(err.Error(), "request_too_large") {
t.Fatalf("expected 413 or request_too_large, got: %v", err)
}
}
// TestGatewayEdge_BadSignature corrupts the request signature and
// asserts the gateway rejects it as Unauthenticated.
func TestGatewayEdge_BadSignature(t *testing.T) {
plat := testenv.Bootstrap(t, testenv.BootstrapOptions{})
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
sess := testenv.RegisterSession(t, plat, "pilot+badsig@example.com")
gw, err := sess.DialAuthenticated(ctx, plat)
if err != nil {
t.Fatalf("dial: %v", err)
}
defer gw.Close()
payload, err := transcoder.GetMyAccountRequestToPayload(&usermodel.GetMyAccountRequest{})
if err != nil {
t.Fatalf("encode payload: %v", err)
}
bogus := make([]byte, 64)
_, err = gw.Execute(ctx, usermodel.MessageTypeGetMyAccount, payload, testenv.ExecuteOptions{
OverrideSignature: bogus,
})
if err == nil {
t.Fatalf("expected Unauthenticated for bad signature")
}
if !testenv.IsUnauthenticated(err) {
t.Fatalf("expected Unauthenticated, got: %v", err)
}
}
// TestGatewayEdge_PayloadHashMismatch sends a request whose
// payload_hash is not the SHA-256 of payload_bytes and asserts the
// gateway rejects it.
func TestGatewayEdge_PayloadHashMismatch(t *testing.T) {
plat := testenv.Bootstrap(t, testenv.BootstrapOptions{})
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
sess := testenv.RegisterSession(t, plat, "pilot+hash@example.com")
gw, err := sess.DialAuthenticated(ctx, plat)
if err != nil {
t.Fatalf("dial: %v", err)
}
defer gw.Close()
payload, err := transcoder.GetMyAccountRequestToPayload(&usermodel.GetMyAccountRequest{})
if err != nil {
t.Fatalf("encode payload: %v", err)
}
// The signed canonical bytes still use this wrong hash; gateway
// recomputes and should detect the mismatch independently of the
// signature check.
wrong := sha256.Sum256([]byte("not-the-payload"))
_, err = gw.Execute(ctx, usermodel.MessageTypeGetMyAccount, payload, testenv.ExecuteOptions{
OverridePayloadHash: wrong[:],
})
if err == nil {
t.Fatalf("expected rejection for payload_hash mismatch")
}
if !testenv.IsUnauthenticated(err) && !testenv.IsInvalidArgument(err) {
t.Fatalf("expected Unauthenticated or InvalidArgument, got: %v", err)
}
}
// TestGatewayEdge_StaleTimestamp tightens freshness window to 1
// second, then submits a request whose timestamp is 30 seconds in
// the past, and asserts the gateway rejects it as stale.
func TestGatewayEdge_StaleTimestamp(t *testing.T) {
plat := testenv.Bootstrap(t, testenv.BootstrapOptions{
GatewayExtra: map[string]string{
"GATEWAY_AUTHENTICATED_GRPC_FRESHNESS_WINDOW": "1s",
},
})
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
sess := testenv.RegisterSession(t, plat, "pilot+stale@example.com")
gw, err := sess.DialAuthenticated(ctx, plat)
if err != nil {
t.Fatalf("dial: %v", err)
}
defer gw.Close()
payload, err := transcoder.GetMyAccountRequestToPayload(&usermodel.GetMyAccountRequest{})
if err != nil {
t.Fatalf("encode payload: %v", err)
}
stale := time.Now().Add(-30 * time.Second).UnixMilli()
_, err = gw.Execute(ctx, usermodel.MessageTypeGetMyAccount, payload, testenv.ExecuteOptions{
TimestampMS: stale,
})
if err == nil {
t.Fatalf("expected rejection for stale timestamp")
}
if !testenv.IsUnauthenticated(err) && !testenv.IsInvalidArgument(err) && !testenv.IsFailedPrecondition(err) {
t.Fatalf("expected Unauthenticated, InvalidArgument or FailedPrecondition, got: %v", err)
}
}
// TestGatewayEdge_UnknownSession addresses a session id that backend
// has never seen; gateway must reject before forwarding.
func TestGatewayEdge_UnknownSession(t *testing.T) {
plat := testenv.Bootstrap(t, testenv.BootstrapOptions{})
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
sess := testenv.RegisterSession(t, plat, "pilot+unknown@example.com")
gw, err := sess.DialAuthenticated(ctx, plat)
if err != nil {
t.Fatalf("dial: %v", err)
}
defer gw.Close()
payload, err := transcoder.GetMyAccountRequestToPayload(&usermodel.GetMyAccountRequest{})
if err != nil {
t.Fatalf("encode payload: %v", err)
}
_, err = gw.Execute(ctx, usermodel.MessageTypeGetMyAccount, payload, testenv.ExecuteOptions{
OverrideSessionID: uuid.NewString(),
})
if err == nil {
t.Fatalf("expected rejection for unknown session")
}
if !testenv.IsUnauthenticated(err) {
t.Fatalf("expected Unauthenticated, got: %v", err)
}
}
// TestGatewayEdge_UnsupportedProtocolVersion sets protocol_version
// to an unknown literal and asserts gateway rejection.
func TestGatewayEdge_UnsupportedProtocolVersion(t *testing.T) {
plat := testenv.Bootstrap(t, testenv.BootstrapOptions{})
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
sess := testenv.RegisterSession(t, plat, "pilot+protover@example.com")
gw, err := sess.DialAuthenticated(ctx, plat)
if err != nil {
t.Fatalf("dial: %v", err)
}
defer gw.Close()
payload, err := transcoder.GetMyAccountRequestToPayload(&usermodel.GetMyAccountRequest{})
if err != nil {
t.Fatalf("encode payload: %v", err)
}
_, err = gw.Execute(ctx, usermodel.MessageTypeGetMyAccount, payload, testenv.ExecuteOptions{
OverrideProtocolVersion: "v999",
})
if err == nil {
t.Fatalf("expected rejection for unsupported protocol_version")
}
if !testenv.IsInvalidArgument(err) && !testenv.IsUnauthenticated(err) && !testenv.IsFailedPrecondition(err) {
t.Fatalf("expected InvalidArgument, Unauthenticated or FailedPrecondition, got: %v", err)
}
}