| |
| |
| |
| |
| @@ -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" |
| |
| new file mode 100644 |
| |
| |
| |
| @@ -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) |
| +} |
| |
| |
| |
| |
| @@ -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 |
|
|