feat: backend service
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user