File size: 2,355 Bytes
d61821a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | diff --git a/common/build.go b/common/build.go
index 1d79b330..fd7ae93f 100644
--- a/common/build.go
+++ b/common/build.go
@@ -529,6 +529,15 @@ func wrapStepStageErr(err error) error {
berr := &BuildError{Inner: err}
+ // Classify step-runner internal failures (gRPC handler panics and
+ // ErrorInternal job statuses) as ScriptFailure rather than
+ // RunnerSystemFailure: a malicious job could deliberately trigger either
+ // path to forge a RunnerSystemFailure and evade job-failure accounting.
+ var cierr *steps.ClientInternalError
+ if errors.As(err, &cierr) {
+ berr.FailureReason = ScriptFailure
+ }
+
var cserr *steps.ClientStatusError
if errors.As(err, &cserr) {
switch cserr.Status.ErrorKind {
diff --git a/steps/execute.go b/steps/execute.go
index 63837242..76e564e4 100644
--- a/steps/execute.go
+++ b/steps/execute.go
@@ -9,7 +9,9 @@ import (
"time"
"google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials/insecure"
+ grpcstatus "google.golang.org/grpc/status"
"gitlab.com/gitlab-org/gitlab-runner/common/spec"
"gitlab.com/gitlab-org/step-runner/pkg/api/client"
@@ -50,6 +52,17 @@ func (cserr *ClientStatusError) Unwrap() error {
return cserr.Err
}
+// ClientInternalError signals a step-runner client failure that is not tied
+// to a job Status — specifically, a gRPC handler panic surfacing as
+// codes.Internal via step-runner's panic-recovery interceptor. Distinct from
+// ClientStatusError, which reports a Status returned by step-runner.
+type ClientInternalError struct {
+ Err error
+}
+
+func (e *ClientInternalError) Error() string { return e.Err.Error() }
+func (e *ClientInternalError) Unwrap() error { return e.Err }
+
func Execute(ctx context.Context, connector Connector, jobInfo JobInfo, steps []schema.Step, trace io.Writer) error {
dialFn, err := connector.Connect(ctx)
if err != nil {
@@ -73,7 +86,11 @@ func Execute(ctx context.Context, connector Connector, jobInfo JobInfo, steps []
status, err := c.RunAndFollow(ctx, request, &out)
if err != nil {
- return fmt.Errorf("executing steps request: %w", err)
+ wrapped := fmt.Errorf("executing steps request: %w", err)
+ if grpcstatus.Code(err) == codes.Internal {
+ return &ClientInternalError{Err: wrapped}
+ }
+ return wrapped
}
if status.State == client.StateSuccess {
|