From d05e06662193efd2874ae9533cac18fcfa8d2869 Mon Sep 17 00:00:00 2001 From: Miroslav Shubernetskiy Date: Tue, 3 Oct 2023 12:35:38 -0400 Subject: [PATCH] initial setup action script --- .github/workflows/setup.yml | 34 ++++++ .gitignore | 1 + README.md | 45 ++++++++ action.yml | 24 +++++ setup.sh | 200 ++++++++++++++++++++++++++++++++++++ 5 files changed, 304 insertions(+) create mode 100644 .github/workflows/setup.yml create mode 100644 .gitignore create mode 100644 README.md create mode 100644 action.yml create mode 100755 setup.sh diff --git a/.github/workflows/setup.yml b/.github/workflows/setup.yml new file mode 100644 index 0000000..516c4d6 --- /dev/null +++ b/.github/workflows/setup.yml @@ -0,0 +1,34 @@ +name: setup + +on: + pull_request: + +permissions: + contents: read + +jobs: + verify: + runs-on: ubuntu-latest + + concurrency: + # only allow one job per PR running + # older pending jobs will be cancelled not to waste CI minutes + # cannot use github.job here https://github.com/community/community/discussions/13496 + group: ${{ github.workflow }}-setup-${{ github.ref }} + cancel-in-progress: true + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Chalk + uses: . + + - name: Verify Setup + run: | + set -x + which chalk + which docker + echo 'log_level: "trace"' > /etc/chalk.conf + chalk version + docker version diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6e92f57 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +tags diff --git a/README.md b/README.md new file mode 100644 index 0000000..ea83c11 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# Setup Chalk + +GitHub Action to setting up [Chalk]. + +This action will install `chalk` and will also wrap other commands +`chalk` supports such as `docker`. + +## Usage + +```yaml +name: ci + +on: + push: + +jobs: + buildx: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Chalk + uses: crashappsec/setup-chalk-version +``` + +## Customizing + +The following parameters can be provided to the action. + +| Name | Type | Default | Description | +| --------- | ------ | ------- | --------------------------------------------------------------------------------------------------------------- | +| `version` | String | | Version of chalk to install. By default latest version is installed. See [releases] for all available versions. | +| `load` | String | | Chalk config to load. Can be either path to a file or an URL. | + +For example: + +```yaml +- name: Set up Chalk + uses: crashappsec/setup-chalk-version + with: + version: "0.1.2" +``` + +[chalk]: https://github.com/crashappsec/chalk/ +[releases]: https://crashoverride.com/releases diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..0f009df --- /dev/null +++ b/action.yml @@ -0,0 +1,24 @@ +name: Setup Chalk +description: Install chalk and wrap supported commands + +inputs: + version: + description: | + Version of chalk to install. + By default latest version is installed. + See https://crashoverride.com/releases for all available versions. + required: false + load: + description: | + Chalk config to load. + Can be either path to a file or an URL. + required: false + +runs: + using: "composite" + steps: + - shell: bash + run: | + setup.sh \ + --version=${{ inputs.version }} \ + --load=${{ inputs.load }} diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..0e32f00 --- /dev/null +++ b/setup.sh @@ -0,0 +1,200 @@ +#!/usr/bin/env bash + +set -eEu +set -o pipefail + +DEFAULT_CHALK_PATH=/usr/local/bin/chalk +WRAPPINGS_PATH=/usr/local/chalk +URL_PREFIX=https://crashoverride.com/dl/chalk +SHA256=sha256sum +TMP=/tmp + +# on osx, sha256sum doesnt exist and instead its shasum +if [ -z "$(which $SHA256 2> /dev/null)" ]; then + SHA256="shasum -a 256" +fi + +# version of chalk to download +version= +# which config to load after install +load= +# where chalk should be installed +chalk_path= +# tmp location for downloading chalk +chalk_tmp= +# whether to overwrite existing chalk binary +overwrite=true +# whether to wrap external commands with chalk +wrap=true + +function log { + echo "$@" > /dev/stderr +} + +# wrapper for calling chalk within the script +function chalk { + echo CHALK_PATH INSIDE "$chalk_path" > /dev/stderr + $chalk_path --log-level=error --skip-summary-report --skip-command-report "$@" +} + +# find out latest chalk version +function get_latest_version { + log Querying latest version of chalk + version=$(curl -fsSL "$URL_PREFIX/current-version.txt") + log Latest version is "$version" + echo "$version" +} + +# get the chalk file name for the version/os/architecture +function chalk_version_name { + echo "chalk-$version-$(uname -s)-$(uname -m)" +} + +# download chalk and validate its checksum +function download_chalk { + url=$URL_PREFIX/$(chalk_version_name) + log Downloading chalk from "$url" + wget --content-on-error --quiet --directory-prefix=$TMP --unlink "$url"{,.sha256} || ( + log Could not download "$(chalk_version_name)". Are you sure this is a valid version? + return 1 + ) + log Validating sha256 signature + $SHA256 "$chalk_tmp.sha256" +} + +# validate downloaded chalk can run on the system +# and then install it to $chalk_path which should be on PATH +function install_chalk { + chmod +x "$chalk_tmp" + log Checking chalk version + $chalk_tmp version + log Installing chalk to "$chalk_path" + mkdir -p "$(dirname "$chalk_path")" + cp "$chalk_tmp" "$chalk_path" +} + +# load custom chalk config +function load_config { + log Loading custom chalk config from "$load" + chalk load "$load" +} + +# add line to config file if its not there already +function add_line_to_config { + line=$1 + config=$2 + if grep "$line" "$config" &> /dev/null; then + log "$cmd" path is already configured in chalk config + return 0 + fi + log Adding "\"$line\"" to chalk config + echo >> "$config" + echo "$line" >> "$config" +} + +# add necessary configs to wrap command with chalk +function add_cmd_exe_to_config { + cmd=$1 + path=$2 + folder=$(dirname "$path") + config=$(mktemp) + chalk dump > "$config" + add_line_to_config "default_command = \"$cmd\"" "$config" + add_line_to_config "${cmd}_exe = \"$folder\"" "$config" + chalk load "$config" + chalk dump +} + +# wrap given command with chalk +function wrap_cmd { + cmd=$1 + existing_path=$(which "$cmd" 2> /dev/null) + if [ -z "$existing_path" ]; then + log Skipping wrapping "$cmd" as it is not installed + return 0 + fi + + log Wrapping "$existing_path" command with chalk + + # As we cant control PATH in CI, we copy original command + # to a chalk-specific location. + # Then well configure chalk to search for commands here + # and will replace the original binary with chalk. + # This way we chalk will still be able to find the original + # command and binary will still be in the same location. + new_path="$WRAPPINGS_PATH/$cmd" + sudo mkdir -p "$(dirname "$new_path")" + sudo cp "$existing_path" "$new_path" + log Moved "$existing_path" to "$new_path" + + # create temporary chalk copy so that we can adjust its configuration + # to be able to find the moved binary in the custom location + tmp=$(mktemp) + cp "$chalk_path" "$tmp" + chalk_path=$tmp add_cmd_exe_to_config "$cmd" "$new_path" + + sudo mv "$tmp" "$existing_path" + log Replaced "$existing_path" with chalk +} + +for arg; do + shift + case "$arg" in + --version=*) + version=${arg##*=} + ;; + --load=*) + load=${arg##*=} + ;; + --chalk-path=*) + chalk_path=${arg##*=} + ;; + --no-wrap) + wrap= + ;; + --debug) + set -x + ;; + --overwrite) + overwrite=true + ;; + --no-overwrite) + overwrite= + ;; + *) + set -- "$@" "$arg" + ;; + esac +done + +if [ -z "$chalk_path" ]; then + chalk_path=$(which chalk 2> /dev/null || true) +fi +if [ -z "$chalk_path" ]; then + chalk_path=$DEFAULT_CHALK_PATH +fi + +if ! [ -f "$chalk_path" ] || [ -n "$overwrite" ]; then + if [ -f "$chalk_path" ]; then + log "$chalk_path" is already installed. overwriting + fi + + if [ -z "$version" ]; then + version=$(get_latest_version) + fi + + chalk_tmp=$TMP/$(chalk_version_name) + + download_chalk + install_chalk +else + log "$chalk_path" is already installed. skipping +fi + +if [ -n "$load" ]; then + load_config +fi + +if [ -n "$wrap" ]; then + wrap_cmd docker +fi