From d2eec449e97e867bf3d1a4afe2da1e0660a8ef2a Mon Sep 17 00:00:00 2001 From: Owen Nelson Date: Wed, 10 Jan 2024 16:25:14 -0600 Subject: [PATCH 1/8] Only install binary and not hooks/scripts Authored-by: Owen Nelson --- install.sh | 323 +++++++++++++++++------------------------------------ 1 file changed, 102 insertions(+), 221 deletions(-) diff --git a/install.sh b/install.sh index 89b30327..f69fdc1f 100755 --- a/install.sh +++ b/install.sh @@ -1,256 +1,137 @@ #!/bin/bash -# Hello there! If you update the talisman version, please remember to: -# - Test that this script works with no args, and the `pre-push` / `pre-commit` arg. -# - also update `install.sh` in the gh_pages branch of this repo, so that -# gets updated too. -# Thanks! - set -euo pipefail -DEBUG=${DEBUG:-''} -HOOK_NAME="${1:-pre-push}" -case "$HOOK_NAME" in -pre-commit | pre-push) REPO_HOOK_TARGET=".git/hooks/${HOOK_NAME}" ;; -*) - echo "Unknown Hook name '${HOOK_NAME}'. Please check parameters" - exit 1 - ;; -esac - -# we call run() at the end of the script to prevent inconsistent state in case -# user runs with curl|bash and curl fails in the middle of the download -# (https://www.seancassidy.me/dont-pipe-to-your-shell.html) -run() { +function run() { declare TALISMAN_BINARY_NAME - IFS=$'\n' - - GITHUB_URL="https://github.com/thoughtworks/talisman" - VERSION=$(curl --silent "https://api.github.com/repos/thoughtworks/talisman/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') - BINARY_BASE_URL="$GITHUB_URL/releases/download/$VERSION" - REPO_HOOK_BIN_DIR=".git/hooks/bin" + E_UNSUPPORTED_ARCH=5 - DEFAULT_GLOBAL_TEMPLATE_DIR="$HOME/.git-templates" + DEBUG=${DEBUG:-''} + VERSION=${VERSION:-'latest'} + INSTALL_ORG_REPO=${INSTALL_ORG_REPO:-'thoughtworks/talisman'} + INSTALL_LOCATION=${INSTALL_LOCATION:-'/usr/local/bin'} - declare DOWNLOADED_BINARY TEMP_DIR=$(mktemp -d 2>/dev/null || mktemp -d -t 'talisman_setup') - trap "rm -r ${TEMP_DIR}" EXIT - chmod 0700 ${TEMP_DIR} - - E_HOOK_ALREADY_PRESENT=1 - E_CHECKSUM_MISMATCH=2 - E_USER_CANCEL=3 - E_HEADLESS=4 - E_UNSUPPORTED_ARCH=5 - E_DEPENDENCY_NOT_FOUND=6 + # shellcheck disable=SC2064 + trap "rm -r $TEMP_DIR" EXIT + chmod 0700 "$TEMP_DIR" - echo_error() { - echo -ne $(tput setaf 1) >&2 + function echo_error() { + echo -ne "$(tput setaf 1)" >&2 echo "$1" >&2 - echo -ne $(tput sgr0) >&2 + echo -ne "$(tput sgr0)" >&2 } - export -f echo_error - function echo_debug() { - [[ -z "${DEBUG}" ]] && return - echo -ne $(tput setaf 3) >&2 - echo "$1" >&2 - echo -ne $(tput sgr0) >&2 - } - export -f echo_debug + function echo_debug() { + [[ -z "$DEBUG" ]] && return + echo -ne "$(tput setaf 3)" >&2 + echo "$1" >&2 + echo -ne "$(tput sgr0)" >&2 + } - echo_success() { - echo -ne $(tput setaf 2) + function echo_success() { + echo -ne "$(tput setaf 2)" echo "$1" >&2 - echo -ne $(tput sgr0) + echo -ne "$(tput sgr0)" } - export -f echo_success - operating_system() { + function operating_system() { OS=$(uname -s) case $OS in - "Linux") - echo "linux" - ;; - "Darwin") - echo "darwin" - ;; - MINGW32_NT-*) - echo "windows" - ;; - MINGW64_NT-*) - echo "windows" - ;; - MINGW64_NT-6.3*) - echo "windows" - ;; - *) - echo_error "Talisman currently only supports Windows, Linux and MacOS(darwin) systems." - echo_error "If this is a problem for you, please open an issue: https://github.com/${INSTALL_ORG_REPO}/issues/new" - exit $E_UNSUPPORTED_ARCH - ;; - esac -} - - binary_arch_suffix() { - declare OS - OS=$(operating_system) - ARCH=$(uname -m) - case $ARCH in - "x86_64") - OS="${OS}_amd64" - ;; - "i686" | "i386") - OS="${OS}_386" - ;; - "arm64") - OS="${OS}_arm64" - ;; - *) - echo_error "Talisman currently only supports x86 and x86_64 architectures." - echo_error "If this is a problem for you, please open an issue: https://github.com/thoughtworks/talisman/issues/new" - exit $E_UNSUPPORTED_ARCH - ;; - esac - - TALISMAN_BINARY_NAME="talisman_${OS}" - if [[ $OS == *"windows"* ]]; then - TALISMAN_BINARY_NAME="${TALISMAN_BINARY_NAME}.exe" - fi + "Linux") + echo "linux" + ;; + "Darwin") + echo "darwin" + ;; + MINGW32_NT-*) + echo "windows" + ;; + MINGW64_NT-*) + echo "windows" + ;; + MSYS_NT-*) + echo "windows" + ;; + *) + echo_error "Talisman currently only supports Windows, Linux and MacOS(darwin) systems." + echo_error "If this is a problem for you, please open an issue: https://github.com/$INSTALL_ORG_REPO/issues/new" + exit $E_UNSUPPORTED_ARCH + ;; + esac } - function download() { - OBJECT=$1 - DOWNLOAD_URL=${BINARY_BASE_URL}/${OBJECT} - echo "Downloading ${OBJECT} from ${DOWNLOAD_URL}" - curl --location --silent ${DOWNLOAD_URL} >"$TEMP_DIR/${OBJECT}" - } - - function verify_checksum() { - FILE_NAME=$1 - CHECKSUM_FILE_NAME='checksums' - echo_debug "Verifying checksum for ${FILE_NAME}" - download ${CHECKSUM_FILE_NAME} - - pushd ${TEMP_DIR} >/dev/null 2>&1 - grep ${TALISMAN_BINARY_NAME} ${CHECKSUM_FILE_NAME} >${CHECKSUM_FILE_NAME}.single - - if ! command -v shasum &> /dev/null; then - sha256sum -c ${CHECKSUM_FILE_NAME}.single - else - shasum -a 256 -c ${CHECKSUM_FILE_NAME}.single - fi - popd >/dev/null 2>&1 - echo_debug "Checksum verification successful!" - echo - } - - function download_and_verify() { - binary_arch_suffix - download "${TALISMAN_BINARY_NAME}" - DOWNLOADED_BINARY="${TEMP_DIR}/${TALISMAN_BINARY_NAME}" - verify_checksum "${TALISMAN_BINARY_NAME}" - } - - install_to_repo() { - if [[ -x "$REPO_HOOK_TARGET" ]]; then - echo_error "Oops, it looks like you already have a ${HOOK_NAME} hook installed at '${REPO_HOOK_TARGET}'." - echo_error "If this is expected, you should consider setting-up a tool to allow git hook chaining," - echo_error "like pre-commit (brew install pre-commit) or Husky or any other tool of your choice." - echo_error "WARNING! Talisman hook not installed." - exit $E_HOOK_ALREADY_PRESENT + function set_talisman_binary_name() { + # based on OS (linux/darwin) and ARCH(32/64 bit) + declare SUFFIX + SUFFIX=$(operating_system) + ARCH=$(uname -m) + case $ARCH in + "x86_64") + SUFFIX="${SUFFIX}_amd64" + ;; + "i686" | "i386") + SUFFIX="${SUFFIX}_386" + ;; + "arm64" | "aarch64") + SUFFIX="${SUFFIX}_arm64" + ;; + *) + echo_error "Talisman currently only supports x86 and x86_64 and arm64 architectures." + echo_error "If this is a problem for you, please open an issue: https://github.com/$INSTALL_ORG_REPO/issues/new" + exit $E_UNSUPPORTED_ARCH + ;; + esac + + TALISMAN_BINARY_NAME="talisman_$SUFFIX" + if [[ $SUFFIX == *"windows"* ]]; then + TALISMAN_BINARY_NAME="$TALISMAN_BINARY_NAME.exe" fi + } - download_and_verify - - mkdir -p "$REPO_HOOK_BIN_DIR" - TALISMAN_BIN_TARGET="${REPO_HOOK_BIN_DIR}/talisman" - cp "$DOWNLOADED_BINARY" "$TALISMAN_BIN_TARGET" - chmod +x "$TALISMAN_BIN_TARGET" - - cat >"$REPO_HOOK_TARGET" <"$TEMP_DIR/$OBJECT" } - install_to_git_templates() { - if [[ ! -t 1 ]]; then - echo_error "Headless install to system templates is not supported." - echo_error "If you would like this feature, please open an issue: https://github.com/thoughtworks/talisman/issues/new" - exit $E_HEADLESS - fi - - TEMPLATE_DIR=$(git config --global init.templatedir) || true + function verify_checksum() { + FILE_NAME=$1 + CHECKSUM_FILE_NAME='checksums' + echo_debug "Verifying checksum for $FILE_NAME" + download $CHECKSUM_FILE_NAME - echo "Not running from inside a git repository... installing as a" - echo "git template." - echo - echo "If you meant to install to a specific repo, 'cd' into that" - echo "repo and run this script again." - echo - echo "Installing as a template will automatically add Talisman to" - echo "any new repo that you 'init' or 'clone'." - echo + pushd "$TEMP_DIR" >/dev/null 2>&1 + grep "$TALISMAN_BINARY_NAME" $CHECKSUM_FILE_NAME >$CHECKSUM_FILE_NAME.single - if [[ "$TEMPLATE_DIR" == "" ]]; then - echo "No git template directory is configured. Let's add one." - echo "(this will override any system git templates and modify your git config file)" - echo - read -u1 -p "Git template directory: ($DEFAULT_GLOBAL_TEMPLATE_DIR) " TEMPLATE_DIR - echo - TEMPLATE_DIR=${TEMPLATE_DIR:-$DEFAULT_GLOBAL_TEMPLATE_DIR} - git config --global init.templatedir $TEMPLATE_DIR + if ! command -v shasum &> /dev/null; then + sha256sum -c $CHECKSUM_FILE_NAME.single else - echo "You already have a git template directory configured." - echo - read -u1 -p "Add Talisman to '$TEMPLATE_DIR/hooks?' (Y/n) " USE_EXISTING - echo - - case "$USE_EXISTING" in - Y | y | "") ;; # okay, continue - *) - echo_error "Not installing Talisman." - echo_error "If you were trying to install into a single git repo, re-run this command from that repo." - echo_error "You can always download/compile manually from our Github page: $GITHUB_URL" - exit $E_USER_CANCEL - ;; - esac + shasum -a 256 -c $CHECKSUM_FILE_NAME.single fi + popd >/dev/null 2>&1 + echo_debug "Checksum verification successfully!" + echo + } - # Support '~' in path - TEMPLATE_DIR=${TEMPLATE_DIR/#\~/$HOME} - - if [ -f "$TEMPLATE_DIR/hooks/${HOOK_NAME}" ]; then - echo_error "Oops, it looks like you already have a ${HOOK_NAME} hook installed at '$TEMPLATE_DIR/hooks/${HOOK_NAME}'." - echo_error "If this is expected, you should consider setting-up a tool to allow git hook chaining," - echo_error "like pre-commit (brew install pre-commit) or Husky or any other tool of your choice." - echo_error "WARNING! Talisman hook not installed." - exit $E_HOOK_ALREADY_PRESENT - fi - - mkdir -p "$TEMPLATE_DIR/hooks" - - download_and_verify - - cp "$DOWNLOADED_BINARY" "$TEMPLATE_DIR/hooks/${HOOK_NAME}" - chmod +x "$TEMPLATE_DIR/hooks/${HOOK_NAME}" + function download_talisman_binary() { + download "$TALISMAN_BINARY_NAME" + verify_checksum "$TALISMAN_BINARY_NAME" + } - echo_success "Talisman successfully installed." + function setup_talisman() { + sudo cp "$TEMP_DIR/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/talisman" + sudo chmod +x "$INSTALL_LOCATION/talisman" } - if [ ! -d "./.git" ]; then - install_to_git_templates - else - install_to_repo - fi + set_talisman_binary_name + + echo_success "Downloading talisman binary" + download_talisman_binary + setup_talisman } -run $0 $@ +run From 9753625e38d1bed9407582fdd6b53f39cfbf592c Mon Sep 17 00:00:00 2001 From: Owen Nelson Date: Wed, 10 Jan 2024 17:12:36 -0600 Subject: [PATCH 2/8] Add instructions for installing just the binary Authored-by: Owen Nelson --- README.md | 51 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 7d5fb77b..e6494b5d 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ## Table of Contents - [What is Talisman?](#what-is-talisman) - [Installation](#installation) - - [[Recommended approach]](#recommended-approach) + - [Install onto path (recommended approach)](#install-onto-path-recommended-approach) - [Installation as a global hook template](#installation-as-a-global-hook-template) - [Handling existing hooks](#handling-existing-hooks) - [1. Pre-commit (Linux/Unix)](#1-pre-commit-linuxunix) @@ -44,10 +44,12 @@ - [Contributing to Talisman](#contributing-to-talisman) # What is Talisman? -Talisman is a tool that installs a hook to your repository to ensure that potential secrets or sensitive information do not leave the developer's workstation. -It validates the outgoing changeset for things that look suspicious - such as potential SSH -keys, authorization tokens, private keys etc. +Talisman is a tool that scans git changesets to ensure that potential secrets +or sensitive information do not leave the developer's workstation. + +It validates the outgoing changeset for things that look suspicious - such as +potential SSH keys, authorization tokens, private keys etc. # Installation @@ -55,8 +57,9 @@ Talisman supports MAC OSX, Linux and Windows. Talisman can be installed and used in one of the following ways: -1. As a git hook as a global [git hook template](https://git-scm.com/docs/git-init#_template_directory) and a CLI utility (for git repo scanning) -2. As a git hook into a single git repository +1. As a standalone executable +2. As a git hook as a global [git hook template](https://git-scm.com/docs/git-init#_template_directory) and a CLI utility (for git repo scanning) +3. As a git hook into a single git repository Talisman can be set up as either a pre-commit or pre-push hook on the git repositories. @@ -64,11 +67,34 @@ Find the instructions below. *Disclaimer: Secrets creeping in via a forced push in a git repository cannot be detected by Talisman. A forced push is believed to be notorious in its own ways, and we suggest git repository admins to apply appropriate measures to authorize such activities.* +## Install onto path (recommended approach) + +We recommend installing `talisman` onto your path so that it is available for +git hook frameworks and scripts. Pick the correct binary for your system from +our [Releases Page](https://github.com/thoughtworks/talisman/releases), or run +our [install script](https://github.com/thoughtworks/talisman/blob/main/install.sh): + +``` +bash -c "$(curl --silent https://raw.githubusercontent.com/thoughtworks/talisman/main/install.sh)" +``` + +Or set environment variable `INSTALL_LOCATION` to specify a custom location for +the binary: + +``` +INSTALL_LOCATION=/usr/local/bin bash -c "$(curl --silent https://raw.githubusercontent.com/thoughtworks/talisman/main/install.sh)" +``` + +Or using linuxbrew in Linux and homebrew in macOS by running the following +command in terminal: + +``` +brew install talisman +``` -## [Recommended approach] ## Installation as a global hook template -We recommend installing Talisman as a **pre-commit git hook template**, as that will cause +We offer scripts that will install Talisman as a **pre-commit git hook template**, as that will cause Talisman to be present, not only in your existing git repositories, but also in any new repository that you 'init' or 'clone'. @@ -102,15 +128,6 @@ If you choose to set the `$PATH` later, please export TALISMAN\_HOME=$HOME/.tali - you can set SEARCH_ROOT environment variable with the path of the base directory before executing the installation so you don't need to input it manually during the installation -#### Alternative installation using brew - -Talisman can also be installed using linuxbrew in Linux and homebrew in macOS by running the following command in terminal - - ``` -brew install talisman -``` - - ### Handling existing hooks Installation of Talisman globally does not clobber pre-existing hooks on repositories.
If the installation script finds any existing hooks, it will only indicate so on the console.
From 5f1bddab3a0f2c2b491600fb5c5f1f90cb474abf Mon Sep 17 00:00:00 2001 From: Owen Nelson Date: Thu, 11 Jan 2024 10:21:32 -0600 Subject: [PATCH 3/8] Consolidate hook framework instructions Authored-by: Owen Nelson --- README.md | 130 +++++++++++++++--------------------------------------- 1 file changed, 36 insertions(+), 94 deletions(-) diff --git a/README.md b/README.md index e6494b5d..8a023b38 100644 --- a/README.md +++ b/README.md @@ -12,15 +12,10 @@ - [Installation](#installation) - [Install onto path (recommended approach)](#install-onto-path-recommended-approach) - [Installation as a global hook template](#installation-as-a-global-hook-template) - - [Handling existing hooks](#handling-existing-hooks) - - [1. Pre-commit (Linux/Unix)](#1-pre-commit-linuxunix) - - [2. Husky (Linux/Unix/Windows)](#2-husky-linuxunixwindows) - - [Windows](#windows) - - [Linux/Unix](#linuxunix) - - [Windows](#windows-1) - - [Linux/Unix](#linuxunix-1) - [Installation to a single project](#installation-to-a-single-project) - - [Handling existing hooks](#handling-existing-hooks-1) +- [Using with hook frameworks](#using-with-hook-frameworks) + - [Pre-commit](#pre-commit) + - [Husky](#husky) - [Upgrading](#upgrading) - [Talisman in action](#talisman-in-action) - [Validations](#validations) @@ -41,7 +36,7 @@ - [Uninstallation](#uninstallation) - [Uninstallation from a global hook template](#uninstallation-from-a-global-hook-template) - [Uninstallation from a single repository](#uninstallation-from-a-single-repository) - - [Contributing to Talisman](#contributing-to-talisman) +- [Contributing to Talisman](#contributing-to-talisman) # What is Talisman? @@ -122,81 +117,11 @@ bash -c "$(curl --silent https://thoughtworks.github.io/talisman/scripts/install If you choose to set the `$PATH` later, please export TALISMAN\_HOME=$HOME/.talisman/bin to the path. -3. Choose a base directory where Talisman should scan for all git repositories, and setup a git hook (pre-commit or pre-push, as chosen in step 1) as a symlink. - This script will not clobber pre-existing hooks. If you have existing hooks, [look for ways to chain Talisman into them.](#handling-existing-hooks) +3. Choose a base directory where Talisman should scan for all git repositories, and set up a git hook (pre-commit or pre-push, as chosen in step 1) as a symlink. + This script will not clobber pre-existing hooks. If you have existing hooks you can add talisman through a [hook framework](#using-with-hook-frameworks) - you can set SEARCH_ROOT environment variable with the path of the base directory before executing the installation so you don't need to input it manually during the installation - -### Handling existing hooks -Installation of Talisman globally does not clobber pre-existing hooks on repositories.
-If the installation script finds any existing hooks, it will only indicate so on the console.
-To achieve running multiple hooks we suggest (but not limited to) the following two tools - -#### 1. Pre-commit (Linux/Unix) -Use [pre-commit](https://pre-commit.com) tool to manage all the existing hooks along with Talisman. -In the suggestion, it will prompt the following code to be included in .pre-commit-config.yaml - -``` - - repo: local - hooks: - - id: talisman-precommit - name: talisman - entry: bash -c 'if [ -n "${TALISMAN_HOME:-}" ]; then ${TALISMAN_HOME}/talisman_hook_script pre-commit; else echo "TALISMAN does not exist. Consider installing from https://github.com/thoughtworks/talisman . If you already have talisman installed, please ensure TALISMAN_HOME variable is set to where talisman_hook_script resides, for example, TALISMAN_HOME=${HOME}/.talisman/bin"; fi' - language: system - pass_filenames: false - types: [text] - verbose: true -``` - -#### 2. Husky (Linux/Unix/Windows) -[husky](https://typicode.github.io/husky) is an npm module for managing git hooks. -In order to use husky, make sure you have already set TALISMAN_HOME to `$PATH`. - -+ **Existing Users** - - If you already are using husky, add the following lines to husky pre-commit in package.json - - ###### Windows - - ``` - "bash -c '\"%TALISMAN_HOME%\\${TALISMAN_BINARY_NAME}\" --githook pre-commit'" -``` - - ###### Linux/Unix - - ``` - $TALISMAN_HOME/talisman_hook_script pre-commit -``` -+ **New Users** - - If you want to use husky with multiple hooks along with talisman, add the following snippet to you package json. -###### Windows - - ``` - { - "husky": { - "hooks": { - "pre-commit": "bash -c '\"%TALISMAN_HOME%\\${TALISMAN_BINARY_NAME}\" --githook pre-commit'" && "other-scripts" - } - } - } -``` - - ###### Linux/Unix - - ``` - { - "husky": { - "hooks": { - "pre-commit": "$TALISMAN_HOME/talisman_hook_script pre-commit" && "other-scripts" - } - } - } -``` - - - ## Installation to a single project ```bash @@ -214,24 +139,41 @@ cd my-git-project ~/install-talisman.sh pre-commit ``` -### Handling existing hooks -Talisman will need to be chained with any existing git hooks.You can use [pre-commit](https://pre-commit.com) git hooks framework to handle this. +*Disclaimer: Talisman cannot guarantee its functionality in Microsoft's unsupported versions of Windows. Anyway Talisman is successfully tested on Windows 7 and server 2008 R2, which might not work in future releases.* + +# Using with hook frameworks + +Globally installing talisman as a hook will not clobber any existing hooks. If +the installation script finds any existing hooks, it will only indicate so on +the console. To run multiple hooks we suggest using a hook framework, such as +pre-commit or husky. These instructions assume that the talisman executable is +installed somewhere on your system's path. -Add this to your `.pre-commit-config.yaml` (be sure to update `rev` to point to -a real git revision!) +## Pre-commit + +Use [pre-commit](https://pre-commit.com) tool to manage all the existing hooks +along with Talisman. In the suggestion, it will prompt the following code to be +included in .pre-commit-config.yaml: ```yaml - repo: https://github.com/thoughtworks/talisman rev: 'v1.28.0' # Update me! hooks: - # either `commit` or `push` support - # - id: talisman-push - - id: talisman-commit - entry: cmd --githook pre-commit - + # both pre-commit and pre-push supported + # - id: talisman-push + - id: talisman-commit + entry: cmd --githook pre-commit ``` -*Disclaimer: Talisman cannot guarantee its functionality in Microsoft's unsupported versions of Windows. Anyway Talisman is successfully tested on Windows 7 and server 2008 R2, which might not work in future releases.* +## Husky + +[husky](https://typicode.github.io/husky) is an npm module for managing hooks. +Add the following line to the husky pre-commit configuration in you +`package.json`: + +``` +talisman --githook pre-commit +``` # Upgrading Since release v0.4.4, Talisman automatically updates the binary to the latest release, when the hook is invoked (at pre-commit/pre-push, as set up). So, just sit back, relax, and keep using the latest Talisman without any extra efforts. @@ -521,8 +463,8 @@ To run the checksum please "cd" into the root of your repository and run the fol For Example: `talisman --checksum="*.pem *.txt"` -1. This command finds all the .pem files in the respository and calculates collective checksum of all those files and outputs a yaml format for .talismanrc. In the same way it deals with the .txt files. -2. Multiple file names / patterns can be given with space seperation. +1. This command finds all the .pem files in the repository and calculates collective checksum of all those files and outputs a yaml format for .talismanrc. In the same way it deals with the .txt files. +2. Multiple file names / patterns can be given with space separation. Example output: @@ -608,6 +550,6 @@ When you installed Talisman, it must have created a pre-commit or pre-push hook You can remove the hook manually by deleting the Talisman pre-commit or pre-push hook from .git/hooks folder in repository. -## Contributing to Talisman +# Contributing to Talisman To contribute to Talisman, have a look at our [contributing guide](contributing.md). From b74f0418f9f8814dd476572943ae7be3778ebe64 Mon Sep 17 00:00:00 2001 From: Owen Nelson Date: Thu, 11 Jan 2024 16:06:16 -0600 Subject: [PATCH 4/8] Install without sudo if possible Authored-by: Owen Nelson --- install.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index f69fdc1f..47d34d3d 100755 --- a/install.sh +++ b/install.sh @@ -123,8 +123,16 @@ function run() { } function setup_talisman() { - sudo cp "$TEMP_DIR/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/talisman" - sudo chmod +x "$INSTALL_LOCATION/talisman" + if (touch "$INSTALL_LOCATION/talisman" &>/dev/null); then + cp "$TEMP_DIR/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/talisman" + chmod +x "$INSTALL_LOCATION/talisman" + elif (which sudo &>/dev/null); then + sudo cp "$TEMP_DIR/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/talisman" + sudo chmod +x "$INSTALL_LOCATION/talisman" + else + echo_error "Insufficient permission to install to $INSTALL_LOCATION" + exit 126 + fi } set_talisman_binary_name From 352530490da916b688ca7ec17b0beba427b99092 Mon Sep 17 00:00:00 2001 From: Owen Nelson Date: Thu, 11 Jan 2024 16:50:26 -0600 Subject: [PATCH 5/8] Fail if install location does not exist Authored-by: Owen Nelson --- install.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/install.sh b/install.sh index 47d34d3d..5a5e9051 100755 --- a/install.sh +++ b/install.sh @@ -105,12 +105,11 @@ function run() { download $CHECKSUM_FILE_NAME pushd "$TEMP_DIR" >/dev/null 2>&1 - grep "$TALISMAN_BINARY_NAME" $CHECKSUM_FILE_NAME >$CHECKSUM_FILE_NAME.single if ! command -v shasum &> /dev/null; then - sha256sum -c $CHECKSUM_FILE_NAME.single + sha256sum --ignore-missing -c $CHECKSUM_FILE_NAME else - shasum -a 256 -c $CHECKSUM_FILE_NAME.single + shasum -a 256 --ignore-missing -c $CHECKSUM_FILE_NAME fi popd >/dev/null 2>&1 echo_debug "Checksum verification successfully!" @@ -135,6 +134,11 @@ function run() { fi } + if [ ! -d "$INSTALL_LOCATION" ]; then + echo_error "$INSTALL_LOCATION is not a directory!" + exit 1 + fi + set_talisman_binary_name echo_success "Downloading talisman binary" From 643806e9a052cd8b6038018a0814ca100bf946b9 Mon Sep 17 00:00:00 2001 From: Owen Nelson Date: Fri, 12 Jan 2024 10:29:00 -0600 Subject: [PATCH 6/8] Declare functions outside of body of main function Authored-by: Owen Nelson --- install.sh | 245 ++++++++++++++++++++++++++--------------------------- 1 file changed, 118 insertions(+), 127 deletions(-) diff --git a/install.sh b/install.sh index 5a5e9051..0933e137 100755 --- a/install.sh +++ b/install.sh @@ -1,149 +1,140 @@ #!/bin/bash set -euo pipefail -function run() { - declare TALISMAN_BINARY_NAME +declare TALISMAN_BINARY_NAME + +E_UNSUPPORTED_ARCH=5 +DEBUG=${DEBUG:-''} +VERSION=${VERSION:-'latest'} +INSTALL_ORG_REPO=${INSTALL_ORG_REPO:-'thoughtworks/talisman'} +INSTALL_LOCATION=${INSTALL_LOCATION:-'/usr/local/bin'} + +function echo_error() { + echo -ne "$(tput setaf 1)" >&2 + echo "$1" >&2 + echo -ne "$(tput sgr0)" >&2 +} + +function echo_debug() { + [[ -z "$DEBUG" ]] && return + echo -ne "$(tput setaf 3)" >&2 + echo "$1" >&2 + echo -ne "$(tput sgr0)" >&2 +} + +function echo_success() { + echo -ne "$(tput setaf 2)" + echo "$1" >&2 + echo -ne "$(tput sgr0)" +} + +function operating_system() { + OS=$(uname -s) + case $OS in + "Linux") + echo "linux" + ;; + "Darwin") + echo "darwin" + ;; + MINGW32_NT-* | MINGW64_NT-* | MSYS_NT-*) + echo "windows" + ;; + *) + echo_error "Talisman currently only supports Windows, Linux, and MacOS (darwin) systems." + echo_error "If this is a problem for you, please open an issue: https://github.com/$INSTALL_ORG_REPO/issues/new" + exit $E_UNSUPPORTED_ARCH + ;; + esac +} - E_UNSUPPORTED_ARCH=5 +function architecture() { + ARCH=$(uname -m) + case $ARCH in + "x86_64") + echo "amd64" + ;; + "i686" | "i386") + echo "386" + ;; + "arm64" | "aarch64") + echo "arm64" + ;; + *) + echo_error "Talisman currently only supports x86 and x86_64 and arm64 architectures." + echo_error "If this is a problem for you, please open an issue: https://github.com/$INSTALL_ORG_REPO/issues/new" + exit $E_UNSUPPORTED_ARCH + ;; + esac +} - DEBUG=${DEBUG:-''} - VERSION=${VERSION:-'latest'} - INSTALL_ORG_REPO=${INSTALL_ORG_REPO:-'thoughtworks/talisman'} - INSTALL_LOCATION=${INSTALL_LOCATION:-'/usr/local/bin'} +function set_talisman_binary_name() { + TALISMAN_BINARY_NAME="talisman_$(operating_system)_$(architecture)" + if [ "$(operating_system)" = "windows" ]; then + TALISMAN_BINARY_NAME="$TALISMAN_BINARY_NAME.exe" + fi +} + +function download() { + OBJECT=$1 + DOWNLOAD_URL=$(curl -Ls https://api.github.com/repos/"$INSTALL_ORG_REPO"/releases/latest | + grep download_url | awk '{print $2}' | tr -d '"' | grep "$OBJECT") + + echo_debug "Downloading $OBJECT from $DOWNLOAD_URL" + curl --location --silent "$DOWNLOAD_URL" >"$TEMP_DIR/$OBJECT" +} +function verify_checksum() { + FILE_NAME=$1 + CHECKSUM_FILE_NAME='checksums' + echo_debug "Verifying checksum for $FILE_NAME" + download $CHECKSUM_FILE_NAME + + pushd "$TEMP_DIR" >/dev/null 2>&1 + + if ! command -v shasum &> /dev/null; then + sha256sum --ignore-missing -c $CHECKSUM_FILE_NAME + else + shasum -a 256 --ignore-missing -c $CHECKSUM_FILE_NAME + fi + popd >/dev/null 2>&1 + echo_debug "Checksum verification successfully!" + echo +} + +function download_talisman_binary() { + download "$TALISMAN_BINARY_NAME" + verify_checksum "$TALISMAN_BINARY_NAME" +} + +function install_talisman() { + if (touch "$INSTALL_LOCATION/talisman" &>/dev/null); then + cp "$TEMP_DIR/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/talisman" + chmod +x "$INSTALL_LOCATION/talisman" + elif (which sudo &>/dev/null); then + sudo cp "$TEMP_DIR/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/talisman" + sudo chmod +x "$INSTALL_LOCATION/talisman" + else + echo_error "Insufficient permission to install to $INSTALL_LOCATION" + exit 126 + fi +} + +function run() { TEMP_DIR=$(mktemp -d 2>/dev/null || mktemp -d -t 'talisman_setup') # shellcheck disable=SC2064 trap "rm -r $TEMP_DIR" EXIT chmod 0700 "$TEMP_DIR" - function echo_error() { - echo -ne "$(tput setaf 1)" >&2 - echo "$1" >&2 - echo -ne "$(tput sgr0)" >&2 - } - - function echo_debug() { - [[ -z "$DEBUG" ]] && return - echo -ne "$(tput setaf 3)" >&2 - echo "$1" >&2 - echo -ne "$(tput sgr0)" >&2 - } - - function echo_success() { - echo -ne "$(tput setaf 2)" - echo "$1" >&2 - echo -ne "$(tput sgr0)" - } - - function operating_system() { - OS=$(uname -s) - case $OS in - "Linux") - echo "linux" - ;; - "Darwin") - echo "darwin" - ;; - MINGW32_NT-*) - echo "windows" - ;; - MINGW64_NT-*) - echo "windows" - ;; - MSYS_NT-*) - echo "windows" - ;; - *) - echo_error "Talisman currently only supports Windows, Linux and MacOS(darwin) systems." - echo_error "If this is a problem for you, please open an issue: https://github.com/$INSTALL_ORG_REPO/issues/new" - exit $E_UNSUPPORTED_ARCH - ;; - esac - } - - function set_talisman_binary_name() { - # based on OS (linux/darwin) and ARCH(32/64 bit) - declare SUFFIX - SUFFIX=$(operating_system) - ARCH=$(uname -m) - case $ARCH in - "x86_64") - SUFFIX="${SUFFIX}_amd64" - ;; - "i686" | "i386") - SUFFIX="${SUFFIX}_386" - ;; - "arm64" | "aarch64") - SUFFIX="${SUFFIX}_arm64" - ;; - *) - echo_error "Talisman currently only supports x86 and x86_64 and arm64 architectures." - echo_error "If this is a problem for you, please open an issue: https://github.com/$INSTALL_ORG_REPO/issues/new" - exit $E_UNSUPPORTED_ARCH - ;; - esac - - TALISMAN_BINARY_NAME="talisman_$SUFFIX" - if [[ $SUFFIX == *"windows"* ]]; then - TALISMAN_BINARY_NAME="$TALISMAN_BINARY_NAME.exe" - fi - } - - function download() { - OBJECT=$1 - DOWNLOAD_URL=$(curl -Ls https://api.github.com/repos/"$INSTALL_ORG_REPO"/releases/latest | - grep download_url | awk '{print $2}' | tr -d '"' | grep "$OBJECT") - - echo_debug "Downloading $OBJECT from $DOWNLOAD_URL" - curl --location --silent "$DOWNLOAD_URL" >"$TEMP_DIR/$OBJECT" - } - - function verify_checksum() { - FILE_NAME=$1 - CHECKSUM_FILE_NAME='checksums' - echo_debug "Verifying checksum for $FILE_NAME" - download $CHECKSUM_FILE_NAME - - pushd "$TEMP_DIR" >/dev/null 2>&1 - - if ! command -v shasum &> /dev/null; then - sha256sum --ignore-missing -c $CHECKSUM_FILE_NAME - else - shasum -a 256 --ignore-missing -c $CHECKSUM_FILE_NAME - fi - popd >/dev/null 2>&1 - echo_debug "Checksum verification successfully!" - echo - } - - function download_talisman_binary() { - download "$TALISMAN_BINARY_NAME" - verify_checksum "$TALISMAN_BINARY_NAME" - } - - function setup_talisman() { - if (touch "$INSTALL_LOCATION/talisman" &>/dev/null); then - cp "$TEMP_DIR/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/talisman" - chmod +x "$INSTALL_LOCATION/talisman" - elif (which sudo &>/dev/null); then - sudo cp "$TEMP_DIR/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/talisman" - sudo chmod +x "$INSTALL_LOCATION/talisman" - else - echo_error "Insufficient permission to install to $INSTALL_LOCATION" - exit 126 - fi - } - if [ ! -d "$INSTALL_LOCATION" ]; then echo_error "$INSTALL_LOCATION is not a directory!" exit 1 fi set_talisman_binary_name - echo_success "Downloading talisman binary" download_talisman_binary - setup_talisman + install_talisman } run From f887cb9621078f872f6e5f77efce3c4692e8eb8e Mon Sep 17 00:00:00 2001 From: Owen Nelson Date: Fri, 12 Jan 2024 11:13:01 -0600 Subject: [PATCH 7/8] Retain fully binary name and link to "talisman" Authored-by: Owen Nelson --- install.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/install.sh b/install.sh index 0933e137..38fa3dba 100755 --- a/install.sh +++ b/install.sh @@ -108,12 +108,14 @@ function download_talisman_binary() { } function install_talisman() { - if (touch "$INSTALL_LOCATION/talisman" &>/dev/null); then - cp "$TEMP_DIR/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/talisman" - chmod +x "$INSTALL_LOCATION/talisman" + if (touch "$INSTALL_LOCATION/$TALISMAN_BINARY_NAME" &>/dev/null); then + cp "$TEMP_DIR/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/$TALISMAN_BINARY_NAME" + chmod +x "$INSTALL_LOCATION/$TALISMAN_BINARY_NAME" + ln -s "$INSTALL_LOCATION/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/talisman" elif (which sudo &>/dev/null); then - sudo cp "$TEMP_DIR/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/talisman" - sudo chmod +x "$INSTALL_LOCATION/talisman" + sudo cp "$TEMP_DIR/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/$TALISMAN_BINARY_NAME" + sudo chmod +x "$INSTALL_LOCATION/$TALISMAN_BINARY_NAME" + sudo ln -s "$INSTALL_LOCATION/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/talisman" else echo_error "Insufficient permission to install to $INSTALL_LOCATION" exit 126 From 35137d5da4095f3e449cf16c3dec90d0083cded7 Mon Sep 17 00:00:00 2001 From: Owen Nelson Date: Fri, 12 Jan 2024 15:17:45 -0600 Subject: [PATCH 8/8] Refactor methods to have matching levels of abstraction Authored-by: Owen Nelson --- README.md | 2 +- install.sh | 64 +++++++++++++++++++++++++----------------------------- 2 files changed, 31 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 8a023b38..c04af4f9 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ included in .pre-commit-config.yaml: ## Husky [husky](https://typicode.github.io/husky) is an npm module for managing hooks. -Add the following line to the husky pre-commit configuration in you +Add the following line to the husky pre-commit configuration in your `package.json`: ``` diff --git a/install.sh b/install.sh index 38fa3dba..dc1fb7b4 100755 --- a/install.sh +++ b/install.sh @@ -1,9 +1,11 @@ #!/bin/bash set -euo pipefail -declare TALISMAN_BINARY_NAME +declare BINARY_NAME E_UNSUPPORTED_ARCH=5 +CHECKSUM_FILE_NAME='checksums' + DEBUG=${DEBUG:-''} VERSION=${VERSION:-'latest'} INSTALL_ORG_REPO=${INSTALL_ORG_REPO:-'thoughtworks/talisman'} @@ -68,28 +70,27 @@ function architecture() { esac } -function set_talisman_binary_name() { - TALISMAN_BINARY_NAME="talisman_$(operating_system)_$(architecture)" +function set_binary_name() { + BINARY_NAME="talisman_$(operating_system)_$(architecture)" if [ "$(operating_system)" = "windows" ]; then - TALISMAN_BINARY_NAME="$TALISMAN_BINARY_NAME.exe" + BINARY_NAME="$BINARY_NAME.exe" fi + echo_success "Selected $BINARY_NAME" } function download() { - OBJECT=$1 - DOWNLOAD_URL=$(curl -Ls https://api.github.com/repos/"$INSTALL_ORG_REPO"/releases/latest | - grep download_url | awk '{print $2}' | tr -d '"' | grep "$OBJECT") - - echo_debug "Downloading $OBJECT from $DOWNLOAD_URL" - curl --location --silent "$DOWNLOAD_URL" >"$TEMP_DIR/$OBJECT" + ASSETS=$(curl -Ls https://api.github.com/repos/"$INSTALL_ORG_REPO"/releases/latest | + grep download_url | awk '{print $2}' | tr -d '"') + BINARY_URL=$(echo "$ASSETS" | grep "$BINARY_NAME") + CHECKSUM_URL=$(echo "$ASSETS" | grep $CHECKSUM_FILE_NAME) + echo_debug "Downloading $BINARY_NAME and from $BINARY_URL" + curl --location --silent "$BINARY_URL" >"$TEMP_DIR/$BINARY_NAME" + echo_debug "Downloading $CHECKSUM_FILE_NAME and from $CHECKSUM_URL" + curl --location --silent "$CHECKSUM_URL" >"$TEMP_DIR/$CHECKSUM_FILE_NAME" + echo_success "Downloaded talisman binary and checksums" } function verify_checksum() { - FILE_NAME=$1 - CHECKSUM_FILE_NAME='checksums' - echo_debug "Verifying checksum for $FILE_NAME" - download $CHECKSUM_FILE_NAME - pushd "$TEMP_DIR" >/dev/null 2>&1 if ! command -v shasum &> /dev/null; then @@ -97,25 +98,20 @@ function verify_checksum() { else shasum -a 256 --ignore-missing -c $CHECKSUM_FILE_NAME fi - popd >/dev/null 2>&1 - echo_debug "Checksum verification successfully!" - echo -} -function download_talisman_binary() { - download "$TALISMAN_BINARY_NAME" - verify_checksum "$TALISMAN_BINARY_NAME" + popd >/dev/null 2>&1 + echo_success "Checksum OK" } -function install_talisman() { - if (touch "$INSTALL_LOCATION/$TALISMAN_BINARY_NAME" &>/dev/null); then - cp "$TEMP_DIR/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/$TALISMAN_BINARY_NAME" - chmod +x "$INSTALL_LOCATION/$TALISMAN_BINARY_NAME" - ln -s "$INSTALL_LOCATION/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/talisman" +function install() { + if (touch "$INSTALL_LOCATION/$BINARY_NAME" &>/dev/null); then + cp "$TEMP_DIR/$BINARY_NAME" "$INSTALL_LOCATION/$BINARY_NAME" + chmod +x "$INSTALL_LOCATION/$BINARY_NAME" + ln -s "$INSTALL_LOCATION/$BINARY_NAME" "$INSTALL_LOCATION/talisman" elif (which sudo &>/dev/null); then - sudo cp "$TEMP_DIR/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/$TALISMAN_BINARY_NAME" - sudo chmod +x "$INSTALL_LOCATION/$TALISMAN_BINARY_NAME" - sudo ln -s "$INSTALL_LOCATION/$TALISMAN_BINARY_NAME" "$INSTALL_LOCATION/talisman" + sudo cp "$TEMP_DIR/$BINARY_NAME" "$INSTALL_LOCATION/$BINARY_NAME" + sudo chmod +x "$INSTALL_LOCATION/$BINARY_NAME" + sudo ln -s "$INSTALL_LOCATION/$BINARY_NAME" "$INSTALL_LOCATION/talisman" else echo_error "Insufficient permission to install to $INSTALL_LOCATION" exit 126 @@ -133,10 +129,10 @@ function run() { exit 1 fi - set_talisman_binary_name - echo_success "Downloading talisman binary" - download_talisman_binary - install_talisman + set_binary_name + download + verify_checksum + install } run