| @@ -115,8 +115,14 @@ func (r *runner) runStepsPodman(j job, dir string, env []string, sink io.Writer, |
| 115 | // file outside the workspace holds them instead — outside because the |
115 | // file outside the workspace holds them instead — outside because the |
| 116 | // workspace is bind mounted, and a file of secrets sitting in the |
116 | // workspace is bind mounted, and a file of secrets sitting in the |
| 117 | // checkout is one `cat` from a build's own log. |
117 | // checkout is one `cat` from a build's own log. |
| |
118 | // |
| |
119 | // A value with a newline in it — a private key — cannot go in the |
| |
120 | // file, which has no escape for one. Those are named on the command |
| |
121 | // line with --env NAME and valued in the podman process's own |
| |
122 | // environment, which podman copies into the container. |
| |
123 | fileEnv, inherit := splitEnv(env) |
| 118 | envFile := filepath.Join(r.workdir, fmt.Sprintf("env-%d", j.ID)) |
124 | envFile := filepath.Join(r.workdir, fmt.Sprintf("env-%d", j.ID)) |
| 119 | if err := writeEnvFile(envFile, env); err != nil { |
125 | if err := writeEnvFile(envFile, fileEnv); err != nil { |
| 120 | fmt.Fprintf(sink, "preparing the build environment: %v\n", err) |
126 | fmt.Fprintf(sink, "preparing the build environment: %v\n", err) |
| 121 | return false |
127 | return false |
| 122 | } |
128 | } |
| @@ -144,7 +150,9 @@ func (r *runner) runStepsPodman(j job, dir string, env []string, sink io.Writer, |
| 144 | args := append(r.podmanGlobal(), "run", "--detach", "--rm", "--pull=never", "--cgroups=disabled") |
150 | args := append(r.podmanGlobal(), "run", "--detach", "--rm", "--pull=never", "--cgroups=disabled") |
| 145 | args = append(args, |
151 | args = append(args, |
| 146 | "--name", name, |
152 | "--name", name, |
| 147 | "--env-file", envFile, |
153 | "--env-file", envFile) |
| |
154 | args = append(args, inheritArgs(inherit)...) |
| |
155 | args = append(args, |
| 148 | "--volume", dir+":/workspace:rw", |
156 | "--volume", dir+":/workspace:rw", |
| 149 | // The build home holds the tool caches (Go modules, the sonar |
157 | // The build home holds the tool caches (Go modules, the sonar |
| 150 | // scanner) that must outlive a build; HOME in env points at it. |
158 | // scanner) that must outlive a build; HOME in env points at it. |
| @@ -156,7 +164,7 @@ func (r *runner) runStepsPodman(j job, dir string, env []string, sink io.Writer, |
| 156 | "--entrypoint", "sh", |
164 | "--entrypoint", "sh", |
| 157 | image, "-c", "sleep infinity") |
165 | image, "-c", "sleep infinity") |
| 158 | start := exec.Command(podman, args...) |
166 | start := exec.Command(podman, args...) |
| 159 | start.Env = []string{"PATH=" + os.Getenv("PATH"), "HOME=" + r.podmanHome()} |
167 | start.Env = append([]string{"PATH=" + os.Getenv("PATH"), "HOME=" + r.podmanHome()}, inherit...) |
| 160 | intoCgroup(start, cgroupFD) |
168 | intoCgroup(start, cgroupFD) |
| 161 | if out, err := start.CombinedOutput(); err != nil { |
169 | if out, err := start.CombinedOutput(); err != nil { |
| 162 | // A missing image lands here, and it is the common case worth |
170 | // A missing image lands here, and it is the common case worth |
| @@ -226,6 +234,31 @@ func (r *runner) podmanHome() string { |
| 226 | return "/var/lib/gitbay-runner" |
234 | return "/var/lib/gitbay-runner" |
| 227 | } |
235 | } |
| 228 | |
236 | |
| |
237 | // splitEnv separates the entries an env file can carry from those whose |
| |
238 | // value holds a newline, which podman must inherit from its environment. |
| |
239 | func splitEnv(env []string) (file, inherit []string) { |
| |
240 | for _, e := range env { |
| |
241 | if strings.ContainsAny(e, "\n\r") { |
| |
242 | inherit = append(inherit, e) |
| |
243 | } else { |
| |
244 | file = append(file, e) |
| |
245 | } |
| |
246 | } |
| |
247 | return file, inherit |
| |
248 | } |
| |
249 | |
| |
250 | // inheritArgs names each inherited variable for podman run: --env NAME |
| |
251 | // with no value makes podman take it from its own environment, so the |
| |
252 | // value never appears on a command line. |
| |
253 | func inheritArgs(inherit []string) []string { |
| |
254 | var args []string |
| |
255 | for _, e := range inherit { |
| |
256 | name, _, _ := strings.Cut(e, "=") |
| |
257 | args = append(args, "--env", name) |
| |
258 | } |
| |
259 | return args |
| |
260 | } |
| |
261 | |
| 229 | // writeEnvFile writes KEY=VALUE lines for podman --env-file, readable |
262 | // writeEnvFile writes KEY=VALUE lines for podman --env-file, readable |
| 230 | // only by this user. Values containing a newline are refused rather than |
263 | // only by this user. Values containing a newline are refused rather than |
| 231 | // silently truncated: the format has no escape for one, and a secret that |
264 | // silently truncated: the format has no escape for one, and a secret that |