Skip to content

Commit

Permalink
Added unit tests for ssh key setup. (#1235)
Browse files Browse the repository at this point in the history
  • Loading branch information
richardgaunt authored Mar 25, 2024
1 parent b0bdb60 commit 29ef4a2
Show file tree
Hide file tree
Showing 3 changed files with 315 additions and 0 deletions.
26 changes: 26 additions & 0 deletions .scaffold/tests/bats/_helper.deployment.bash
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,29 @@ install_and_build_site() {

popd >/dev/null || exit 1
}

setup_ssh_key_fixture() {
# Create a fixture directory for ssh keys
export HOME="${BUILD_DIR}"
export SSH_KEY_FIXTURE_DIR="${BUILD_DIR}/.ssh"
fixture_prepare_dir "${SSH_KEY_FIXTURE_DIR}"
}

setup_robo_fixture() {
export HOME="${BUILD_DIR}"
fixture_prepare_dir "${HOME}/.composer/vendor/bin"
touch "${HOME}/.composer/vendor/bin/robo"
chmod +x "${HOME}/.composer/vendor/bin/robo"
}

provision_default_ssh_key() {
# Generate fixture keys.
ssh-keygen -t rsa -b 4096 -N "" -f "${SSH_KEY_FIXTURE_DIR}/id_rsa"
# Generate SSH key with TEST suffix.
ssh-keygen -t rsa -b 4096 -N "" -f "${SSH_KEY_FIXTURE_DIR}/id_rsa_TEST"
}

provision_ssh_key_with_suffix() {
local suffix="${1:-TEST}"
ssh-keygen -t rsa -b 4096 -N "" -f "${SSH_KEY_FIXTURE_DIR}/id_rsa_${suffix}"
}
92 changes: 92 additions & 0 deletions .scaffold/tests/bats/deployment-artifact.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/usr/bin/env bats
#
# Test for CircleCI lifecycle.
#
# shellcheck disable=SC2030,SC2031,SC2129,SC2155

load _helper.bash
load _helper.deployment.bash

@test "Missing or Invalid DREVOPS_DEPLOY_TYPES" {
substep "Swap to ${LOCAL_REPO_DIR}"
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

export DREVOPS_DEPLOY_TYPES=""
run ahoy deploy
assert_failure

assert_output_contains "Missing required value for DREVOPS_DEPLOY_TYPES. Must be a combination of comma-separated values (to support multiple deployments): code, docker, webhook, lagoon."

popd >/dev/null
}

@test "Check setting and default values for required variables" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

# Note the following variables have default values
# so the check for empty string is redundant:
# - DREVOPS_DEPLOY_ARTIFACT_GIT_USER_NAME
# - DREVOPS_DEPLOY_ARTIFACT_ROOT
# - DREVOPS_DEPLOY_ARTIFACT_REPORT_FILE

unset DREVOPS_DEPLOY_ARTIFACT_GIT_REMOTE
unset DREVOPS_DEPLOY_ARTIFACT_DST_BRANCH
unset DREVOPS_DEPLOY_ARTIFACT_SRC
unset DREVOPS_DEPLOY_ARTIFACT_ROOT
unset DREVOPS_DEPLOY_ARTIFACT_REPORT_FILE
run scripts/drevops/deploy-artifact.sh
assert_failure
assert_output_contains "Missing required value for DREVOPS_DEPLOY_ARTIFACT_GIT_REMOTE."
export DREVOPS_DEPLOY_ARTIFACT_GIT_REMOTE="[email protected]:yourorg/your-repo-destination.git"
run scripts/drevops/deploy-artifact.sh
assert_failure
assert_output_contains "Missing required value for DREVOPS_DEPLOY_ARTIFACT_SRC."
export DREVOPS_DEPLOY_ARTIFACT_SRC="dist"
run scripts/drevops/deploy-artifact.sh
assert_failure
assert_output_contains "Missing required value for DREVOPS_DEPLOY_ARTIFACT_GIT_USER_EMAIL."
popd >/dev/null
}

@test "Artifact deployment, global git username and email configured, default SSH Key" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1
setup_ssh_key_fixture
setup_robo_fixture
provision_default_ssh_key
export DREVOPS_DEPLOY_ARTIFACT_GIT_REMOTE="[email protected]:yourorg/your-repo-destination.git"
export DREVOPS_DEPLOY_ARTIFACT_DST_BRANCH="main"
export DREVOPS_DEPLOY_ARTIFACT_SRC="dist"
export DREVOPS_DEPLOY_ARTIFACT_ROOT="."
export DREVOPS_DEPLOY_ARTIFACT_REPORT_FILE="deploy-report.txt"
export DREVOPS_DEPLOY_ARTIFACT_GIT_USER_NAME="test_user"
export DREVOPS_DEPLOY_ARTIFACT_GIT_USER_EMAIL="[email protected]"
local file=${HOME}/.ssh/id_rsa
mock_realpath=$(mock_command "realpath")

declare -a STEPS=(
"- Missing required value for DREVOPS_DEPLOY_ARTIFACT_GIT_REMOTE."
"- Missing required value for DREVOPS_DEPLOY_ARTIFACT_SRC."
"- Missing required value for DREVOPS_DEPLOY_ARTIFACT_GIT_USER_EMAIL."
"@git config --global user.name #"
"Configuring global git user name."
"@git config --global user.name ${DREVOPS_DEPLOY_ARTIFACT_GIT_USER_NAME} # 0 #"
"@git config --global user.email #"
"Configuring global git user email."
"@git config --global user.email ${DREVOPS_DEPLOY_ARTIFACT_GIT_USER_EMAIL} # 0 #"
"Using default SSH file ${file}."
"Using SSH key file ${file}."
"@ssh-add -l # ${file}"
"SSH agent has ${file} key loaded."
"Installing artifact builder."
"@composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:^0.5"
"Running artifact builder."
"Finished ARTIFACT deployment."
)
mocks="$(run_steps "setup")"
run scripts/drevops/deploy-artifact.sh
assert_success
run_steps "assert" "${mocks[@]}"
assert_equal "2" "$(mock_get_call_num "${mock_realpath}" 1)"

popd >/dev/null
}
197 changes: 197 additions & 0 deletions .scaffold/tests/bats/setup-ssh.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
#!/usr/bin/env bats
#
# Test for CircleCI lifecycle.
#
# shellcheck disable=SC2030,SC2031,SC2129,SC2155

load _helper.bash
load _helper.deployment.bash

@test "No DREVOPS_SSH_PREFIX" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1
setup_ssh_key_fixture
run scripts/drevops/setup-ssh.sh
assert_failure
assert_output_contains "Missing the required DREVOPS_SSH_PREFIX environment variable"
popd >/dev/null
}

@test "Use default SSH Key, SSH Key missing" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1
setup_ssh_key_fixture
export DREVOPS_SSH_PREFIX="test"
local file=${HOME}/.ssh/id_rsa
run scripts/drevops/setup-ssh.sh
assert_failure
assert_output_contains "Using default SSH file ${file}."
assert_output_contains "SSH key file ${file} does not exist."

popd >/dev/null
}

@test "Use default SSH Key, SSH Key exists" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1
setup_ssh_key_fixture
provision_default_ssh_key

export DREVOPS_SSH_PREFIX="test"
local file=${HOME}/.ssh/id_rsa

declare -a STEPS=(
"Using default SSH file ${file}."
"Using SSH key file ${file}."
"@ssh-add -l # ${file}"
"SSH agent has ${file} key loaded."
)
mocks="$(run_steps "setup")"
run scripts/drevops/setup-ssh.sh
assert_success
run_steps "assert" "${mocks[@]}"

popd >/dev/null
}

@test "Use SSH Prefix, SSH Key with suffix, SSH Key exists" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1
setup_ssh_key_fixture
local suffix="TEST"
provision_ssh_key_with_suffix ${suffix}
export DREVOPS_SSH_PREFIX="KEY_IDENTIFIER"
export DREVOPS_KEY_IDENTIFIER_SSH_FILE="${SSH_KEY_FIXTURE_DIR}/id_rsa_${suffix}"
declare -a STEPS=(
"Started SSH setup"
"Found variable DREVOPS_KEY_IDENTIFIER_SSH_FILE with value ${DREVOPS_KEY_IDENTIFIER_SSH_FILE}."
"Using SSH key file ${DREVOPS_KEY_IDENTIFIER_SSH_FILE}."
"@ssh-add -l # ${DREVOPS_KEY_IDENTIFIER_SSH_FILE}"
"SSH agent has ${DREVOPS_KEY_IDENTIFIER_SSH_FILE} key loaded."
"Finished SSH setup"
)
mocks="$(run_steps "setup")"
run scripts/drevops/setup-ssh.sh
assert_success
run_steps "assert" "${mocks[@]}"

popd >/dev/null
}

@test "Use SSH Fingerprint, No matching SSH Key, Cannot load to agent" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1
setup_ssh_key_fixture
export DREVOPS_SSH_PREFIX="test"
export DREVOPS_test_SSH_FINGERPRINT="DOES_NOT_EXIST"
run scripts/drevops/setup-ssh.sh
assert_failure
assert_output_contains "Found variable DREVOPS_test_SSH_FINGERPRINT with value ${DREVOPS_test_SSH_FINGERPRINT}."
assert_output_contains "Using fingerprint-based deploy key because fingerprint was provided."
assert_output_contains "SSH key file ${HOME}/.ssh/id_rsa_${DREVOPS_test_SSH_FINGERPRINT} does not exist."

popd >/dev/null
}

@test "Use SSH Fingerprint, SSH Key provided" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1
setup_ssh_key_fixture
# Assert using fingerprint with ssh key
export DREVOPS_test_SSH_FINGERPRINT="TEST"
provision_ssh_key_with_suffix ${DREVOPS_test_SSH_FINGERPRINT}
export DREVOPS_SSH_PREFIX="test"
local file="${SSH_KEY_FIXTURE_DIR}/id_rsa_${DREVOPS_test_SSH_FINGERPRINT}"
declare -a STEPS=(
"Found variable DREVOPS_test_SSH_FINGERPRINT with value ${DREVOPS_test_SSH_FINGERPRINT}."
"Using fingerprint-based deploy key because fingerprint was provided."
"Using SSH key file ${file}."
"@ssh-add -l # ${file}"
"SSH agent has ${file} key loaded."
)
mocks="$(run_steps "setup")"
run scripts/drevops/setup-ssh.sh
assert_success
run_steps "assert" "${mocks[@]}"

popd >/dev/null
}

@test "Loading SSH key to SSH Agent, Key exists, CI environment" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1
setup_ssh_key_fixture

# Assert does not have key loaded
export DREVOPS_SSH_PREFIX="IDENTIFIER"
export DREVOPS_IDENTIFIER_SSH_FINGERPRINT="TEST"
provision_ssh_key_with_suffix ${DREVOPS_IDENTIFIER_SSH_FINGERPRINT}
export CI="1"
local file="${SSH_KEY_FIXTURE_DIR}/id_rsa_${DREVOPS_IDENTIFIER_SSH_FINGERPRINT}"
declare -a STEPS=(
"Found variable DREVOPS_${DREVOPS_SSH_PREFIX}_SSH_FINGERPRINT with value ${DREVOPS_IDENTIFIER_SSH_FINGERPRINT}."
"Using fingerprint-based deploy key because fingerprint was provided."
"Using SSH key file ${file}."
"@ssh-add -l # The agent has no identities."
"SSH agent does not have a required key loaded. Trying to load."
"- SSH agent has ${file} key loaded."
"@ssh-add -D"
"@ssh-add ${file}"
"@ssh-add -l # ${file}"
"Disabling strict host key checking in CI."
"Finished SSH setup."
)
mocks="$(run_steps "setup")"
run scripts/drevops/setup-ssh.sh
assert_success
run_steps "assert" "${mocks[@]}"

popd >/dev/null
}

@test "Key provided, MD5 Fingerprint, Key not found" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1
setup_ssh_key_fixture
local suffix="TEST"
provision_ssh_key_with_suffix ${suffix}
export DREVOPS_SSH_PREFIX="test"
export DREVOPS_test_SSH_FINGERPRINT="$(ssh-keygen -l -E md5 -f "${SSH_KEY_FIXTURE_DIR}/id_rsa_${suffix}" | awk '{print $2}')"
export DREVOPS_test_SSH_FILE="${SSH_KEY_FIXTURE_DIR}/id_rsa_${suffix}"
export CI=""
local ssh_key_file="${DREVOPS_test_SSH_FINGERPRINT//:/}"
ssh_key_file="${HOME}/.ssh/id_rsa_${ssh_key_file//\"/}"
declare -a STEPS=(
"Found variable DREVOPS_test_SSH_FINGERPRINT with value ${DREVOPS_test_SSH_FINGERPRINT}."
"Found variable DREVOPS_test_SSH_FILE with value ${DREVOPS_test_SSH_FILE}."
"Using fingerprint-based deploy key because fingerprint was provided."
"SSH key file ${ssh_key_file} does not exist."
)
mocks="$(run_steps "setup")"
run scripts/drevops/setup-ssh.sh
assert_failure
run_steps "assert" "${mocks[@]}"

popd >/dev/null
}

@test "Key found, SHA256 fingerprint, Not CI environment" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1
setup_ssh_key_fixture
local suffix="TEST"
provision_ssh_key_with_suffix ${suffix}
export DREVOPS_SSH_PREFIX="TEST"
export DREVOPS_TEST_SSH_FINGERPRINT="$(ssh-keygen -l -E sha256 -f "${SSH_KEY_FIXTURE_DIR}/id_rsa_${suffix}" | awk '{print $2}')"
export CI=""
local md5_fingerprint="$(ssh-keygen -l -E md5 -f "${SSH_KEY_FIXTURE_DIR}/id_rsa_${suffix}" | awk '{print $2}')"
md5_fingerprint="${md5_fingerprint#MD5:}"
local ssh_key_file="${md5_fingerprint//:/}"
ssh_key_file="${HOME}/.ssh/id_rsa_${ssh_key_file//\"/}"
local file="${SSH_KEY_FIXTURE_DIR}/id_rsa_${suffix}"
declare -a STEPS=(
"Found variable DREVOPS_TEST_SSH_FINGERPRINT with value ${DREVOPS_TEST_SSH_FINGERPRINT}."
"Using fingerprint-based deploy key because fingerprint was provided."
"Searching for MD5 hash as fingerprint starts with SHA256."
"Found matching existing key file ${file}."
"SSH key file ${ssh_key_file} does not exist."
"- Disabling strict host key checking in CI."
)
mocks="$(run_steps "setup")"
run scripts/drevops/setup-ssh.sh
assert_failure
run_steps "assert" "${mocks[@]}"

popd >/dev/null
}

0 comments on commit 29ef4a2

Please sign in to comment.