Skip to content

Commit aa531c4

Browse files
authored
Escape variables in image entrypoints (#1573)
Signed-off-by: Jonathan GAYVALLET <[email protected]>
1 parent 9857a47 commit aa531c4

File tree

4 files changed

+36
-14
lines changed

4 files changed

+36
-14
lines changed

src/job.ts

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -911,19 +911,15 @@ export class Job {
911911
}
912912

913913
if (this.imageEntrypoint) {
914-
if (this.imageEntrypoint[0] == "") {
915-
dockerCmd += "--entrypoint '' ";
916-
} else {
917-
dockerCmd += `--entrypoint ${this.imageEntrypoint[0]} `;
918-
}
914+
dockerCmd += `--entrypoint ${Utils.safeBashString(this.imageEntrypoint[0])} `;
919915
}
920916

921917
dockerCmd += `${(await this.mountCacheCmd(writeStreams, expanded)).join(" ")} `;
922918
dockerCmd += `${imageName} `;
923919

924920
if (this.imageEntrypoint?.length ?? 0 > 1) {
925921
this.imageEntrypoint?.slice(1).forEach((e) => {
926-
dockerCmd += `"${e}" `;
922+
dockerCmd += `${Utils.safeBashString(e)} `;
927923
});
928924
}
929925

@@ -1446,11 +1442,7 @@ export class Job {
14461442

14471443
const serviceEntrypoint = service.entrypoint;
14481444
if (serviceEntrypoint) {
1449-
if (serviceEntrypoint[0] == "") {
1450-
dockerCmd += "--entrypoint '' ";
1451-
} else {
1452-
dockerCmd += `--entrypoint ${serviceEntrypoint[0]} `;
1453-
}
1445+
dockerCmd += `--entrypoint ${Utils.safeBashString(serviceEntrypoint[0])} `;
14541446
}
14551447
dockerCmd += `--volume ${this.buildVolumeName}:${this.ciProjectDir} `;
14561448
dockerCmd += `--volume ${this.tmpVolumeName}:${this.fileVariablesDir} `;
@@ -1469,9 +1461,7 @@ export class Job {
14691461

14701462
if (serviceEntrypoint?.length ?? 0 > 1) {
14711463
serviceEntrypoint?.slice(1).forEach((e) => {
1472-
dockerCmd += `'${e
1473-
.replace(/'/g, "'\"'\"'") // replaces `'` with `'"'"'`
1474-
}' `;
1464+
dockerCmd += `${Utils.safeBashString(e)} `;
14751465
});
14761466
}
14771467
(service.command ?? []).forEach((e) => dockerCmd += `"${e.replace(/\$/g, "\\$")}" `);

src/utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ export class Utils {
5353
});
5454
}
5555

56+
static safeBashString (s: string) {
57+
return `'${s.replace(/'/g, "'\"'\"'")}'`; // replaces `'` with `'"'"'`
58+
}
59+
5660
static forEachRealJob (gitlabData: any, callback: (jobName: string, jobData: any) => void) {
5761
for (const [jobName, jobData] of Object.entries<any>(gitlabData)) {
5862
if (Job.illegalJobNames.has(jobName) || jobName[0].startsWith(".")) {

tests/test-cases/image/.gitlab-ci.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,17 @@ image-user:
6363
user: nobody
6464
script:
6565
- id -u
66+
67+
image-entrypoint-with-variables:
68+
variables:
69+
FOO: BAR
70+
image:
71+
name: alpine
72+
entrypoint:
73+
- sh
74+
- -c
75+
- |
76+
if [ -z "$FOO" ]; then >&2 echo FOO is not defined in entrypoint; exit 1; fi
77+
sh "$@"
78+
script:
79+
- echo "success"

tests/test-cases/image/integration.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,17 @@ test.concurrent("pull invalid image", async () => {
135135

136136
await cleanupJobResources(jobs);
137137
});
138+
139+
test.concurrent("no variable substitution in entrpoint", async () => {
140+
const writeStreams = new WriteStreamsMock();
141+
142+
await handler({
143+
cwd: "tests/test-cases/image",
144+
job: ["image-entrypoint-with-variables"],
145+
}, writeStreams);
146+
147+
const expected = [
148+
chalk`{blueBright image-entrypoint-with-variables} {greenBright >} success`,
149+
];
150+
expect(writeStreams.stdoutLines).toEqual(expect.arrayContaining(expected));
151+
});

0 commit comments

Comments
 (0)