diff --git a/README.md b/README.md index e02c0d1..9c99dfe 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ | Feature | Description | Install method | Version | | ------- | ----------- | -------------- | ------- | -| [add-script](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/add-script) | Add a script from a URL or inline text to /usr/local/bin during devcontainer build | custom | 1.0.0 | +| [add-script](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/add-script) | Add a script from a URL or inline text to /usr/local/bin during devcontainer build | custom | 1.1.0 | | [alexpasmantier/television](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/alexpasmantier-television) | `tv` — fuzzy finder for files, text, and more | gh release | 1.0.1 | | [ankitpokhrel/jira-cli](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/ankitpokhrel-jira-cli) | `jira` — feature-rich interactive Jira command line client | gh release | 1.0.0 | | [apt-build-essential](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/apt-build-essential) | `gcc`/`g++`/`make` — C/C++ compiler toolchain via the build-essential package | apt | 1.0.0 | @@ -78,7 +78,7 @@ | [rclone](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/rclone.org) | `rclone` — sync files to/from cloud storage | gh release | 1.0.1 | | [restic.net](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/restic.net) | `restic` — fast, encrypted, deduplicated backups | gh release | 1.0.1 | | [ripgrep](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/ripgrep) | `rg` — fast grep alternative (ripgrep) | gh release | 1.0.1 | -| [run-script](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/run-script) | Run a script from a URL or inline text during devcontainer build | custom | 1.0.0 | +| [run-script](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/run-script) | Run a script from a URL or inline text during devcontainer build | custom | 1.1.0 | | [schpet/linear-cli](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/schpet-linear-cli) | `linear` — CLI to access linear.com issue tracker | gh release | 1.0.2 | | [smallstep.com](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/smallstep.com) | `step` — zero-trust security toolkit and CA | gh release | 1.0.2 | | [socket.dev/sfw-free](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/socket.dev-sfw-free) | `sfw` — network security proxy that blocks malicious dependencies | gh release | 1.0.0 | diff --git a/src/add-script/devcontainer-feature.json b/src/add-script/devcontainer-feature.json index e9d330f..70a11c8 100644 --- a/src/add-script/devcontainer-feature.json +++ b/src/add-script/devcontainer-feature.json @@ -1,7 +1,7 @@ { "name": "add-script", "id": "add-script", - "version": "1.0.0", + "version": "1.1.0", "description": "Add a script from a URL or inline text to /usr/local/bin during devcontainer build", "documentationURL": "https://github.com/devcontainer-community/devcontainer-features/tree/main/src/add-script", "options": { diff --git a/src/add-script/install.sh b/src/add-script/install.sh index b01f1d9..18b7b07 100755 --- a/src/add-script/install.sh +++ b/src/add-script/install.sh @@ -31,6 +31,14 @@ echo_banner() { } install() { + # Re-read SCRIPT from the env file verbatim to prevent shell evaluation of + # backticks: the devcontainer CLI wraps option values in double quotes in the + # env file and then sources it, which causes bash to evaluate backticks. + # Reading the file directly with awk avoids this evaluation. + if [ -f ./devcontainer-features.env ]; then + SCRIPT=$(awk '/^SCRIPT="/{sub(/^SCRIPT="/,"");v=$0;f=1;next}f{v=v"\n"$0}END{if(f){sub(/"$/,"",v);printf"%s",v}}' ./devcontainer-features.env) + fi + if [ -z "${NAME}" ]; then echo "No script name provided. Nothing to do." return 0 diff --git a/src/run-script/devcontainer-feature.json b/src/run-script/devcontainer-feature.json index a832a76..23cc909 100644 --- a/src/run-script/devcontainer-feature.json +++ b/src/run-script/devcontainer-feature.json @@ -1,7 +1,7 @@ { "name": "run-script", "id": "run-script", - "version": "1.0.0", + "version": "1.1.0", "description": "Run a script from a URL or inline text during devcontainer build", "documentationURL": "https://github.com/devcontainer-community/devcontainer-features/tree/main/src/run-script", "options": { diff --git a/src/run-script/install.sh b/src/run-script/install.sh index 2c37d8f..ee3aa83 100755 --- a/src/run-script/install.sh +++ b/src/run-script/install.sh @@ -31,6 +31,14 @@ echo_banner() { } install() { + # Re-read SCRIPT from the env file verbatim to prevent shell evaluation of + # backticks: the devcontainer CLI wraps option values in double quotes in the + # env file and then sources it, which causes bash to evaluate backticks. + # Reading the file directly with awk avoids this evaluation. + if [ -f ./devcontainer-features.env ]; then + SCRIPT=$(awk '/^SCRIPT="/{sub(/^SCRIPT="/,"");v=$0;f=1;next}f{v=v"\n"$0}END{if(f){sub(/"$/,"",v);printf"%s",v}}' ./devcontainer-features.env) + fi + if [ -n "${URL}" ] && [ -n "${SCRIPT}" ]; then printf >&2 '=== [ERROR] Both "url" and "script" options are provided. Please provide only one.\n' exit 1 @@ -41,7 +49,6 @@ install() { return 0 fi - local tmpScript tmpScript="$(mktemp)" trap 'rm -f "${tmpScript}"' EXIT diff --git a/test/add-script/scenarios.json b/test/add-script/scenarios.json new file mode 100644 index 0000000..3260b7f --- /dev/null +++ b/test/add-script/scenarios.json @@ -0,0 +1,11 @@ +{ + "test-backtick": { + "image": "debian:latest", + "features": { + "add-script": { + "name": "test-backtick", + "script": "#!/bin/bash\necho `hostname`" + } + } + } +} diff --git a/test/add-script/test-backtick.sh b/test/add-script/test-backtick.sh new file mode 100755 index 0000000..e1d1267 --- /dev/null +++ b/test/add-script/test-backtick.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +source dev-container-features-test-lib + +check "test-backtick script exists" test -f /usr/local/bin/test-backtick +check "test-backtick script is executable" test -x /usr/local/bin/test-backtick +check "test-backtick script contains verbatim backtick" grep -qF '`hostname`' /usr/local/bin/test-backtick + +reportResults diff --git a/test/run-script/scenarios.json b/test/run-script/scenarios.json new file mode 100644 index 0000000..7879d0d --- /dev/null +++ b/test/run-script/scenarios.json @@ -0,0 +1,10 @@ +{ + "test-backtick": { + "image": "debian:latest", + "features": { + "run-script": { + "script": "echo backtick_test=`hostname` > /tmp/devcontainer-run-script-test.txt" + } + } + } +} diff --git a/test/run-script/test-backtick.sh b/test/run-script/test-backtick.sh new file mode 100755 index 0000000..688648d --- /dev/null +++ b/test/run-script/test-backtick.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +source dev-container-features-test-lib + +check "run-script created output file" test -f /tmp/devcontainer-run-script-test.txt +check "run-script output contains expected prefix" grep -q 'backtick_test=' /tmp/devcontainer-run-script-test.txt +check "run-script output contains non-empty value" grep -qv 'backtick_test=$' /tmp/devcontainer-run-script-test.txt + +reportResults