Created
March 2, 2023 21:37
-
-
Save drgsn/900559fc321b43d4a7ea14a8f4345c71 to your computer and use it in GitHub Desktop.
[git secrets install] install git secrets and do a basic config
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
pretty_print() { | |
# BLACK=$(tput setaf 0) | |
# RED=$(tput setaf 1) | |
# GREEN=$(tput setaf 2) | |
# YELLOW=$(tput setaf 3) | |
# LIME_YELLOW=$(tput setaf 190) | |
# POWDER_BLUE=$(tput setaf 153) | |
# BLUE=$(tput setaf 4) | |
# MAGENTA=$(tput setaf 5) | |
# CYAN=$(tput setaf 6) | |
# WHITE=$(tput setaf 7) | |
# BRIGHT=$(tput bold) | |
# NORMAL=$(tput sgr0) | |
# BLINK=$(tput blink) | |
# REVERSE=$(tput smso) | |
# UNDERLINE=$(tput smul) | |
printf "\n%b\n" "$1" | |
} | |
function info() { | |
pretty_print "$(date) INFO: $1" | |
} | |
function error() { | |
local RED=$(tput setaf 1) | |
local NORMAL=$(tput sgr0) | |
pretty_print "$(date): ${RED}ERR: ${NORMAL} $1" >&2 | |
} | |
function halt() { | |
pretty_print "$(date) HALT: $1" >&2 | |
error "$1" | |
exit 1 | |
} | |
function updateSystem() { | |
if [[ $1 == $MAC_OS ]]; then | |
# check if homebrew is installed and install if not or update if it is. | |
homebrewInstall | |
elif [[ $1 == "$LINUX" ]]; then | |
info "Updating system..." | |
sudo apt-get update | |
sudo apt-get upgrade -y | |
else | |
halt "$UNSUPPORTED_OS" | |
fi | |
} | |
function homebrewInstall() { | |
if ! command -v brew &>/dev/null; then | |
info "Installing Homebrew, an OSX package manager, follow the instructions..." | |
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" | |
if ! grep -qs "recommended by brew doctor" ~/.zshrc; then | |
pretty_print "Put Homebrew location earlier in PATH ..." | |
printf '\n# recommended by brew doctor\n' >>~/.zshrc | |
printf 'export PATH="/usr/local/bin:$PATH"\n' >>~/.zshrc | |
export PATH="/usr/local/bin:$PATH" | |
fi | |
else | |
info "Updating Homebrew..." | |
brew update | |
info "Upgrading Homebrew..." | |
brew upgrade | |
fi | |
} | |
function checkAndInstallPackage() { | |
local successMessage="$2 is installed..." | |
local errorMessage="$2 is not installed. Installing it now!" | |
if [[ $1 == "$MAC_OS" ]]; then | |
if [[ $(brew list | grep $2) ]]; then | |
info "$successMessage" | |
else | |
info "$errorMessage" | |
installPackage $1 $2 | |
fi | |
elif [[ $1 == "$LINUX" ]]; then | |
if [[ $(dpkg -l | grep $2) ]]; then | |
info "$successMessage" | |
else | |
info "$errorMessage" | |
installPackage $1 $2 | |
fi | |
else | |
halt "$UNSUPPORTED_OS" | |
fi | |
} | |
function installPackage() { | |
info "Installing $2" | |
if [[ $1 == "$MAC_OS" ]]; then | |
brew install $2 | |
elif [[ $1 == "$LINUX" ]]; then | |
sudo apt-get install -y $2 | |
else | |
halt "$UNSUPPORTED_OS" | |
fi | |
} | |
function install_git_hook() { | |
cd "$1" || exit | |
git secrets --install | |
} | |
function register_rules() { | |
# $1 = Path to git repo | |
# $2 = Selected rules | |
# $3 = Available rules | |
local path=$1 | |
IFS=' ' read -ra selected <<<"${2}" | |
IFS=' ' read -ra options <<<"${3}" | |
cd "$path" || exit | |
for i in "${!selected[@]}"; do | |
if [ "${selected[$i]}" == "true" ]; then | |
info "Trying to register rule: ${options[$i]}" | |
case "${options[$i]}" in | |
AWS*) register_aws_rule ;; | |
GENERIC_PASSWORD*) register_generic_password_rule ;; | |
GCP_API_KEY*) register_gcp_api_key_rule ;; | |
SSH_KEY*) register_ssh_key_rule ;; | |
*) error "no handler defined for ${options[$i]}" ;; | |
esac | |
fi | |
done | |
} | |
function register_aws_rule() { | |
# Adds common AWS patterns to the git config and ensures that keys present | |
# in ~/.aws/credentials are not found in any commit. The following checks are added: | |
# | |
# AWS Access Key IDs via (A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16} | |
# AWS Secret Access Key assignments via ":" or "=" surrounded by optional quotes | |
# AWS account ID assignments via ":" or "=" surrounded by optional quotes | |
# Allowed patterns for example AWS keys (AKIAIOSFODNN7EXAMPLE and wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY) | |
# Known credentials from ~/.aws/credentials | |
git secrets --register-aws | |
info "AWS rule added" | |
} | |
function register_generic_password_rule() { | |
local pattern="'password\s*=\s*.+'" | |
git secrets --add "$pattern" | |
info "Password rule added" | |
} | |
function register_gcp_api_key_rule() { | |
local pattern="AIza[0-9A-Za-z\\-_]{35}" | |
git secrets --add "$pattern" | |
info "Password GCP API Key added" | |
} | |
function register_ssh_key_rule() { | |
local pattern1="-----BEGIN RSA PRIVATE KEY-----" | |
local pattern2="-----BEGIN DSA PRIVATE KEY-----" | |
local pattern3="-----BEGIN EC PRIVATE KEY-----" | |
local pattern4="-----BEGIN PGP PRIVATE KEY BLOCK-----" | |
git secrets --add "$pattern1" | |
git secrets --add "$pattern2" | |
git secrets --add "$pattern3" | |
git secrets --add "$pattern4" | |
info "SSH Key rule added" | |
} | |
function scan_history() { | |
cd "$1" || exit | |
git secrets --scan-history | |
} | |
function detect_os() { | |
unameOut="$(uname -s)" | |
case "${unameOut}" in | |
Linux*) machine=Linux ;; | |
Darwin*) machine=Mac ;; | |
CYGWIN*) machine=Cygwin ;; | |
MINGW*) machine=MinGw ;; | |
*) machine="UNKNOWN:${unameOut}" ;; | |
esac | |
info "Detected OS: $machine" | |
} | |
function project_path() { | |
info "provided path $1" | |
if [[ "$1" && -d "$1/.git" ]]; then | |
info "Using project path: $1" | |
PROJECT_PATH=$1 | |
elif [ "$1" ]; then | |
info "Provided path is not a git project: $1" | |
project_path | |
else | |
read -r -p "Please enter git project path:" r1 | |
if [[ -d $r1 && -d "$r1/.git" ]]; then | |
info "Installing git-secrets for $r1" | |
PROJECT_PATH=$r1 | |
elif [[ -d $r1 ]]; then | |
error "$r1 is not a git repository" | |
project_path | |
else | |
error "$r1 is not a valid path" | |
project_path | |
fi | |
fi | |
} | |
function parse_args() { | |
# https://unix.stackexchange.com/questions/129391/passing-named-arguments-to-shell-scripts | |
while getopts ":p:" opt; do | |
case $opt in | |
p) | |
# info "Using project path: $OPTARG" | |
PROJECT_PATH="$OPTARG" | |
;; | |
\?) | |
error "Invalid option -$OPTARG will prompt for project path!" | |
# exit 1 # uncomment this line to exit if invalid option is passed. for the moment this is non fatal. | |
;; | |
esac | |
case $OPTARG in | |
-*) | |
error "Option $opt needs a valid argument" | |
# exit 1 # uncomment this line to exit if invalid option is passed. for the moment this is non fatal. | |
;; | |
esac | |
done | |
} | |
function main() { | |
# ===== vars ===== | |
MAC_OS="Mac" | |
LINUX="Linux" | |
UNSUPPORTED_OS="Unsupported OS" | |
local OPTIONS=("AWS" "GENERIC_PASSWORD" "GCP_API_KEY") | |
local OPTIONS_STRING=$( | |
IFS=';' | |
echo "${OPTIONS[*]}" | |
) | |
error "OPTIONS_STRING: $OPTIONS_STRING" | |
# ===== parse cmd args ===== | |
parse_args "$@" | |
# ===== detect os ===== | |
detect_os | |
# ===== check if supported os ===== | |
if [[ $machine != "$MAC_OS" && $machine != "$LINUX" ]]; then | |
halt "OS is not supported" | |
fi | |
# ===== check if git project else get path ===== | |
project_path "$PROJECT_PATH" | |
# ===== update system ===== | |
updateSystem "$machine" | |
# ===== install git secrets ===== | |
info "Installing git-secrets for $PROJECT_PATH" | |
checkAndInstallPackage "$machine" "git-secrets" | |
prompt_for_multiselect SELECTED "$OPTIONS_STRING" | |
# ===== install git hook ===== | |
install_git_hook "$PROJECT_PATH" | |
# ===== register aws rule ===== | |
register_rules "$PROJECT_PATH" "${SELECTED[*]}" "${OPTIONS[*]}" | |
# ===== scan repo history ===== | |
scan_history "$PROJECT_PATH" | |
info "For more info checkout https://github.com/awslabs/git-secrets#options-for-add-provider" | |
info "todo: https://gist.github.com/tehryanx/44657fcad0b97589d99ea3b282e411e7" | |
info "todo: https://github.com/odomojuli/RegExAPI" | |
info "https://github.com/zricethezav/gitleaks/blob/master/config/gitleaks.toml" | |
} | |
function prompt_for_multiselect { | |
echo "Navigate using ARROWS" | |
echo "Use SPACE to select" | |
echo "Use ENTER to finish" | |
# little helpers for terminal print control and key input | |
GREEN='\033[00;32m' | |
YELLOW='\033[00;33m' | |
RESTORE='\033[0m' | |
ESC=$(printf "\033") | |
# shellcheck disable=SC2059 | |
# shellcheck disable=SC1087 | |
cursor_blink_on() { printf "$ESC[?25h"; } | |
# shellcheck disable=SC2059 | |
# shellcheck disable=SC1087 | |
cursor_blink_off() { printf "$ESC[?25l"; } | |
# shellcheck disable=SC2059 | |
# shellcheck disable=SC1087 | |
cursor_to() { printf "$ESC[$1;${2:-1}H"; } | |
# shellcheck disable=SC2059 | |
# shellcheck disable=SC1087 | |
print_inactive() { printf "$2 $1 $RESTORE"; } | |
# shellcheck disable=SC2059 | |
# shellcheck disable=SC1087 | |
print_active() { printf "$YELLOW$2 $ESC[7m $1 $RESTORE$ESC[27m"; } | |
get_cursor_row() { | |
# shellcheck disable=SC2162 | |
IFS=';' read -sdR -p $'\E[6n' ROW COL | |
echo "${ROW#*[}" | |
} | |
key_input() { | |
local key | |
IFS= read -rsn1 key 2>/dev/null >&2 | |
if [[ $key = "" ]]; then echo enter; fi | |
if [[ $key = $'\x20' ]]; then echo space; fi | |
if [[ $key = $'\x1b' ]]; then | |
read -rsn2 key | |
if [[ $key = [A ]]; then echo up; fi | |
if [[ $key = [B ]]; then echo down; fi | |
fi | |
} | |
toggle_option() { | |
local arr_name=$1 | |
eval "local arr=(\"\${${arr_name}[@]}\")" | |
local option=$2 | |
if [[ ${arr[option]} == true ]]; then | |
arr[option]= | |
else | |
arr[option]=true | |
fi | |
eval $arr_name='("${arr[@]}")' | |
} | |
local retval=$1 | |
local options | |
local defaults | |
IFS=';' read -r -a options <<<"$2" | |
if [[ -z $3 ]]; then | |
defaults=() | |
else | |
IFS=';' read -r -a defaults <<<"$3" | |
fi | |
local selected=() | |
for ((i = 0; i < ${#options[@]}; i++)); do | |
selected+=("${defaults[i]:-false}") | |
printf "\n" | |
done | |
# determine current screen position for overwriting the options | |
local lastrow=$(get_cursor_row) | |
local startrow=$(($lastrow - ${#options[@]})) | |
# ensure cursor and input echoing back on upon a ctrl+c during read -s | |
trap "cursor_blink_on; stty echo; printf '\n'; exit" 2 | |
cursor_blink_off | |
local active=0 | |
while true; do | |
# print options by overwriting the last lines | |
local idx=0 | |
for option in "${options[@]}"; do | |
local prefix="$RESET ◻︎" | |
if [[ ${selected[idx]} == true ]]; then | |
prefix="$GREEN ◼︎" | |
fi | |
cursor_to $(($startrow + $idx)) | |
if [ $idx -eq $active ]; then | |
print_active "$option" "$prefix" | |
else | |
print_inactive "$option" "$prefix" | |
fi | |
((idx++)) | |
done | |
# user key control | |
case $(key_input) in | |
space) toggle_option selected $active ;; | |
enter) break ;; | |
up) | |
((active--)) | |
if [ $active -lt 0 ]; then active=$((${#options[@]} - 1)); fi | |
;; | |
down) | |
((active++)) | |
if [ $active -ge ${#options[@]} ]; then active=0; fi | |
;; | |
esac | |
done | |
# cursor position back to normal | |
cursor_to $lastrow | |
printf "\n" | |
cursor_blink_on | |
eval $retval='("${selected[@]}")' | |
} | |
# running main function | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment