phase 4: connectrpc on the gateway authenticated edge

Replace the native-gRPC server bootstrap with a single
`connectrpc.com/connect` HTTP/h2c listener. Connect-Go natively
serves Connect, gRPC, and gRPC-Web on the same port, so browsers can
now reach the authenticated surface without giving up the gRPC
framing native and desktop clients may use later. The decorator
stack (envelope → session → payload-hash → signature →
freshness/replay → rate-limit → routing/push) is reused unchanged
behind a small Connect → gRPC adapter and a `grpc.ServerStream`
shim around `*connect.ServerStream`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-07 11:49:28 +02:00
parent 39b7b2ef29
commit 118f7c17a2
30 changed files with 1009 additions and 772 deletions
+20 -9
View File
@@ -7,19 +7,21 @@ import (
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"time"
"galaxy/gateway/authn"
"galaxy/gateway/internal/downstream"
"galaxy/gateway/internal/session"
gatewayv1 "galaxy/gateway/proto/galaxy/gateway/v1"
"galaxy/gateway/proto/galaxy/gateway/v1/gatewayv1connect"
gatewayfbs "galaxy/schema/fbs/gateway"
"connectrpc.com/connect"
flatbuffers "github.com/google/flatbuffers/go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
)
var (
@@ -170,28 +172,37 @@ func (c fixedClock) Now() time.Time {
func recvBootstrapEvent(t interface {
require.TestingT
Helper()
}, stream grpc.ServerStreamingClient[gatewayv1.GatewayEvent]) *gatewayv1.GatewayEvent {
}, stream *connect.ServerStreamForClient[gatewayv1.GatewayEvent]) *gatewayv1.GatewayEvent {
t.Helper()
event, err := stream.Recv()
require.NoError(t, err)
if !stream.Receive() {
err := stream.Err()
if err == nil {
err = errors.New("stream closed before bootstrap event")
}
require.NoError(t, err)
}
return event
return stream.Msg()
}
func subscribeEventsError(t interface {
require.TestingT
Helper()
}, ctx context.Context, client gatewayv1.EdgeGatewayClient, req *gatewayv1.SubscribeEventsRequest) error {
}, ctx context.Context, client gatewayv1connect.EdgeGatewayClient, req *gatewayv1.SubscribeEventsRequest) error {
t.Helper()
stream, err := client.SubscribeEvents(ctx, req)
stream, err := client.SubscribeEvents(ctx, connect.NewRequest(req))
if err != nil {
return err
}
defer func() { _ = stream.Close() }()
_, err = stream.Recv()
return err
if stream.Receive() {
return nil
}
return stream.Err()
}
func assertServerTimeBootstrapEvent(t interface {