Skip to content

Commit fcff723

Browse files
committed
Allow script mode to accept scripts that do not start with a shebang.
This prefixes scripts that do not start with a shebang with a default value of "/bin/sh". This matches the default entrypoint/shell for docker containers, and should help prevent an easy-to-make mistake.
1 parent 5af2878 commit fcff723

File tree

7 files changed

+63
-28
lines changed

7 files changed

+63
-28
lines changed

docs/tasks.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,11 @@ If this field is present, the step cannot specify `command`.
156156
When specified, a `script` gets invoked as if it were the contents of a file in
157157
the container. Any `args` are passed to the script file.
158158

159-
Scripts should start with a
160-
[shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) line to declare what
161-
tool should be used to interpret the script. That tool must then also be
162-
available within the step's container.
159+
Scripts that do not start with a shebang
160+
[shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) line will use a default
161+
value of `#!/bin/sh`, although users can override this by starting their script
162+
with a shebang to declare what tool should be used to interpret the script.
163+
That tool must then also be available within the step's container.
163164

164165
This allows you to execute a Bash script, if the image includes `bash`:
165166

examples/taskruns/step-script.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ spec:
1010
default: param-value
1111

1212
steps:
13+
- name: noshebang
14+
image: ubuntu
15+
script: |
16+
echo "no shebang"
1317
- name: bash
1418
image: ubuntu
1519
env:

pkg/apis/pipeline/v1alpha1/task_validation.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,6 @@ func validateSteps(steps []Step) *apis.FieldError {
138138
Paths: []string{"script"},
139139
}
140140
}
141-
if !strings.HasPrefix(strings.TrimSpace(s.Script), "#!") {
142-
return &apis.FieldError{
143-
Message: "script must start with a shebang (#!)",
144-
Paths: []string{"script"},
145-
}
146-
}
147141
}
148142

149143
if s.Name == "" {

pkg/apis/pipeline/v1alpha1/task_validation_test.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -631,20 +631,6 @@ func TestTaskSpecValidateError(t *testing.T) {
631631
Message: `multiple volumes with same name "workspace"`,
632632
Paths: []string{"volumes.name"},
633633
},
634-
}, {
635-
name: "step with script without shebang",
636-
fields: fields{
637-
Steps: []v1alpha1.Step{{
638-
Container: corev1.Container{
639-
Image: "my-image",
640-
},
641-
Script: "does not begin with shebang",
642-
}},
643-
},
644-
expectedError: apis.FieldError{
645-
Message: "script must start with a shebang (#!)",
646-
Paths: []string{"steps.script"},
647-
},
648634
}, {
649635
name: "step with script and command",
650636
fields: fields{

pkg/pod/pod_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ func TestMakePod(t *testing.T) {
435435
Name: "one",
436436
Image: "image",
437437
},
438-
Script: "echo hello from step one",
438+
Script: "#!/bin/sh\necho hello from step one",
439439
}, {
440440
Container: corev1.Container{
441441
Name: "two",
@@ -462,6 +462,7 @@ print("Hello from Python")`,
462462
Args: []string{"-c", `tmpfile="/tekton/scripts/script-0-mz4c7"
463463
touch ${tmpfile} && chmod +x ${tmpfile}
464464
cat > ${tmpfile} << 'script-heredoc-randomly-generated-mssqb'
465+
#!/bin/sh
465466
echo hello from step one
466467
script-heredoc-randomly-generated-mssqb
467468
tmpfile="/tekton/scripts/script-1-78c5n"

pkg/pod/script.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package pod
1919
import (
2020
"fmt"
2121
"path/filepath"
22+
"strings"
2223

2324
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
2425
"github.com/tektoncd/pipeline/pkg/names"
@@ -28,6 +29,7 @@ import (
2829
const (
2930
scriptsVolumeName = "scripts"
3031
scriptsDir = "/tekton/scripts"
32+
defaultShebang = "#!/bin/sh\n"
3133
)
3234

3335
var (
@@ -68,6 +70,25 @@ func convertScripts(shellImage string, steps []v1alpha1.Step) (*corev1.Container
6870
continue
6971
}
7072

73+
// Check for a shebang, and add a default if it's not set.
74+
// The shebang must be the first non-empty line.
75+
lines := strings.Split(s.Script, "\n")
76+
hasShebang := false
77+
for _, l := range lines {
78+
if strings.TrimSpace(l) == "" {
79+
continue
80+
}
81+
// This is the first non-empty line.
82+
if strings.HasPrefix(l, "#!") {
83+
hasShebang = true
84+
}
85+
break
86+
}
87+
script := s.Script
88+
if !hasShebang {
89+
script = defaultShebang + s.Script
90+
}
91+
7192
// At least one step uses a script, so we should return a
7293
// non-nil init container.
7394
placeScripts = true
@@ -88,7 +109,7 @@ touch ${tmpfile} && chmod +x ${tmpfile}
88109
cat > ${tmpfile} << '%s'
89110
%s
90111
%s
91-
`, tmpFile, heredoc, s.Script, heredoc)
112+
`, tmpFile, heredoc, script, heredoc)
92113

93114
// Set the command to execute the correct script in the mounted
94115
// volume.

pkg/pod/script_test.go

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,23 @@ func TestConvertScripts(t *testing.T) {
5656
}}
5757

5858
gotInit, got := convertScripts(images.ShellImage, []v1alpha1.Step{{
59-
Script: "script-1",
59+
Script: `#!/bin/sh
60+
script-1`,
6061
Container: corev1.Container{Image: "step-1"},
6162
}, {
6263
// No script to convert here.
6364
Container: corev1.Container{Image: "step-2"},
6465
}, {
65-
Script: "script-3",
66+
Script: `
67+
#!/bin/sh
68+
script-3`,
69+
Container: corev1.Container{
70+
Image: "step-3",
71+
VolumeMounts: preExistingVolumeMounts,
72+
Args: []string{"my", "args"},
73+
},
74+
}, {
75+
Script: `no-shebang`,
6676
Container: corev1.Container{
6777
Image: "step-3",
6878
VolumeMounts: preExistingVolumeMounts,
@@ -77,13 +87,22 @@ func TestConvertScripts(t *testing.T) {
7787
Args: []string{"-c", `tmpfile="/tekton/scripts/script-0-mz4c7"
7888
touch ${tmpfile} && chmod +x ${tmpfile}
7989
cat > ${tmpfile} << 'script-heredoc-randomly-generated-mssqb'
90+
#!/bin/sh
8091
script-1
8192
script-heredoc-randomly-generated-mssqb
8293
tmpfile="/tekton/scripts/script-2-78c5n"
8394
touch ${tmpfile} && chmod +x ${tmpfile}
8495
cat > ${tmpfile} << 'script-heredoc-randomly-generated-6nl7g'
96+
97+
#!/bin/sh
8598
script-3
8699
script-heredoc-randomly-generated-6nl7g
100+
tmpfile="/tekton/scripts/script-3-j2tds"
101+
touch ${tmpfile} && chmod +x ${tmpfile}
102+
cat > ${tmpfile} << 'script-heredoc-randomly-generated-vr6ds'
103+
#!/bin/sh
104+
no-shebang
105+
script-heredoc-randomly-generated-vr6ds
87106
`},
88107
VolumeMounts: []corev1.VolumeMount{scriptsVolumeMount},
89108
}
@@ -98,6 +117,15 @@ script-heredoc-randomly-generated-6nl7g
98117
Command: []string{"/tekton/scripts/script-2-78c5n"},
99118
Args: []string{"my", "args"},
100119
VolumeMounts: append(preExistingVolumeMounts, scriptsVolumeMount),
120+
}, {
121+
Image: "step-3",
122+
Command: []string{"/tekton/scripts/script-3-j2tds"},
123+
Args: []string{"my", "args"},
124+
VolumeMounts: []corev1.VolumeMount{
125+
{Name: "pre-existing-volume-mount", MountPath: "/mount/path"},
126+
{Name: "another-one", MountPath: "/another/one"},
127+
{Name: "scripts", MountPath: "/tekton/scripts"},
128+
},
101129
}}
102130
if d := cmp.Diff(wantInit, gotInit); d != "" {
103131
t.Errorf("Init Container Diff (-want, +got): %s", d)

0 commit comments

Comments
 (0)