From dd7d1e414e3b6bef042c485a12390a8b5a850967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Banaszewski?= Date: Fri, 10 Apr 2026 13:08:03 +0000 Subject: [PATCH 1/2] chore: lint fixes part 4 --- circuitbreaker/circuitbreaker.go | 4 +- intercept/apidump/apidump.go | 4 +- intercept/chatcompletions/base.go | 4 +- intercept/chatcompletions/blocking.go | 4 +- intercept/chatcompletions/streaming.go | 4 +- intercept/interceptor.go | 2 +- intercept/messages/base.go | 4 +- intercept/messages/blocking.go | 4 +- intercept/messages/streaming.go | 4 +- intercept/responses/base.go | 4 +- intercept/responses/blocking.go | 4 +- intercept/responses/streaming.go | 4 +- internal/integrationtest/apidump_test.go | 6 +- internal/integrationtest/bridge_test.go | 70 +++++++++---------- .../integrationtest/circuit_breaker_test.go | 8 +-- internal/integrationtest/metrics_test.go | 24 +++---- internal/integrationtest/mockupstream.go | 6 +- internal/integrationtest/responses_test.go | 22 +++--- internal/integrationtest/setupbridge.go | 6 +- internal/integrationtest/trace_test.go | 20 +++--- passthrough.go | 10 +-- recorder/recorder.go | 2 +- 22 files changed, 110 insertions(+), 110 deletions(-) diff --git a/circuitbreaker/circuitbreaker.go b/circuitbreaker/circuitbreaker.go index ae4f226c..cdba12d6 100644 --- a/circuitbreaker/circuitbreaker.go +++ b/circuitbreaker/circuitbreaker.go @@ -77,7 +77,7 @@ func (p *ProviderCircuitBreakers) openErrorResponse() []byte { func (p *ProviderCircuitBreakers) Get(endpoint, model string) *gobreaker.CircuitBreaker[struct{}] { key := endpoint + ":" + model if v, ok := p.breakers.Load(key); ok { - return v.(*gobreaker.CircuitBreaker[struct{}]) + return v.(*gobreaker.CircuitBreaker[struct{}]) //nolint:forcetypeassert // sync.Map always stores this type } settings := gobreaker.Settings{ @@ -97,7 +97,7 @@ func (p *ProviderCircuitBreakers) Get(endpoint, model string) *gobreaker.Circuit cb := gobreaker.NewCircuitBreaker[struct{}](settings) actual, _ := p.breakers.LoadOrStore(key, cb) - return actual.(*gobreaker.CircuitBreaker[struct{}]) + return actual.(*gobreaker.CircuitBreaker[struct{}]) //nolint:forcetypeassert // sync.Map always stores this type } // statusCapturingWriter wraps http.ResponseWriter to capture the status code. diff --git a/intercept/apidump/apidump.go b/intercept/apidump/apidump.go index 2f3dd674..41fd70cd 100644 --- a/intercept/apidump/apidump.go +++ b/intercept/apidump/apidump.go @@ -109,7 +109,7 @@ func (d *dumper) dumpRequest(req *http.Request) error { buf.Write(prettyBody) buf.WriteByte('\n') - return os.WriteFile(dumpPath, buf.Bytes(), 0o644) + return os.WriteFile(dumpPath, buf.Bytes(), 0o600) } func (d *dumper) dumpResponse(resp *http.Response) error { @@ -132,7 +132,7 @@ func (d *dumper) dumpResponse(resp *http.Response) error { if resp.Body == nil { // No body, just write headers - return os.WriteFile(dumpPath, headerBuf.Bytes(), 0o644) + return os.WriteFile(dumpPath, headerBuf.Bytes(), 0o600) } // Wrap the response body to capture it as it streams diff --git a/intercept/chatcompletions/base.go b/intercept/chatcompletions/base.go index 1cf10ddd..ca9d061f 100644 --- a/intercept/chatcompletions/base.go +++ b/intercept/chatcompletions/base.go @@ -80,9 +80,9 @@ func (i *interceptionBase) Credential() intercept.CredentialInfo { return i.credential } -func (i *interceptionBase) Setup(logger slog.Logger, recorder recorder.Recorder, mcpProxy mcp.ServerProxier) { +func (i *interceptionBase) Setup(logger slog.Logger, rec recorder.Recorder, mcpProxy mcp.ServerProxier) { i.logger = logger - i.recorder = recorder + i.recorder = rec i.mcpProxy = mcpProxy } diff --git a/intercept/chatcompletions/blocking.go b/intercept/chatcompletions/blocking.go index 531577f4..8dd98463 100644 --- a/intercept/chatcompletions/blocking.go +++ b/intercept/chatcompletions/blocking.go @@ -51,8 +51,8 @@ func NewBlockingInterceptor( }} } -func (i *BlockingInterception) Setup(logger slog.Logger, recorder recorder.Recorder, mcpProxy mcp.ServerProxier) { - i.interceptionBase.Setup(logger.Named("blocking"), recorder, mcpProxy) +func (i *BlockingInterception) Setup(logger slog.Logger, rec recorder.Recorder, mcpProxy mcp.ServerProxier) { + i.interceptionBase.Setup(logger.Named("blocking"), rec, mcpProxy) } func (*BlockingInterception) Streaming() bool { diff --git a/intercept/chatcompletions/streaming.go b/intercept/chatcompletions/streaming.go index dbb30622..fb37a73c 100644 --- a/intercept/chatcompletions/streaming.go +++ b/intercept/chatcompletions/streaming.go @@ -55,8 +55,8 @@ func NewStreamingInterceptor( }} } -func (i *StreamingInterception) Setup(logger slog.Logger, recorder recorder.Recorder, mcpProxy mcp.ServerProxier) { - i.interceptionBase.Setup(logger.Named("streaming"), recorder, mcpProxy) +func (i *StreamingInterception) Setup(logger slog.Logger, rec recorder.Recorder, mcpProxy mcp.ServerProxier) { + i.interceptionBase.Setup(logger.Named("streaming"), rec, mcpProxy) } func (*StreamingInterception) Streaming() bool { diff --git a/intercept/interceptor.go b/intercept/interceptor.go index 4517ebd4..47a61a29 100644 --- a/intercept/interceptor.go +++ b/intercept/interceptor.go @@ -17,7 +17,7 @@ type Interceptor interface { ID() uuid.UUID // Setup injects some required dependencies. This MUST be called before using the interceptor // to process requests. - Setup(logger slog.Logger, recorder recorder.Recorder, mcpProxy mcp.ServerProxier) + Setup(logger slog.Logger, rec recorder.Recorder, mcpProxy mcp.ServerProxier) // Model returns the model in use for this [Interceptor]. Model() string // ProcessRequest handles the HTTP request. diff --git a/intercept/messages/base.go b/intercept/messages/base.go index 0cd5a631..8a4dbf0b 100644 --- a/intercept/messages/base.go +++ b/intercept/messages/base.go @@ -92,9 +92,9 @@ func (i *interceptionBase) Credential() intercept.CredentialInfo { return i.credential } -func (i *interceptionBase) Setup(logger slog.Logger, recorder recorder.Recorder, mcpProxy mcp.ServerProxier) { +func (i *interceptionBase) Setup(logger slog.Logger, rec recorder.Recorder, mcpProxy mcp.ServerProxier) { i.logger = logger - i.recorder = recorder + i.recorder = rec i.mcpProxy = mcpProxy } diff --git a/intercept/messages/blocking.go b/intercept/messages/blocking.go index aee4b403..9ac31f30 100644 --- a/intercept/messages/blocking.go +++ b/intercept/messages/blocking.go @@ -54,8 +54,8 @@ func NewBlockingInterceptor( }} } -func (i *BlockingInterception) Setup(logger slog.Logger, recorder recorder.Recorder, mcpProxy mcp.ServerProxier) { - i.interceptionBase.Setup(logger.Named("blocking"), recorder, mcpProxy) +func (i *BlockingInterception) Setup(logger slog.Logger, rec recorder.Recorder, mcpProxy mcp.ServerProxier) { + i.interceptionBase.Setup(logger.Named("blocking"), rec, mcpProxy) } func (i *BlockingInterception) TraceAttributes(r *http.Request) []attribute.KeyValue { diff --git a/intercept/messages/streaming.go b/intercept/messages/streaming.go index e6247d74..f9f056fc 100644 --- a/intercept/messages/streaming.go +++ b/intercept/messages/streaming.go @@ -59,8 +59,8 @@ func NewStreamingInterceptor( }} } -func (i *StreamingInterception) Setup(logger slog.Logger, recorder recorder.Recorder, mcpProxy mcp.ServerProxier) { - i.interceptionBase.Setup(logger.Named("streaming"), recorder, mcpProxy) +func (i *StreamingInterception) Setup(logger slog.Logger, rec recorder.Recorder, mcpProxy mcp.ServerProxier) { + i.interceptionBase.Setup(logger.Named("streaming"), rec, mcpProxy) } func (*StreamingInterception) Streaming() bool { diff --git a/intercept/responses/base.go b/intercept/responses/base.go index 06ae8d53..baa1f443 100644 --- a/intercept/responses/base.go +++ b/intercept/responses/base.go @@ -89,9 +89,9 @@ func (i *responsesInterceptionBase) Credential() intercept.CredentialInfo { return i.credential } -func (i *responsesInterceptionBase) Setup(logger slog.Logger, recorder recorder.Recorder, mcpProxy mcp.ServerProxier) { +func (i *responsesInterceptionBase) Setup(logger slog.Logger, rec recorder.Recorder, mcpProxy mcp.ServerProxier) { i.logger = logger.With(slog.F("model", i.Model())) - i.recorder = recorder + i.recorder = rec i.mcpProxy = mcpProxy } diff --git a/intercept/responses/blocking.go b/intercept/responses/blocking.go index 69723a1c..ed755567 100644 --- a/intercept/responses/blocking.go +++ b/intercept/responses/blocking.go @@ -50,8 +50,8 @@ func NewBlockingInterceptor( } } -func (i *BlockingResponsesInterceptor) Setup(logger slog.Logger, recorder recorder.Recorder, mcpProxy mcp.ServerProxier) { - i.responsesInterceptionBase.Setup(logger.Named("blocking"), recorder, mcpProxy) +func (i *BlockingResponsesInterceptor) Setup(logger slog.Logger, rec recorder.Recorder, mcpProxy mcp.ServerProxier) { + i.responsesInterceptionBase.Setup(logger.Named("blocking"), rec, mcpProxy) } func (*BlockingResponsesInterceptor) Streaming() bool { diff --git a/intercept/responses/streaming.go b/intercept/responses/streaming.go index 2d3a072f..f5a23460 100644 --- a/intercept/responses/streaming.go +++ b/intercept/responses/streaming.go @@ -57,8 +57,8 @@ func NewStreamingInterceptor( } } -func (i *StreamingResponsesInterceptor) Setup(logger slog.Logger, recorder recorder.Recorder, mcpProxy mcp.ServerProxier) { - i.responsesInterceptionBase.Setup(logger.Named("streaming"), recorder, mcpProxy) +func (i *StreamingResponsesInterceptor) Setup(logger slog.Logger, rec recorder.Recorder, mcpProxy mcp.ServerProxier) { + i.responsesInterceptionBase.Setup(logger.Named("streaming"), rec, mcpProxy) } func (*StreamingResponsesInterceptor) Streaming() bool { diff --git a/internal/integrationtest/apidump_test.go b/internal/integrationtest/apidump_test.go index f3e4a741..41e23551 100644 --- a/internal/integrationtest/apidump_test.go +++ b/internal/integrationtest/apidump_test.go @@ -119,12 +119,12 @@ func TestAPIDump(t *testing.T) { // Setup mock upstream server. fix := fixtures.Parse(t, tc.fixture) - srv := newMockUpstream(t, ctx, newFixtureResponse(fix)) + srv := newMockUpstream(ctx, t, newFixtureResponse(fix)) // Create temp dir for API dumps. dumpDir := t.TempDir() - bridgeServer := newBridgeTestServer(t, ctx, srv.URL, + bridgeServer := newBridgeTestServer(ctx, t, srv.URL, withCustomProvider(tc.providerFunc(srv.URL, dumpDir)), ) @@ -252,7 +252,7 @@ func TestAPIDumpPassthrough(t *testing.T) { dumpDir := t.TempDir() - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withCustomProvider(tc.providerFunc(upstream.URL, dumpDir)), ) diff --git a/internal/integrationtest/bridge_test.go b/internal/integrationtest/bridge_test.go index 73f42ad3..519c2e97 100644 --- a/internal/integrationtest/bridge_test.go +++ b/internal/integrationtest/bridge_test.go @@ -82,9 +82,9 @@ func TestAnthropicMessages(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, fixtures.AntSingleBuiltinTool) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL) // Make API call to aibridge for Anthropic /v1/messages reqBody, err := sjson.SetBytes(fix.Request(), "stream", tc.streaming) @@ -214,9 +214,9 @@ func TestAnthropicMessagesModelThoughts(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL) reqBody, err := sjson.SetBytes(fix.Request(), "stream", tc.streaming) require.NoError(t, err) @@ -254,7 +254,7 @@ func TestAWSBedrockIntegration(t *testing.T) { SmallFastModel: "test-haiku", } - bridgeServer := newBridgeTestServer(t, ctx, "http://unused", + bridgeServer := newBridgeTestServer(ctx, t, "http://unused", withCustomProvider(provider.NewAnthropic(anthropicCfg("http://unused", apiKey), bedrockCfg)), ) @@ -276,7 +276,7 @@ func TestAWSBedrockIntegration(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, fixtures.AntSingleBuiltinTool) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) // We define region here to validate that with Region & BaseURL defined, the latter takes precedence. bedrockCfg := &config.AWSBedrock{ @@ -288,7 +288,7 @@ func TestAWSBedrockIntegration(t *testing.T) { BaseURL: upstream.URL, // Use the mock server. } - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withCustomProvider(provider.NewAnthropic(anthropicCfg(upstream.URL, apiKey), bedrockCfg)), ) @@ -400,7 +400,7 @@ func TestAWSBedrockIntegration(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, fixtures.AntSimpleBedrock) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) bCfg := &config.AWSBedrock{ Region: "us-west-2", @@ -411,7 +411,7 @@ func TestAWSBedrockIntegration(t *testing.T) { BaseURL: upstream.URL, } - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withCustomProvider(provider.NewAnthropic(anthropicCfg(upstream.URL, apiKey), bCfg)), ) @@ -495,9 +495,9 @@ func TestOpenAIChatCompletions(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, fixtures.OaiChatSingleBuiltinTool) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL) // Make API call to aibridge for OpenAI /v1/chat/completions reqBody, err := sjson.SetBytes(fix.Request(), "stream", tc.streaming) @@ -571,12 +571,12 @@ func TestOpenAIChatCompletions(t *testing.T) { // Setup mock server for multi-turn interaction. // First request → tool call response, second → tool response. fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix), newFixtureToolResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix), newFixtureToolResponse(fix)) // Setup MCP proxies with the tool from the fixture mockMCP := setupMCPForTest(t, defaultTracer) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withMCP(mockMCP), ) @@ -760,9 +760,9 @@ func TestSimple(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL+tc.basePath) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL+tc.basePath) // When: calling the "API server" with the fixture's request body. reqBody, err := sjson.SetBytes(fix.Request(), "stream", streaming) @@ -865,8 +865,8 @@ func TestSessionIDTracking(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, withProvider(config.ProviderAnthropic)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withProvider(config.ProviderAnthropic)) reqBody := fix.Request() if tc.metadataSessionID != "" { @@ -948,8 +948,8 @@ func TestFallthrough(t *testing.T) { t.Parallel() fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, t.Context(), newFixtureResponse(fix)) - bridgeServer := newBridgeTestServer(t, t.Context(), upstream.URL+tc.basePath) + upstream := newMockUpstream(t.Context(), t, newFixtureResponse(fix)) + bridgeServer := newBridgeTestServer(t.Context(), t, upstream.URL+tc.basePath) resp := bridgeServer.makeRequest(t, http.MethodGet, tc.requestPath, nil) @@ -1282,9 +1282,9 @@ func TestErrorHandling(t *testing.T) { // Setup mock server. Error fixtures contain raw HTTP // responses that may cause the bridge to retry. fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL) // Add the stream param to the request. reqBody, err := sjson.SetBytes(fix.Request(), "stream", streaming) @@ -1352,10 +1352,10 @@ func TestErrorHandling(t *testing.T) { // Setup mock server. fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) upstream.StatusCode = http.StatusInternalServerError - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL) resp := bridgeServer.makeRequest(t, http.MethodPost, tc.path, fix.Request()) @@ -1408,9 +1408,9 @@ func TestStableRequestEncoding(t *testing.T) { for i := range count { responses[i] = newFixtureResponse(fix) } - upstream := newMockUpstream(t, ctx, responses...) + upstream := newMockUpstream(ctx, t, responses...) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withMCP(mockMCP), ) @@ -1669,9 +1669,9 @@ func TestAnthropicToolChoiceParallelDisabled(t *testing.T) { } fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withMCP(mockMCP), ) @@ -1823,13 +1823,13 @@ func TestChatCompletionsParallelToolCallsDisabled(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) var opts []bridgeOption if tc.withInjectedTools { opts = append(opts, withMCP(setupMCPForTest(t, defaultTracer))) } - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, opts...) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, opts...) var ( reqBody = fix.Request() @@ -1876,9 +1876,9 @@ func TestThinkingAdaptiveIsPreserved(t *testing.T) { t.Cleanup(cancel) // Create a mock server that captures the request body sent upstream. - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL) // Inject adaptive thinking into the fixture request. reqBody, err := sjson.SetBytes(fix.Request(), "thinking", map[string]string{"type": "adaptive"}) @@ -1939,7 +1939,7 @@ func TestEnvironmentDoNotLeak(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) // Set environment variables that the SDK would automatically read. // These should NOT leak into upstream requests. @@ -1947,7 +1947,7 @@ func TestEnvironmentDoNotLeak(t *testing.T) { t.Setenv(key, val) } - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL) resp := bridgeServer.makeRequest(t, http.MethodPost, tc.path, fix.Request()) require.Equal(t, http.StatusOK, resp.StatusCode) @@ -2049,10 +2049,10 @@ func TestActorHeaders(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) metadataKey := "Username" - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withCustomProvider(tc.createProviderFn(upstream.URL, apiKey, send)), withActor(defaultActorID, recorder.Metadata{ metadataKey: actorUsername, diff --git a/internal/integrationtest/circuit_breaker_test.go b/internal/integrationtest/circuit_breaker_test.go index 7072d1b0..4aaf1119 100644 --- a/internal/integrationtest/circuit_breaker_test.go +++ b/internal/integrationtest/circuit_breaker_test.go @@ -130,7 +130,7 @@ func TestCircuitBreaker_FullRecoveryCycle(t *testing.T) { } ctx := t.Context() - bridgeServer := newBridgeTestServer(t, ctx, mockUpstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, mockUpstream.URL, withCustomProvider(tc.createProvider(mockUpstream.URL, cbConfig)), withMetrics(m), withActor("test-user-id", nil), @@ -283,7 +283,7 @@ func TestCircuitBreaker_HalfOpenFailure(t *testing.T) { } ctx := t.Context() - bridgeServer := newBridgeTestServer(t, ctx, mockUpstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, mockUpstream.URL, withCustomProvider(tc.createProvider(mockUpstream.URL, cbConfig)), withMetrics(m), withActor("test-user-id", nil), @@ -429,7 +429,7 @@ func TestCircuitBreaker_HalfOpenMaxRequests(t *testing.T) { } ctx := t.Context() - bridgeServer := newBridgeTestServer(t, ctx, mockUpstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, mockUpstream.URL, withCustomProvider(tc.createProvider(mockUpstream.URL, cbConfig)), withMetrics(m), withActor("test-user-id", nil), @@ -544,7 +544,7 @@ func TestCircuitBreaker_PerModelIsolation(t *testing.T) { MaxRequests: 1, } ctx := t.Context() - bridgeServer := newBridgeTestServer(t, ctx, mockUpstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, mockUpstream.URL, withCustomProvider(provider.NewAnthropic(config.Anthropic{ BaseURL: mockUpstream.URL, Key: "test-key", diff --git a/internal/integrationtest/metrics_test.go b/internal/integrationtest/metrics_test.go index 7e5bf2df..1d8a103d 100644 --- a/internal/integrationtest/metrics_test.go +++ b/internal/integrationtest/metrics_test.go @@ -147,11 +147,11 @@ func TestMetrics_Interception(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) upstream.AllowOverflow = tc.allowOverflow m := aibridge.NewMetrics(prometheus.NewRegistry()) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withMetrics(m), ) @@ -185,7 +185,7 @@ func TestMetrics_InterceptionsInflight(t *testing.T) { t.Cleanup(srv.Close) m := aibridge.NewMetrics(prometheus.NewRegistry()) - bridgeServer := newBridgeTestServer(t, ctx, srv.URL, + bridgeServer := newBridgeTestServer(ctx, t, srv.URL, withMetrics(m), ) @@ -233,7 +233,7 @@ func TestMetrics_PassthroughCount(t *testing.T) { t.Cleanup(upstream.Close) m := aibridge.NewMetrics(prometheus.NewRegistry()) - bridgeServer := newBridgeTestServer(t, t.Context(), upstream.URL, + bridgeServer := newBridgeTestServer(t.Context(), t, upstream.URL, withMetrics(m), ) @@ -252,10 +252,10 @@ func TestMetrics_PromptCount(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, fixtures.OaiChatSimple) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) m := aibridge.NewMetrics(prometheus.NewRegistry()) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withMetrics(m), ) @@ -340,10 +340,10 @@ func TestMetrics_TokenUseCount(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) m := aibridge.NewMetrics(prometheus.NewRegistry()) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withMetrics(m), ) @@ -379,10 +379,10 @@ func TestMetrics_NonInjectedToolUseCount(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, fixtures.OaiChatSingleBuiltinTool) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) m := aibridge.NewMetrics(prometheus.NewRegistry()) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withMetrics(m), ) @@ -404,14 +404,14 @@ func TestMetrics_InjectedToolUseCount(t *testing.T) { // First request returns the tool invocation, the second returns the mocked response to the tool result. fix := fixtures.Parse(t, fixtures.AntSingleInjectedTool) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix), newFixtureToolResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix), newFixtureToolResponse(fix)) m := aibridge.NewMetrics(prometheus.NewRegistry()) // Setup mocked MCP server & tools. mockMCP := setupMCPForTest(t, defaultTracer) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withMetrics(m), withMCP(mockMCP), ) diff --git a/internal/integrationtest/mockupstream.go b/internal/integrationtest/mockupstream.go index 4112fea8..faef0488 100644 --- a/internal/integrationtest/mockupstream.go +++ b/internal/integrationtest/mockupstream.go @@ -111,9 +111,9 @@ func (ms *mockUpstream) receivedRequests() []receivedRequest { // The test fails if the number of requests doesn't match the number of // responses (when AllowOverflow is not set, default). // -// srv := newMockUpstream(t, ctx, newFixtureResponse(fix)) // simple -// srv := newMockUpstream(t, ctx, newFixtureResponse(fix), newFixtureToolResponse(fix)) // multi-turn -func newMockUpstream(t *testing.T, ctx context.Context, responses ...upstreamResponse) *mockUpstream { +// srv := newMockUpstream(ctx, t, newFixtureResponse(fix)) // simple +// srv := newMockUpstream(ctx, t, newFixtureResponse(fix), newFixtureToolResponse(fix)) // multi-turn +func newMockUpstream(ctx context.Context, t *testing.T, responses ...upstreamResponse) *mockUpstream { t.Helper() require.NotEmpty(t, responses, "at least one upstreamResponse required") diff --git a/internal/integrationtest/responses_test.go b/internal/integrationtest/responses_test.go index 6861ccb8..2e9d8cd6 100644 --- a/internal/integrationtest/responses_test.go +++ b/internal/integrationtest/responses_test.go @@ -339,9 +339,9 @@ func TestResponsesOutputMatchesUpstream(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL) resp := bridgeServer.makeRequest(t, http.MethodPost, pathOpenAIResponses, fix.Request(), http.Header{"User-Agent": {tc.userAgent}}) require.Equal(t, http.StatusOK, resp.StatusCode) @@ -426,7 +426,7 @@ func TestResponsesBackgroundModeForbidden(t *testing.T) { })) t.Cleanup(upstream.Close) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL) // Create a request with background mode enabled reqBytes := responsesRequestBytes(t, tc.streaming, keyVal{"background", true}) @@ -551,13 +551,13 @@ func TestResponsesParallelToolsOverwritten(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, tc.fixture[i]) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) var opts []bridgeOption if tc.withInjectedTools { opts = append(opts, withMCP(setupMCPForTest(t, defaultTracer))) } - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, opts...) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, opts...) var ( reqBody = fix.Request() @@ -635,7 +635,7 @@ func TestClientAndConnectionError(t *testing.T) { t.Cleanup(cancel) // tc.addr may be an intentionally invalid URL; use withCustomProvider. - bridgeServer := newBridgeTestServer(t, ctx, tc.addr, withCustomProvider(provider.NewOpenAI(openAICfg(tc.addr, apiKey)))) + bridgeServer := newBridgeTestServer(ctx, t, tc.addr, withCustomProvider(provider.NewOpenAI(openAICfg(tc.addr, apiKey)))) reqBytes := responsesRequestBytes(t, tc.streaming) resp := bridgeServer.makeRequest(t, http.MethodPost, pathOpenAIResponses, reqBytes) @@ -712,7 +712,7 @@ func TestUpstreamError(t *testing.T) { })) t.Cleanup(upstream.Close) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL) reqBytes := responsesRequestBytes(t, tc.streaming) resp := bridgeServer.makeRequest(t, http.MethodPost, pathOpenAIResponses, reqBytes) @@ -886,7 +886,7 @@ func TestResponsesInjectedTool(t *testing.T) { // Setup mock server for multi-turn interaction. // First request → tool call response, second → tool response. fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix), newFixtureToolResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix), newFixtureToolResponse(fix)) // Setup MCP server proxies (with mock tools). mockMCP := setupMCPForTest(t, defaultTracer) @@ -894,7 +894,7 @@ func TestResponsesInjectedTool(t *testing.T) { mockMCP.setToolError(tc.mcpToolName, tc.expectToolError) } - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, withMCP(mockMCP)) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withMCP(mockMCP)) resp := bridgeServer.makeRequest(t, http.MethodPost, pathOpenAIResponses, fix.Request()) require.Equal(t, http.StatusOK, resp.StatusCode) @@ -1029,9 +1029,9 @@ func TestResponsesModelThoughts(t *testing.T) { t.Cleanup(cancel) fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL) resp := bridgeServer.makeRequest(t, http.MethodPost, pathOpenAIResponses, fix.Request()) require.Equal(t, http.StatusOK, resp.StatusCode) diff --git a/internal/integrationtest/setupbridge.go b/internal/integrationtest/setupbridge.go index 5c91953b..17883c2b 100644 --- a/internal/integrationtest/setupbridge.go +++ b/internal/integrationtest/setupbridge.go @@ -133,8 +133,8 @@ func withActor(id string, md recorder.Metadata) bridgeOption { // - defaultTracer (unless withTracer) // - defaultActorID (unless withActor) func newBridgeTestServer( - t *testing.T, ctx context.Context, + t *testing.T, upstreamURL string, opts ...bridgeOption, ) *bridgeTestServer { @@ -220,7 +220,7 @@ func setupInjectedToolTest( firstResp := newFixtureResponse(fix) toolResp := newFixtureToolResponse(fix) toolResp.OnRequest = toolRequestValidatorFn - upstream := newMockUpstream(t, ctx, firstResp, toolResp) + upstream := newMockUpstream(ctx, t, firstResp, toolResp) mockMCP := setupMCPForTest(t, tracer) @@ -230,7 +230,7 @@ func setupInjectedToolTest( withActor(defaultActorID, nil), } allOpts = append(allOpts, opts...) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, allOpts...) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, allOpts...) // Add the stream param to the request. reqBody, err := sjson.SetBytes(fix.Request(), "stream", streaming) diff --git a/internal/integrationtest/trace_test.go b/internal/integrationtest/trace_test.go index 913e4ed3..75fe0949 100644 --- a/internal/integrationtest/trace_test.go +++ b/internal/integrationtest/trace_test.go @@ -143,7 +143,7 @@ func TestTraceAnthropic(t *testing.T) { sr, tracer := setupTracer(t) fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) opts := []bridgeOption{ withTracer(tracer), @@ -151,7 +151,7 @@ func TestTraceAnthropic(t *testing.T) { if tc.bedrock { opts = append(opts, withProvider(providerBedrock)) } - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, opts...) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, opts...) reqBody, err := sjson.SetBytes(fix.Request(), "stream", tc.streaming) require.NoError(t, err) @@ -253,7 +253,7 @@ func TestTraceAnthropicErr(t *testing.T) { sr, tracer := setupTracer(t) fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) opts := []bridgeOption{ withTracer(tracer), @@ -261,7 +261,7 @@ func TestTraceAnthropicErr(t *testing.T) { if tc.bedrock { opts = append(opts, withProvider(providerBedrock)) } - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, opts...) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, opts...) reqBody, err := sjson.SetBytes(fix.Request(), "stream", tc.streaming) require.NoError(t, err) @@ -535,8 +535,8 @@ func TestTraceOpenAI(t *testing.T) { sr, tracer := setupTracer(t) fix := fixtures.Parse(t, tc.fixture) - upstream := newMockUpstream(t, ctx, newFixtureResponse(fix)) - bridgeServer := newBridgeTestServer(t, ctx, upstream.URL, + upstream := newMockUpstream(ctx, t, newFixtureResponse(fix)) + bridgeServer := newBridgeTestServer(ctx, t, upstream.URL, withTracer(tracer), ) @@ -689,9 +689,9 @@ func TestTraceOpenAIErr(t *testing.T) { fix := fixtures.Parse(t, tc.fixture) - mockAPI := newMockUpstream(t, ctx, newFixtureResponse(fix)) + mockAPI := newMockUpstream(ctx, t, newFixtureResponse(fix)) mockAPI.AllowOverflow = tc.allowOverflow - bridgeServer := newBridgeTestServer(t, ctx, mockAPI.URL, + bridgeServer := newBridgeTestServer(ctx, t, mockAPI.URL, withTracer(tracer), ) @@ -729,11 +729,11 @@ func TestTracePassthrough(t *testing.T) { fix := fixtures.Parse(t, fixtures.OaiChatFallthrough) - upstream := newMockUpstream(t, t.Context(), newFixtureResponse(fix)) + upstream := newMockUpstream(t.Context(), t, newFixtureResponse(fix)) sr, tracer := setupTracer(t) - bridgeServer := newBridgeTestServer(t, t.Context(), upstream.URL, + bridgeServer := newBridgeTestServer(t.Context(), t, upstream.URL, withTracer(tracer), ) diff --git a/passthrough.go b/passthrough.go index 5e1efe6a..ae239a32 100644 --- a/passthrough.go +++ b/passthrough.go @@ -21,10 +21,10 @@ import ( // newPassthroughRouter returns a simple reverse-proxy implementation which will be used when a route is not handled specifically // by a [intercept.Provider]. -func newPassthroughRouter(provider provider.Provider, logger slog.Logger, m *metrics.Metrics, tracer trace.Tracer) http.HandlerFunc { +func newPassthroughRouter(prov provider.Provider, logger slog.Logger, m *metrics.Metrics, tracer trace.Tracer) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if m != nil { - m.PassthroughCount.WithLabelValues(provider.Name(), r.URL.Path, r.Method).Add(1) + m.PassthroughCount.WithLabelValues(prov.Name(), r.URL.Path, r.Method).Add(1) } ctx, span := tracer.Start(r.Context(), "Passthrough", trace.WithAttributes( @@ -33,7 +33,7 @@ func newPassthroughRouter(provider provider.Provider, logger slog.Logger, m *met )) defer span.End() - upURL, err := url.Parse(provider.BaseURL()) + upURL, err := url.Parse(prov.BaseURL()) if err != nil { logger.Warn(ctx, "failed to parse provider base URL", slog.Error(err)) http.Error(w, "request error", http.StatusBadGateway) @@ -96,7 +96,7 @@ func newPassthroughRouter(provider provider.Provider, logger slog.Logger, m *met } // Inject provider auth. - provider.InjectAuthHeader(&req.Header) + prov.InjectAuthHeader(&req.Header) }, ErrorHandler: func(rw http.ResponseWriter, req *http.Request, e error) { logger.Warn(req.Context(), "reverse proxy error", slog.Error(e), slog.F("path", req.URL.Path)) @@ -113,7 +113,7 @@ func newPassthroughRouter(provider provider.Provider, logger slog.Logger, m *met TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, } - proxy.Transport = apidump.NewPassthroughMiddleware(t, provider.APIDumpDir(), provider.Name(), logger, quartz.NewReal()) + proxy.Transport = apidump.NewPassthroughMiddleware(t, prov.APIDumpDir(), prov.Name(), logger, quartz.NewReal()) proxy.ServeHTTP(w, r) } diff --git a/recorder/recorder.go b/recorder/recorder.go index bafd1bd5..7e2b988c 100644 --- a/recorder/recorder.go +++ b/recorder/recorder.go @@ -187,7 +187,7 @@ func (a *AsyncRecorder) WithClient(client string) { // RecordInterception must NOT be called asynchronously. // If an interception cannot be recorded, the whole request should fail. -func (a *AsyncRecorder) RecordInterception(_ context.Context, _ *InterceptionRecord) error { +func (*AsyncRecorder) RecordInterception(context.Context, *InterceptionRecord) error { panic("RecordInterception must not be called asynchronously") } From d553061bb00ebc1bcb7b57e0850fea3590abcee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Banaszewski?= Date: Mon, 13 Apr 2026 11:40:42 +0000 Subject: [PATCH 2/2] review: leave old apidump file permissions --- intercept/apidump/apidump.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intercept/apidump/apidump.go b/intercept/apidump/apidump.go index 41fd70cd..aeb04d71 100644 --- a/intercept/apidump/apidump.go +++ b/intercept/apidump/apidump.go @@ -109,7 +109,7 @@ func (d *dumper) dumpRequest(req *http.Request) error { buf.Write(prettyBody) buf.WriteByte('\n') - return os.WriteFile(dumpPath, buf.Bytes(), 0o600) + return os.WriteFile(dumpPath, buf.Bytes(), 0o644) //nolint:gosec // https://github.com/coder/aibridge/pull/256#discussion_r3072143983 } func (d *dumper) dumpResponse(resp *http.Response) error { @@ -132,7 +132,7 @@ func (d *dumper) dumpResponse(resp *http.Response) error { if resp.Body == nil { // No body, just write headers - return os.WriteFile(dumpPath, headerBuf.Bytes(), 0o600) + return os.WriteFile(dumpPath, headerBuf.Bytes(), 0o644) //nolint:gosec // https://github.com/coder/aibridge/pull/256#discussion_r3072143983 } // Wrap the response body to capture it as it streams