fix(transport): keep harmless query values visible in --debug output

--debug replaced every query value with REDACTED, so it could not show which
filters were sent. Redact only parameters that can authenticate a request
(tokens, passwords, secrets, signatures, storage credentials, OAuth codes and
the OAuth state), and log the sanitized server message of failed responses.

A 404 now names the request instead of blaming the instance, and API errors
recorded from a request keep its instance and credential so a caller can look
up why it failed. Network failures keep the server they could not reach.

Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
bircni committed 2026-10-11 22:48:49 +02:00
1 parent 62962b4f70
commit 0254c0509e
7 files changed
+225 -17

No files matched your search

+12 -3
View File
@@ -5,6 +5,7 @@ package services
import (
"context"
"errors"
"net"
"net/http"
"net/http/httptest"
@@ -32,6 +33,14 @@ func TestSDKCallsAuthenticateWithoutVersionProbe(t *testing.T) {
require.True(t, renamed)
}
// requireAPIError checks the request and server message an *transport.APIError reports.
func requireAPIError(t *testing.T, want transport.APIError, err error) {
t.Helper()
got, ok := errors.AsType[*transport.APIError](err)
require.True(t, ok, "%v is not an API error", err)
require.Equal(t, want, transport.APIError{Status: got.Status, Method: got.Method, Endpoint: got.Endpoint, Message: got.Message})
}
func TestSDKErrorsMapToAPIErrors(t *testing.T) {
for _, tc := range []struct {
name, body, message string
@@ -50,7 +59,7 @@ func TestSDKErrorsMapToAPIErrors(t *testing.T) {
err := do(context.Background(), client, func(ctx context.Context, c *gitea.Client) (*gitea.Response, error) {
return c.Repositories.DeleteRepo(ctx, "alice", "project")
})
require.Equal(t, &transport.APIError{Status: tc.status, Method: http.MethodDelete, Endpoint: "/api/v1/repos/alice/project", Message: tc.message}, err)
requireAPIError(t, transport.APIError{Status: tc.status, Method: http.MethodDelete, Endpoint: "/api/v1/repos/alice/project", Message: tc.message}, err)
require.NotContains(t, err.Error(), "secret")
})
}
@@ -65,7 +74,7 @@ func TestSDKStatusOnlyFailureKeepsServerMessage(t *testing.T) {
return c.Repositories.RenameRepoBranch(ctx, "alice", "project", "main", gitea.RenameRepoBranchOption{Name: "trunk"})
})
require.False(t, renamed)
require.Equal(t, &transport.APIError{Status: http.StatusUnprocessableEntity, Method: http.MethodPatch, Endpoint: "/api/v1/repos/alice/project/branches/main", Message: "branch trunk already exists"}, err)
requireAPIError(t, transport.APIError{Status: http.StatusUnprocessableEntity, Method: http.MethodPatch, Endpoint: "/api/v1/repos/alice/project/branches/main", Message: "branch trunk already exists"}, err)
require.EqualError(t, err, "Gitea API returned HTTP 422 for PATCH /api/v1/repos/alice/project/branches/main: branch trunk already exists")
}
@@ -78,7 +87,7 @@ func TestSDKFailureWithoutResponseKeepsCapturedError(t *testing.T) {
_, _, err := c.Repositories.GetRepo(ctx, "alice", "project")
return nil, nil, err
})
require.Equal(t, &transport.APIError{Status: http.StatusNotFound, Method: http.MethodGet, Endpoint: "/api/v1/repos/alice/project", Message: "repository does not exist"}, err)
requireAPIError(t, transport.APIError{Status: http.StatusNotFound, Method: http.MethodGet, Endpoint: "/api/v1/repos/alice/project", Message: "repository does not exist"}, err)
}
func TestSDKInvalidJSONIsReportedWithoutBody(t *testing.T) {