backend: fix use of SSH private key for git ops

Primarily this is supposed to fix the `git pull` aciton triggered by
webhooks from GitHub. But in addition to that the point is to simplify
that committing wrapper which has far too much in it.

Instead of passing everything as CLI arguments one should make use of
already supported environment variables and the `env` argument to
`subprocess` functions like `run()`. Writing extra logic in the wrapper
only makes it unnecessarily complicated.

By passing both user, email, and the SSH options in `run_shell_command`
we avoid the need to repeat the same boilerplate to provide Git config
and SSH credentials.

Signed-off-by: Jakub Sokołowski <jakub@status.im>
This commit is contained in:
Jakub Sokołowski 2023-02-20 22:21:31 +01:00
parent 9f2af7a777
commit 2f88ba3013
No known key found for this signature in database
GPG Key ID: FE65CD384D5BF7B4
3 changed files with 24 additions and 67 deletions

View File

@ -12,17 +12,9 @@ set -o errtrace -o errexit -o nounset -o pipefail
bpmn_models_absolute_dir="$1"
git_commit_message="$2"
git_branch="$3"
git_commit_username="$4"
git_commit_email="$5"
git_commit_password="$6"
if [[ -z "${5:-}" ]]; then
>&2 echo "usage: $(basename "$0") [bpmn_models_absolute_dir] [git_commit_message] [git_branch] [git_commit_username] [git_commit_email]"
exit 1
fi
if [[ -z "$git_commit_password" && -z "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY:-}" ]]; then
>&2 echo "ERROR: A git password or SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY must be provided"
if [[ -z "${3:-}" ]]; then
>&2 echo "usage: $(basename "${0}") [bpmn_models_absolute_dir] [git_commit_message] [git_branch]"
exit 1
fi
@ -32,38 +24,20 @@ function failed_to_get_lock() {
}
function run() {
cd "$bpmn_models_absolute_dir"
cd "${bpmn_models_absolute_dir}"
git add .
# https://unix.stackexchange.com/a/155077/456630
if [ -z "$(git status --porcelain)" ]; then
echo "No changes to commit"
else
git config --local user.name "$git_commit_username"
git config --local user.email "$git_commit_email"
if [[ -n "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY:-}" ]]; then
tmpfile=$(mktemp /tmp/tmp_git.XXXXXX)
chmod 600 "$tmpfile"
echo "$SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY" >"$tmpfile"
export GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i ${tmpfile} -F /dev/null"
else
PAT="${git_commit_username}:${git_commit_password}"
AUTH=$(echo -n "$PAT" | openssl base64 | tr -d '\n')
git config --local http.extraHeader "Authorization: Basic $AUTH"
return
fi
git commit -m "$git_commit_message"
git push --set-upstream origin "$git_branch"
if [[ -z "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY:-}" ]]; then
git config --unset --local http.extraHeader
fi
fi
git commit -m "${git_commit_message}"
git push --set-upstream origin "${git_branch}"
}
exec {lock_fd}>/var/lock/mylockfile || failed_to_get_lock
flock --timeout 60 "$lock_fd" || failed_to_get_lock
flock --timeout 60 "${lock_fd}" || failed_to_get_lock
run
flock -u "$lock_fd"
flock -u "${lock_fd}"

View File

@ -96,9 +96,6 @@ SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL = environ.get(
SPIFFWORKFLOW_BACKEND_GIT_COMMIT_ON_SAVE = (
environ.get("SPIFFWORKFLOW_BACKEND_GIT_COMMIT_ON_SAVE", default="false") == "true"
)
SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY = environ.get(
"SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY"
)
SPIFFWORKFLOW_BACKEND_GIT_USERNAME = environ.get("SPIFFWORKFLOW_BACKEND_GIT_USERNAME")
SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL = environ.get(
"SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL"
@ -106,11 +103,8 @@ SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL = environ.get(
SPIFFWORKFLOW_BACKEND_GITHUB_WEBHOOK_SECRET = environ.get(
"SPIFFWORKFLOW_BACKEND_GITHUB_WEBHOOK_SECRET", default=None
)
SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY = environ.get(
"SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY", default=None
)
SPIFFWORKFLOW_BACKEND_GIT_USER_PASSWORD = environ.get(
"SPIFFWORKFLOW_BACKEND_GIT_USER_PASSWORD", default=None
SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH = environ.get(
"SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH", default=None
)
# Database Configuration

View File

@ -94,19 +94,7 @@ class GitService:
raise ConfigurationError(
"SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR config must be set"
)
if current_app.config["SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY"]:
os.environ["SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY"] = (
current_app.config["SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY"]
)
git_username = ""
git_email = ""
if (
current_app.config["SPIFFWORKFLOW_BACKEND_GIT_USERNAME"]
and current_app.config["SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL"]
):
git_username = current_app.config["SPIFFWORKFLOW_BACKEND_GIT_USERNAME"]
git_email = current_app.config["SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL"]
shell_command_path = os.path.join(
current_app.root_path, "..", "..", "bin", "git_commit_bpmn_models_repo"
)
@ -115,9 +103,6 @@ class GitService:
repo_path_to_use,
message,
branch_name_to_use,
git_username,
git_email,
current_app.config["SPIFFWORKFLOW_BACKEND_GIT_USER_PASSWORD"],
]
return cls.run_shell_command_to_get_stdout(shell_command)
@ -169,8 +154,17 @@ class GitService:
cls, command: list[str], return_success_state: bool = False
) -> Union[subprocess.CompletedProcess[bytes], bool]:
"""Run_shell_command."""
env = {
'GIT_COMMITTER_NAME': current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USERNAME", "unknown"),
'GIT_COMMITTER_EMAIL': current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL", "unknown@example.org"),
}
# SSH authentication can be also provided via gitconfig.
ssh_key_path = current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH")
if ssh_key_path is not None:
env['GIT_SSH_COMMAND'] = 'ssh -F /dev/null -i %s' % ssh_key_path
# this is fine since we pass the commands directly
result = subprocess.run(command, check=False, capture_output=True) # noqa
result = subprocess.run(command, check=False, capture_output=True, env=env) # noqa
if return_success_state:
return result.returncode == 0
@ -252,11 +246,6 @@ class GitService:
git_clone_url = current_app.config[
"SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL"
]
if git_clone_url.startswith("https://"):
git_clone_url = git_clone_url.replace(
"https://",
f"https://{current_app.config['SPIFFWORKFLOW_BACKEND_GIT_USERNAME']}:{current_app.config['SPIFFWORKFLOW_BACKEND_GIT_USER_PASSWORD']}@",
)
cmd = ["git", "clone", git_clone_url, destination_process_root]
cls.run_shell_command(cmd)