@@ -2,7 +2,9 @@ package docker
22
33import (
44 "bytes"
5+ "compress/gzip"
56 "context"
7+ "encoding/base64"
68 "errors"
79 "fmt"
810 "io"
@@ -58,20 +60,22 @@ const (
5860 ExecutorStageCreatingServices common.ExecutorStage = "docker_creating_services"
5961 ExecutorStageCreatingUserVolumes common.ExecutorStage = "docker_creating_user_volumes"
6062 ExecutorStagePullingImage common.ExecutorStage = "docker_pulling_image"
61- )
6263
63- const ServiceLogOutputLimit = 64 * 1024
64+ ServiceLogOutputLimit = 64 * 1024
6465
65- const (
6666 labelServiceType = "service"
6767 labelWaitType = "wait"
68- )
6968
70- // internalFakeTunnelHostname is an internal hostname we provide the Docker client
71- // when we provide a tunnelled dialer implementation. Because we're overriding
72- // the dialer, this domain should never be used by the client, but we use the
73- // reserved TLD ".invalid" for safety.
74- const internalFakeTunnelHostname = "http://internal.tunnel.invalid"
69+ // internalFakeTunnelHostname is an internal hostname we provide the Docker client
70+ // when we provide a tunnelled dialer implementation. Because we're overriding
71+ // the dialer, this domain should never be used by the client, but we use the
72+ // reserved TLD ".invalid" for safety.
73+ internalFakeTunnelHostname = "http://internal.tunnel.invalid"
74+
75+ // runnerJobVarsNames is the name used to identify the all the job variables names.
76+ // It is used to allow step-runner to filter these variables once the gRPC service is started
77+ runnerJobVarsNames = "RUNNER_JOB_VAR_NAMES"
78+ )
7579
7680var neverRestartPolicy = container.RestartPolicy {Name : "no" }
7781
@@ -871,6 +875,11 @@ func (e *executor) createContainerConfig(
871875 cmd []string ,
872876) (* container.Config , error ) {
873877 labels := e .prepareContainerLabels (map [string ]string {"type" : containerType })
878+ jobVars , err := e .prepareContainerEnvVariables ()
879+ if err != nil {
880+ return nil , fmt .Errorf ("setting job variables: %w" , err )
881+ }
882+
874883 config := & container.Config {
875884 Image : image .ID ,
876885 Hostname : hostname ,
@@ -883,7 +892,7 @@ func (e *executor) createContainerConfig(
883892 OpenStdin : true ,
884893 StdinOnce : true ,
885894 Entrypoint : e .overwriteEntrypoint (& imageDefinition ),
886- Env : e . Build . GetAllVariables () .StringList (),
895+ Env : jobVars .StringList (),
887896 }
888897
889898 //nolint:nestif
@@ -913,6 +922,53 @@ func (e *executor) createContainerConfig(
913922 return config , nil
914923}
915924
925+ // prepareContainerEnvVariables prepares the environment variables for the build container.
926+ // When native steps are enabled, it compresses the list of job variable names and adds them
927+ // to the environment as RUNNER_JOB_VAR_NAMES. This allows step-runner to identify and filter
928+ // out job variables from the OS environment, preventing environment variable size limit issues.
929+ //
930+ // The variable names are gzip-compressed to minimize the size of the RUNNER_JOB_VAR_NAMES
931+ // environment variable itself, which is important on systems with strict environment limits
932+ // (particularly Windows).
933+ //
934+ // For non-native step builds, the function returns the variables unchanged since step-runner
935+ // filtering is not needed.
936+ func (e * executor ) prepareContainerEnvVariables () (spec.Variables , error ) {
937+ vars := e .Build .GetAllVariables ()
938+
939+ if ! e .Build .UseNativeSteps () {
940+ return vars , nil
941+ }
942+
943+ names := vars .GetAllVariableNames ()
944+ compressedVarNames , err := gzipString (names )
945+ if err != nil {
946+ return nil , fmt .Errorf ("job variables names compression failed: %w" , err )
947+ }
948+
949+ v := append ([]spec.Variable {}, vars ... )
950+ v = append (v , spec.Variable {
951+ Key : runnerJobVarsNames ,
952+ Value : compressedVarNames ,
953+ })
954+
955+ return v , nil
956+ }
957+
958+ // gzipString compresses a string and returns the compressed string.
959+ func gzipString (src string ) (string , error ) {
960+ var b bytes.Buffer
961+ gz := gzip .NewWriter (& b )
962+ if _ , err := gz .Write ([]byte (src )); err != nil {
963+ return "" , fmt .Errorf ("writing to gzip writer: %w" , err )
964+ }
965+ if err := gz .Close (); err != nil {
966+ return "" , fmt .Errorf ("closing gzip writer: %w" , err )
967+ }
968+
969+ return base64 .StdEncoding .EncodeToString (b .Bytes ()), nil
970+ }
971+
916972func (e * executor ) getBuildContainerUser (imageDefinition spec.Image ) (string , error ) {
917973 // runner config takes precedence
918974 user := e .Config .Docker .User
0 commit comments