From 90a8db890413b28783b339ba55e081ca59a9f45f Mon Sep 17 00:00:00 2001 From: Kamal Nasser Date: Wed, 3 Mar 2021 01:08:22 +0200 Subject: [PATCH] restrict the scope of HOME to the shimmed buildpack --- bin/build | 18 ++++- build_test.go | 85 +++++++++++++++++++++++ exports_test.go | 3 + test/fixtures/build/app/package.json | 1 + test/fixtures/build/buildpack/bin/compile | 19 +++++ 5 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 build_test.go create mode 100644 test/fixtures/build/app/package.json create mode 100755 test/fixtures/build/buildpack/bin/compile diff --git a/bin/build b/bin/build index a74327d..97108f4 100755 --- a/bin/build +++ b/bin/build @@ -35,10 +35,22 @@ if [[ -d .profile.d ]]; then profile_dir="${layers_dir}/profile" mkdir -p "${profile_dir}/profile.d" - cp .profile.d/* "${profile_dir}/profile.d/" + for script in .profile.d/*; do + dest="${profile_dir}/profile.d/$(basename "$script")" - mkdir -p "${profile_dir}/env.launch" - echo -n "$app_dir" >"${profile_dir}/env.launch/HOME.override" + # wrap each script and set $HOME to + cat <<'EOF' >"$dest" +__cnb_shim__HOME=$HOME +HOME=$(pwd) + +EOF + cat "$script" >>"$dest" + cat <<'EOF' >>"$dest" + +HOME=$__cnb_shim__HOME +unset __cnb_shim__HOME +EOF + done echo "launch = true" >"${profile_dir}.toml" fi diff --git a/build_test.go b/build_test.go new file mode 100644 index 0000000..052afc8 --- /dev/null +++ b/build_test.go @@ -0,0 +1,85 @@ +package cnbshim_test + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "os/exec" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestBuild(t *testing.T) { + tmp, err := ioutil.TempDir("", "build") + require.NoError(t, err) + t.Cleanup(func() { + _ = os.RemoveAll(tmp) + }) + + // set up test env + require.NoError(t, os.MkdirAll(tmp+"/layers", 0755)) + require.NoError(t, os.MkdirAll(tmp+"/platform", 0755)) + require.NoError(t, os.MkdirAll(tmp+"/buildpack/target", 0755)) + require.NoError(t, os.MkdirAll(tmp+"/buildpack/bin", 0755)) + + require.NoError(t, exec.Command("cp", "-r", "test/fixtures/build/app", tmp+"/").Run()) + require.NoError(t, exec.Command("cp", "-r", "test/fixtures/build/buildpack/.", tmp+"/buildpack/target/").Run()) + require.NoError(t, exec.Command("cp", "bin/build", tmp+"/buildpack/bin/").Run()) + // add fake exports and release binaries + require.NoError(t, ioutil.WriteFile(tmp+"/buildpack/bin/exports", nil, 0755)) + require.NoError(t, ioutil.WriteFile(tmp+"/buildpack/bin/release", nil, 0755)) + + // run bin/build + var out bytes.Buffer + cmd := exec.Command(tmp+"/buildpack/bin/build", tmp+"/layers", tmp+"/platform") + cmd.Dir = tmp + "/app" + cmd.Env = append(os.Environ(), "CNB_STACK_ID=heroku-20") + cmd.Stdout = &out + cmd.Stderr = &out + err = cmd.Run() + if _, ok := err.(*exec.ExitError); err != nil && ok { + t.Logf("bin/build output:\n%s", out.String()) + } + require.NoError(t, err) + + contains := []string{ + "got STACK=heroku-20", + fmt.Sprintf("got arg 0=%s/app", tmp), + fmt.Sprintf("got arg 1=%s/layers/shim", tmp), + fmt.Sprintf("got arg 2=%s/platform/env", tmp), + } + for _, c := range contains { + assert.Contains(t, out.String(), c) + } + + files := []string{ + "/layers/profile.toml", + "/layers/profile/env.build", + "/layers/profile/profile.d/1.sh", + } + for _, f := range files { + _, err := os.Stat(tmp + f) + assert.NoError(t, err, f) + } + + out = bytes.Buffer{} + cmd = exec.Command("bash", "-c", fmt.Sprintf(` +echo +echo "before HOME=$HOME" +source "%s" +echo "after HOME=$HOME" +`, tmp+"/layers/profile/profile.d/1.sh")) + cmd.Dir = tmp + "/app" + cmd.Env = []string{"HOME=/home/app"} + cmd.Stdout = &out + cmd.Stderr = &out + require.NoError(t, cmd.Run()) + assert.Equal(t, fmt.Sprintf(` +before HOME=/home/app +buildpack HOME=%s +after HOME=/home/app +`, tmp+"/app"), out.String()) +} diff --git a/exports_test.go b/exports_test.go index 30fff89..456397b 100644 --- a/exports_test.go +++ b/exports_test.go @@ -50,6 +50,9 @@ func TestExports(t *testing.T) { t.Run(tc.name, func(t *testing.T) { tmp, err := ioutil.TempDir("", "exports") require.NoError(t, err) + t.Cleanup(func() { + _ = os.RemoveAll(tmp) + }) cmd := exec.Command("bin/exports", fmt.Sprintf("test/fixtures/%s/export", tc.name), ".", tmp) cmd.Stdout = os.Stdout diff --git a/test/fixtures/build/app/package.json b/test/fixtures/build/app/package.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/test/fixtures/build/app/package.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/test/fixtures/build/buildpack/bin/compile b/test/fixtures/build/buildpack/bin/compile new file mode 100755 index 0000000..7fc89a9 --- /dev/null +++ b/test/fixtures/build/buildpack/bin/compile @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail + +i=0 +for var in "$@"; do + echo "got arg ${i}=${var}" + i=$((i + 1)) +done + +echo "got STACK=$STACK" + +mkdir .profile.d +echo 'echo "buildpack HOME=$HOME"' >.profile.d/1.sh + +BIN_DIR=$( + cd "$(dirname "$0")" + pwd +) # absolute path +touch "${BIN_DIR}/../export"