mirror of
https://github.com/sobolevn/git-secret
synced 2024-10-31 21:20:29 +00:00
549cd9aa24
* check for encrypted version of file before decrypting, for #706 * improve error messages, verbose output and non-verbose output * in tests, prefix output from git init with 'git: ' * 'clean' options only remove added files, for #833 * update changelog
364 lines
10 KiB
Bash
364 lines
10 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# This file is following a name convention defined in:
|
|
# https://github.com/bats-core/bats-core
|
|
|
|
# shellcheck disable=SC1090
|
|
source "$SECRETS_PROJECT_ROOT/src/version.sh"
|
|
# shellcheck disable=SC1090
|
|
source "$SECRETS_PROJECT_ROOT/src/_utils/_git_secret_tools.sh"
|
|
source "$SECRETS_PROJECT_ROOT/src/_utils/_git_secret_tools_freebsd.sh"
|
|
source "$SECRETS_PROJECT_ROOT/src/_utils/_git_secret_tools_linux.sh"
|
|
source "$SECRETS_PROJECT_ROOT/src/_utils/_git_secret_tools_osx.sh"
|
|
|
|
# Constants:
|
|
FIXTURES_DIR="$BATS_TEST_DIRNAME/fixtures"
|
|
|
|
TEST_GPG_HOMEDIR="$BATS_TMPDIR"
|
|
|
|
# TODO: factor out tempdir creation.
|
|
# On osx TEST_OUTPUT_FILE, still has 'XXXXXX's, like
|
|
# /var/folders/mm/_f0j67x10l92b4zznyx4ylzh00017w/T/gitsecret_output.XXXXXX.RaqyGYqL
|
|
TEST_OUTPUT_FILE=$(
|
|
TMPDIR="$BATS_TMPDIR" mktemp -t 'gitsecret_output.XXXXXX'
|
|
)
|
|
|
|
|
|
# shellcheck disable=SC2016
|
|
AWK_GPG_GET_FP='
|
|
BEGIN { OFS=":"; FS=":"; }
|
|
{
|
|
if ( $1 == "fpr" )
|
|
{
|
|
print $10
|
|
exit
|
|
}
|
|
}
|
|
'
|
|
|
|
# git >= 2.28.0 supports --initial-branch=main
|
|
function is_git_version_ge_2_28_0 { # based on code from github autopilot
|
|
# shellcheck disable=SC2155
|
|
local git_version=$(git --version | awk '{print $3}')
|
|
# shellcheck disable=SC2155
|
|
local git_version_major=$(echo "$git_version" | awk -F. '{print $1}')
|
|
# shellcheck disable=SC2155
|
|
local git_version_minor=$(echo "$git_version" | awk -F. '{print $2}')
|
|
# shellcheck disable=SC2155
|
|
local git_version_patch=$(echo "$git_version" | awk -F. '{print $3}')
|
|
if [[ "$git_version_major" -ge 2 ]] && [[ "$git_version_minor" -ge 28 ]] && [[ "$git_version_patch" -ge 0 ]]; then
|
|
echo 0
|
|
else
|
|
echo 1
|
|
fi
|
|
}
|
|
|
|
# GPG-based stuff:
|
|
: "${SECRETS_GPG_COMMAND:='gpg'}"
|
|
|
|
# This command is used with absolute homedir set and disabled warnings:
|
|
GPGTEST="$SECRETS_GPG_COMMAND --homedir=$TEST_GPG_HOMEDIR --no-permission-warning --batch"
|
|
|
|
# Test key fixture data. Fixtures are at tests/fixtures/gpg/$email
|
|
|
|
# See tests/fixtures/gpg/README.md for more
|
|
# on key fixtures 'user[1-5]@gitsecret.io'
|
|
# these two are 'normal' keys.
|
|
export TEST_DEFAULT_USER='user1@gitsecret.io'
|
|
export TEST_SECOND_USER='user2@gitsecret.io'
|
|
|
|
# TEST_NONAME_USER (user3) created with '--quick-key-generate'
|
|
# and has only an email, no username.
|
|
export TEST_NONAME_USER='user3@gitsecret.io'
|
|
|
|
# TEST_EXPIRED_USER (user4) has expired
|
|
export TEST_EXPIRED_USER='user4@gitsecret.io' # this key expires 2018-09-24
|
|
|
|
# fixture filename is named this,
|
|
# but key has no email and a comment, as per #527
|
|
export TEST_NOEMAIL_COMMENT_USER='user5@gitsecret.io'
|
|
|
|
export TEST_ATTACKER_USER='attacker1@gitsecret.io'
|
|
|
|
|
|
export TEST_DEFAULT_FILENAME='space file' # has spaces
|
|
export TEST_SECOND_FILENAME='space file two' # has spaces
|
|
export TEST_THIRD_FILENAME='space file three' # has spaces
|
|
export TEST_FOURTH_FILENAME='space file three [] * $' # has spaces and special chars
|
|
|
|
|
|
function test_user_password {
|
|
# Password for 'user3@gitsecret.io' is 'user3pass'
|
|
# As it was set on key creation.
|
|
# shellcheck disable=SC2001
|
|
echo "$1" | sed -e 's/@.*/pass/'
|
|
}
|
|
|
|
|
|
# Files:
|
|
|
|
function file_has_line {
|
|
# First parameter is the key, second is the filename.
|
|
|
|
local line="$1" # required
|
|
local filename="$2" # required
|
|
|
|
local exit_code
|
|
# -F means 'Interpret PATTERN as a list of fixed strings' (not regexen)
|
|
# -x means 'Select only those matches that exactly match the whole line'
|
|
exit_code=$(grep -Fx "$line" "$filename" 2>&1 > /dev/null; echo $?)
|
|
|
|
# 0 means contains, 1 means not contains, and probably >1 for errors.
|
|
echo "$exit_code"
|
|
}
|
|
|
|
|
|
# GPG:
|
|
|
|
function stop_gpg_agent {
|
|
local username
|
|
username=$(id -u -n)
|
|
if [[ "$SECRETS_DOCKER_ENV" == 'windows' ]]; then
|
|
ps -l -u "$username" | gawk \
|
|
'/gpg-agent/ { if ( $0 !~ "awk" ) { system("kill "$1) } }' >> "$TEST_OUTPUT_FILE" 2>&1
|
|
else
|
|
local ps_is_busybox
|
|
ps_is_busybox=_exe_is_busybox 'ps'
|
|
if [[ $ps_is_busybox -eq '1' ]]; then
|
|
echo '# git-secret: tests: not stopping gpg-agent on busybox' >&3
|
|
else
|
|
ps -wx -U "$username" | gawk \
|
|
'/gpg-agent --homedir/ { if ( $0 !~ "awk" ) { system("kill "$1) } }' >> "$TEST_OUTPUT_FILE" 2>&1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
|
|
function get_gpgtest_prefix {
|
|
if [[ $GPG_VER_21 -eq 1 ]]; then
|
|
# shellcheck disable=SC2086
|
|
echo "echo \"$(test_user_password $1)\" | "
|
|
else
|
|
echo ''
|
|
fi
|
|
}
|
|
|
|
|
|
function get_gpg_fingerprint_by_email {
|
|
local email="$1"
|
|
local fingerprint
|
|
|
|
fingerprint=$($GPGTEST --with-fingerprint \
|
|
--with-colon \
|
|
--list-secret-key "$email" | gawk "$AWK_GPG_GET_FP")
|
|
echo "$fingerprint"
|
|
}
|
|
|
|
|
|
function install_fixture_key {
|
|
local public_key="$BATS_TMPDIR/public-${1}.key"
|
|
|
|
cp "$FIXTURES_DIR/gpg/${1}/public.key" "$public_key"
|
|
$GPGTEST --import "$public_key" >> "$TEST_OUTPUT_FILE" 2>&1
|
|
rm -f "$public_key" || _abort "Couldn't delete public key: $public_key"
|
|
}
|
|
|
|
|
|
function install_fixture_full_key {
|
|
local private_key="$BATS_TMPDIR/private-${1}.key"
|
|
local gpgtest_prefix
|
|
gpgtest_prefix=$(get_gpgtest_prefix "$1")
|
|
local gpgtest_import="$gpgtest_prefix $GPGTEST"
|
|
local email
|
|
local fingerprint
|
|
|
|
email="$1"
|
|
|
|
cp "$FIXTURES_DIR/gpg/${1}/private.key" "$private_key"
|
|
|
|
bash -c "$gpgtest_import --allow-secret-key-import \
|
|
--import \"$private_key\"" >> "${TEST_OUTPUT_FILE}" 2>&1
|
|
|
|
# since 0.1.2 fingerprint is returned:
|
|
fingerprint=$(get_gpg_fingerprint_by_email "$email")
|
|
|
|
install_fixture_key "$1"
|
|
|
|
rm -f "$private_key" || _abort "Couldn't delete private key: $private_key"
|
|
# return fingerprint to delete it later:
|
|
echo "$fingerprint"
|
|
}
|
|
|
|
|
|
function uninstall_fixture_key {
|
|
local email
|
|
|
|
email="$1"
|
|
$GPGTEST --yes --delete-key "$email" >> "$TEST_OUTPUT_FILE" 2>&1
|
|
}
|
|
|
|
|
|
function uninstall_fixture_full_key {
|
|
local email
|
|
email="$1"
|
|
|
|
local fingerprint="$2"
|
|
if [[ -z "$fingerprint" ]]; then
|
|
# see issue_12, fingerprint on `gpg2` has different format:
|
|
fingerprint=$(get_gpg_fingerprint_by_email "$email")
|
|
fi
|
|
|
|
$GPGTEST --yes --delete-secret-keys "$fingerprint" >> "$TEST_OUTPUT_FILE" 2>&1
|
|
|
|
uninstall_fixture_key "$1"
|
|
}
|
|
|
|
|
|
# Git:
|
|
|
|
function git_set_config_email {
|
|
git config --local user.email "$1"
|
|
}
|
|
|
|
|
|
function git_commit {
|
|
git_set_config_email "$1"
|
|
|
|
local user_name
|
|
local commit_gpgsign
|
|
|
|
user_name=$(git config user.name)
|
|
|
|
commit_gpgsign=$(git config commit.gpgsign)
|
|
|
|
git config --local user.name "$TEST_DEFAULT_USER"
|
|
git config --local commit.gpgsign false
|
|
|
|
git add --all
|
|
git commit -m "$2"
|
|
|
|
git config --local user.name "$user_name"
|
|
git config --local commit.gpgsign "$commit_gpgsign"
|
|
}
|
|
|
|
|
|
function remove_git_repository {
|
|
rm -rf ".git"
|
|
}
|
|
|
|
|
|
# Git Secret:
|
|
|
|
function set_state_initial {
|
|
cd "$BATS_TMPDIR" || exit 1
|
|
rm -rf "${BATS_TMPDIR:?}/*"
|
|
}
|
|
|
|
|
|
function set_state_git {
|
|
local has_initial_branch_option
|
|
has_initial_branch_option=$(is_git_version_ge_2_28_0) # 0 for true
|
|
if [[ "$has_initial_branch_option" == 0 ]]; then
|
|
git init --initial-branch=main | sed 's/^/git: /' >> "$TEST_OUTPUT_FILE" 2>&1
|
|
else
|
|
git init | sed 's/^/git: /' >> "$TEST_OUTPUT_FILE" 2>&1
|
|
fi
|
|
}
|
|
|
|
|
|
function set_state_secret_init {
|
|
git secret init >> "$TEST_OUTPUT_FILE" 2>&1
|
|
}
|
|
|
|
|
|
function set_state_secret_tell {
|
|
local email
|
|
|
|
email="$1"
|
|
git secret tell -d "$TEST_GPG_HOMEDIR" "$email" >> "$TEST_OUTPUT_FILE" 2>&1
|
|
}
|
|
|
|
|
|
function set_state_secret_add {
|
|
local filename="$1"
|
|
local content="$2"
|
|
echo "$content" > "$filename" # we add a newline
|
|
|
|
git secret add "$filename" >> "$TEST_OUTPUT_FILE" 2>&1
|
|
}
|
|
|
|
function set_state_secret_add_without_newline {
|
|
local filename="$1"
|
|
local content="$2"
|
|
echo -n "$content" > "$filename" # we do not add a newline
|
|
|
|
git secret add "$filename" >> "$TEST_OUTPUT_FILE" 2>&1
|
|
}
|
|
|
|
|
|
function set_state_secret_hide {
|
|
local armor="$1"
|
|
SECRETS_GPG_ARMOR="$armor" git secret hide >> "$TEST_OUTPUT_FILE" 2>&1
|
|
}
|
|
|
|
|
|
function unset_current_state {
|
|
# states order:
|
|
# initial, git, secret_init, secret_tell, secret_add, secret_hide
|
|
|
|
# unsets `secret_hide`
|
|
# removes .secret files:
|
|
git secret clean >> "$TEST_OUTPUT_FILE" 2>&1
|
|
|
|
# unsets `secret_add`, `secret_tell` and `secret_init` by removing $_SECRETS_DIR
|
|
local secrets_dir
|
|
secrets_dir=$(_get_secrets_dir)
|
|
|
|
rm -rf "$secrets_dir"
|
|
rm -rf '.gitignore'
|
|
|
|
# unsets `git` state
|
|
remove_git_repository
|
|
|
|
# stop gpg-agent
|
|
stop_gpg_agent
|
|
|
|
# SECRETS_TEST_VERBOSE is experimental
|
|
if [[ "$SECRETS_TEST_VERBOSE" == 1 ]]; then
|
|
# display the captured output as bats diagnostic (fd3, preceded by '# ')
|
|
sed "s/^/# $BATS_TEST_DESCRIPTION: VERBOSE OUTPUT: /" < "$TEST_OUTPUT_FILE" >&3
|
|
|
|
# display the last $output
|
|
# shellcheck disable=SC2001,SC2154
|
|
echo "$output" | sed "s/^/# $BATS_TEST_DESCRIPTION: FINAL OUTPUT: /" >&3
|
|
fi
|
|
|
|
rm -f "$TEST_OUTPUT_FILE"
|
|
|
|
# new code to remove temporary gpg homedir artifacts.
|
|
# For #360, 'find and rm only relevant files when test fails'.
|
|
# ${VAR:?} will cause command to fail if VAR is 0 length, as per shellcheck SC2115
|
|
rm -vrf "${TEST_GPG_HOMEDIR:?}/private-keys*" 2>&1 | sed 's/^/# unset_current_state: rm /'
|
|
rm -vrf "${TEST_GPG_HOMEDIR:?}/*.kbx" 2>&1 | sed 's/^/# unset_current_state: rm /'
|
|
rm -vrf "${TEST_GPG_HOMEDIR:?}/*.kbx~" 2>&1 | sed 's/^/# unset_current_state: rm /'
|
|
rm -vrf "${TEST_GPG_HOMEDIR:?}/*.gpg" 2>&1 | sed 's/^/# unset_current_state: rm /'
|
|
rm -vrf "${TEST_GPG_HOMEDIR:?}/${TEST_DEFAULT_FILENAME}" 2>&1 | sed 's/^/# unset_current_state: rm /'
|
|
rm -vrf "${TEST_GPG_HOMEDIR:?}/${TEST_SECOND_FILENAME}" 2>&1 | sed 's/^/# unset_current_state: rm /'
|
|
rm -vrf "${TEST_GPG_HOMEDIR:?}/${TEST_THIRD_FILENAME}" 2>&1 | sed 's/^/# unset_current_state: rm /'
|
|
rm -vrf "${TEST_GPG_HOMEDIR:?}/${TEST_FOURTH_FILENAME}" 2>&1 | sed 's/^/# unset_current_state: rm /'
|
|
|
|
# return to the base dir:
|
|
cd "$SECRETS_PROJECT_ROOT" || exit 1
|
|
}
|
|
|
|
# show output if we wind up manually removing the test output file in a trap
|
|
trap 'if [[ -f "$TEST_OUTPUT_FILE" ]]; then if [[ "$SECRETS_TEST_VERBOSE" == 1 ]]; then echo "git-secret: test: cleaning up: $TEST_OUTPUT_FILE"; fi; rm -f "$TEST_OUTPUT_FILE"; fi;' EXIT
|
|
|
|
function bats_diag_file {
|
|
local filename=$1
|
|
|
|
echo "# DEBUG: begin contents: $filename" >&3
|
|
sed -e 's/^/# DEBUG: /' < "$filename" >&3
|
|
echo "# DEBUG: end contents: $filename" >&3
|
|
}
|