File size: 3,368 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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | diff --git a/apps/gitlab-runner-helper/main.go b/apps/gitlab-runner-helper/main.go
index 206fcf20..e469fbb6 100644
--- a/apps/gitlab-runner-helper/main.go
+++ b/apps/gitlab-runner-helper/main.go
@@ -29,6 +29,9 @@ func main() {
}
}()
+ // Must run before cli.NewApp. See commands/steps.RecoverArgv.
+ steps.RecoverArgv()
+
app := cli.NewApp()
app.Name = filepath.Base(os.Args[0])
app.Usage = "a GitLab Runner Helper"
diff --git a/commands/steps/recovery.go b/commands/steps/recovery.go
new file mode 100644
index 00000000..0d0d2d04
--- /dev/null
+++ b/commands/steps/recovery.go
@@ -0,0 +1,49 @@
+package steps
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "os"
+)
+
+// RecoveryEnvVar carries argv (base64-encoded JSON) for the helper to
+// reconstruct when an image entrypoint drops CMD. Set by the executor on
+// the build container; read and unset by RecoverArgv.
+const RecoveryEnvVar = "_GITLAB_RUNNER_HELPER_NATIVE_STEPS_ARGV"
+
+// EncodeRecoveryArgv returns the RecoveryEnvVar payload for argv.
+func EncodeRecoveryArgv(argv []string) (string, error) {
+ raw, err := json.Marshal(argv)
+ if err != nil {
+ return "", fmt.Errorf("marshalling argv: %w", err)
+ }
+ return base64.StdEncoding.EncodeToString(raw), nil
+}
+
+// RecoverArgv reconstructs os.Args from RecoveryEnvVar when the helper was
+// invoked with no subcommand, the fingerprint of an `sh -c` entrypoint
+// dropping CMD[1:] as positional params that exec doesn't forward. Call
+// from main before any arg processing. No-op otherwise.
+func RecoverArgv() {
+ if len(os.Args) > 1 {
+ return
+ }
+ encoded := os.Getenv(RecoveryEnvVar)
+ if encoded == "" {
+ return
+ }
+ raw, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return
+ }
+ var argv []string
+ if err := json.Unmarshal(raw, &argv); err != nil {
+ return
+ }
+ if len(argv) == 0 {
+ return
+ }
+ os.Args = append(os.Args, argv...)
+ _ = os.Unsetenv(RecoveryEnvVar)
+}
diff --git a/executors/docker/docker.go b/executors/docker/docker.go
index a3997d28..05b871f5 100644
--- a/executors/docker/docker.go
+++ b/executors/docker/docker.go
@@ -30,6 +30,7 @@ import (
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/sirupsen/logrus"
+ "gitlab.com/gitlab-org/gitlab-runner/commands/steps"
"gitlab.com/gitlab-org/gitlab-runner/common"
"gitlab.com/gitlab-org/gitlab-runner/common/buildlogger"
"gitlab.com/gitlab-org/gitlab-runner/common/spec"
@@ -942,9 +943,16 @@ func (e *executor) createContainerConfig(
if e.Build.UseNativeSteps() {
config.Cmd = append([]string{bootstrappedBinary, "steps", "serve"}, config.Cmd...)
- // Environment variables interferes with steps. Given this situation, when
- // native steps are enabled, we no longer add the env vars to the container.
- config.Env = nil
+ // Recovery for `sh -c` entrypoints that drop CMD[1:] as positional
+ // params exec doesn't forward. See commands/steps.RecoveryEnvVar.
+ recoveryArgv, err := steps.EncodeRecoveryArgv(config.Cmd[1:])
+ if err != nil {
+ return nil, fmt.Errorf("encoding native-steps recovery argv: %w", err)
+ }
+
+ // Job env vars are delivered by step-runner; the recovery var is
+ // the only one we set here.
+ config.Env = []string{steps.RecoveryEnvVar + "=" + recoveryArgv}
}
// user config should only be set in build containers
|