Preserve authentication cancellation at the response limit

This commit is contained in:
2026-11-05 15:58:32 +00:00
parent beb18cc9d6
commit ff57dbf8b3
3 changed files with 48 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ package promptkit_test
import (
"context"
"encoding/json"
"errors"
"io"
"net/http"
"reflect"
@@ -13,6 +14,45 @@ import (
"go.maximumdirect.net/promptkit"
)
type cancelingAuthenticationBody struct {
remaining int
cancel context.CancelFunc
closed bool
}
func (b *cancelingAuthenticationBody) Read(p []byte) (int, error) {
n := min(len(p), b.remaining)
for i := range p[:n] {
p[i] = 'x'
}
b.remaining -= n
if b.remaining == 0 {
b.cancel()
return n, context.Canceled
}
return n, nil
}
func (b *cancelingAuthenticationBody) Close() error { b.closed = true; return nil }
func TestAuthenticationReadCancellationWinsOverOverflow(t *testing.T) {
for _, size := range []int{1024, (1 << 20) + 1} {
ctx, cancel := context.WithCancel(context.Background())
body := &cancelingAuthenticationBody{remaining: size, cancel: cancel}
engine, err := promptkit.NewEngine(promptkit.Config{HTTPClient: &http.Client{Transport: roundTripFunc(func(*http.Request) (*http.Response, error) {
return &http.Response{StatusCode: 200, Header: make(http.Header), Body: body}, nil
})}})
if err != nil {
cancel()
t.Fatal(err)
}
report, err := engine.SmokeTest(ctx, promptkit.SmokeTestRequest{Kind: promptkit.SmokeTestAuthentication, BackendID: "openrouter"})
cancel()
if !errors.Is(err, context.Canceled) || report == nil || report.Completed || report.Failure != promptkit.ExecutionFailureCanceled || report.Facts.CredentialsAccepted != nil || report.Facts.ResponseReceived == nil || !*report.Facts.ResponseReceived || !body.closed {
t.Fatalf("size %d: report=%+v error=%v closed=%v", size, report, err, body.closed)
}
}
}
func TestBundledSmokeHTTPDefaults(t *testing.T) {
t.Setenv("OPENROUTER_API_KEY", "synthetic-key")
var urls []string

View File

@@ -27,7 +27,11 @@ contracts.
### 1. Preserve Caller Cancellation When Authentication Also Overflows [P2]
**Status:** Open. **Stages:** 7, 21–22.
**Status:** Complete. **Stages:** 7, 21–22.
Completion: interrupted body reads preserve caller cancellation before overflow
classification. Public below-limit and overflow-boundary regressions retain HTTP
facts, unknown acceptance, incomplete cancellation reports, and body closure.
**Locations:** [authentication adapter](../../internal/llm/openrouter_authentication.go),
`ProbeOpenRouterKey`, lines 61–67;

View File

@@ -59,6 +59,9 @@ func (c *OpenAICompatibleClient) ProbeOpenRouterKey(ctx context.Context, endpoin
return result, nil
}
contents, err := io.ReadAll(io.LimitReader(response.Body, maxAuthenticationResponseBytes+1))
if err != nil && ctx.Err() != nil {
return result, ctx.Err()
}
if len(contents) > maxAuthenticationResponseBytes {
result.Overflow = true
return result, nil