mirror of
https://gitea.com/gitea/act_runner.git
synced 2026-11-02 13:27:16 +08:00
fix: recognize Gitea's 401 reply for an unregistered runner (#1287)
Since https://github.com/go-gitea/gitea/pull/39578 (backported to v28), Gitea answers an unregistered runner with a Connect `Unauthenticated` error instead of a gRPC status wrapped as `Unknown`. `IsRegistrationRejected` missed it, so an ephemeral runner kept its spent registration file and failed on every restart. This also fails the `gitea/gitea:main-nightly` e2e job. Match on the `unregistered runner` message suffix, which both shapes share. The code can't distinguish Gitea from a proxy, because a proxy's 401 with a JSON body also decodes as a wire `Unauthenticated` error. Written by Claude Code. Reviewed-on: https://gitea.com/gitea/runner/pulls/1287 Reviewed-by: bircni <bircni@icloud.com> Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
@@ -128,6 +128,7 @@ func TestDaemonRemovesOnlyConsumedEphemeralRegistration(t *testing.T) {
|
||||
{"ephemeral interrupted before task", true, true, nil, nil, false},
|
||||
{"persistent once", false, false, nil, nil, false},
|
||||
{"ephemeral rejected on fetch", true, false, nil, errUnregisteredRunner, true},
|
||||
{"ephemeral rejected on fetch with 401", true, false, nil, connect.NewError(connect.CodeUnauthenticated, errors.New("unregistered runner")), true},
|
||||
{"ephemeral proxy 401 on fetch", true, false, nil, connect.NewError(connect.CodeUnauthenticated, errors.New("HTTP status 401 Unauthorized")), false},
|
||||
{"ephemeral rejected on declare", true, false, errUnregisteredRunner, nil, true},
|
||||
{"persistent rejected on declare", false, false, errUnregisteredRunner, nil, false},
|
||||
|
||||
@@ -110,8 +110,8 @@ func TestPoller_FetchUnauthenticatedStopsPolling(t *testing.T) {
|
||||
fetchErr error
|
||||
rejected bool
|
||||
}{
|
||||
"connect": {connect_go.NewError(connect_go.CodeUnauthenticated, errors.New("unregistered runner")), false},
|
||||
"gitea": {connect_go.NewWireError(connect_go.CodeUnknown, errors.New("rpc error: code = Unauthenticated desc = unregistered runner")), true},
|
||||
"proxy": {connect_go.NewError(connect_go.CodeUnauthenticated, errors.New("401 Unauthorized")), false},
|
||||
"gitea": {connect_go.NewWireError(connect_go.CodeUnknown, errors.New("rpc error: code = Unauthenticated desc = unregistered runner")), true},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
client := mocks.NewClient(t)
|
||||
|
||||
@@ -6,6 +6,7 @@ package client
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"gitea.dev/actionslib/runner/v1"
|
||||
@@ -20,9 +21,8 @@ type Client interface {
|
||||
UpdateTask(context.Context, *connect.Request[runnerv1.UpdateTaskRequest]) (*connect.Response[runnerv1.UpdateTaskResponse], error)
|
||||
}
|
||||
|
||||
// IsRegistrationRejected reports whether Gitea itself answered "unregistered runner", unlike a proxy's bare 401.
|
||||
// IsRegistrationRejected reports whether Gitea itself answered "unregistered runner", unlike a proxy's 401.
|
||||
func IsRegistrationRejected(err error) bool {
|
||||
var connectErr *connect.Error
|
||||
return errors.As(err, &connectErr) && connectErr.Code() == connect.CodeUnknown && connect.IsWireError(err) &&
|
||||
connectErr.Message() == "rpc error: code = Unauthenticated desc = unregistered runner"
|
||||
return errors.As(err, &connectErr) && strings.HasSuffix(connectErr.Message(), "unregistered runner")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user