Skip to content

Commit ee43ba7

Browse files
committed
fix: avoid deleting root filesystem when KANIKO_DIR not set
1 parent 5213a4f commit ee43ba7

File tree

3 files changed

+59
-2
lines changed

3 files changed

+59
-2
lines changed

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ $ vim .devcontainer/Dockerfile
4747

4848
Exit the container, and re-run the `docker run` command... after the build completes, `htop` should exist in the container! 🥳
4949

50+
> **Note:** Envbuilder performs destructive filesystem operations! To guard against accidental data
51+
> loss, it will refuse to run if it detects that KANIKO_DIR is not set to a specific value.
52+
> If you need to bypass this behaviour for any reason, you can bypass this safety check by setting
53+
> `FORCE_SAFE=true`.
54+
5055
### Git Branch Selection
5156

5257
Choose a branch using `GIT_URL` with a _ref/heads_ reference. For instance:

envbuilder.go

+18-2
Original file line numberDiff line numberDiff line change
@@ -427,8 +427,7 @@ func Run(ctx context.Context, options Options) error {
427427

428428
// It's possible that the container will already have files in it, and
429429
// we don't want to merge a new container with the old one.
430-
err = util.DeleteFilesystem()
431-
if err != nil {
430+
if err := maybeDeleteFilesystem(options.ForceSafe); err != nil {
432431
return nil, fmt.Errorf("delete filesystem: %w", err)
433432
}
434433

@@ -1063,3 +1062,20 @@ func findDevcontainerJSON(options Options) (string, string, error) {
10631062

10641063
return "", "", errors.New("can't find devcontainer.json, is it a correct spec?")
10651064
}
1065+
1066+
// maybeDeleteFilesystem wraps util.DeleteFilesystem with a guard to hopefully stop
1067+
// folks from unwittingly deleting their entire root directory.
1068+
func maybeDeleteFilesystem(force bool) error {
1069+
kanikoDir, ok := os.LookupEnv("KANIKO_DIR")
1070+
if !ok || strings.TrimSpace(kanikoDir) != MagicDir {
1071+
if force {
1072+
_, _ = fmt.Fprintf(os.Stderr, "WARNING! BYPASSING SAFETY CHECK! THIS WILL DELETE %s!\n", kanikoDir)
1073+
} else {
1074+
_, _ = fmt.Fprintf(os.Stderr, "KANIKO_DIR is not set to %s. Bailing!\n", MagicDir)
1075+
_, _ = fmt.Fprintln(os.Stderr, "To bypass this check, set FORCE_SAFE=true.")
1076+
return errors.New("safety check failed")
1077+
}
1078+
}
1079+
1080+
return util.DeleteFilesystem()
1081+
}

integration/integration_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,42 @@ const (
4444
testImageUbuntu = "localhost:5000/envbuilder-test-ubuntu:latest"
4545
)
4646

47+
func TestForceSafe(t *testing.T) {
48+
t.Parallel()
49+
50+
t.Run("Safe", func(t *testing.T) {
51+
t.Parallel()
52+
srv := createGitServer(t, gitServerOptions{
53+
files: map[string]string{
54+
"Dockerfile": "FROM " + testImageAlpine,
55+
},
56+
})
57+
_, err := runEnvbuilder(t, options{env: []string{
58+
"GIT_URL=" + srv.URL,
59+
"KANIKO_DIR=/not/envbuilder",
60+
"DOCKERFILE_PATH=Dockerfile",
61+
}})
62+
require.ErrorContains(t, err, "delete filesystem: safety check failed")
63+
})
64+
65+
// Careful with this one!
66+
t.Run("Unsafe", func(t *testing.T) {
67+
t.Parallel()
68+
srv := createGitServer(t, gitServerOptions{
69+
files: map[string]string{
70+
"Dockerfile": "FROM " + testImageAlpine,
71+
},
72+
})
73+
_, err := runEnvbuilder(t, options{env: []string{
74+
"GIT_URL=" + srv.URL,
75+
"KANIKO_DIR=/not/envbuilder",
76+
"FORCE_SAFE=true",
77+
"DOCKERFILE_PATH=Dockerfile",
78+
}})
79+
require.NoError(t, err)
80+
})
81+
}
82+
4783
func TestFailsGitAuth(t *testing.T) {
4884
t.Parallel()
4985
srv := createGitServer(t, gitServerOptions{

0 commit comments

Comments
 (0)