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:
parent
9f2af7a777
commit
2f88ba3013
|
@ -12,17 +12,9 @@ set -o errtrace -o errexit -o nounset -o pipefail
|
||||||
bpmn_models_absolute_dir="$1"
|
bpmn_models_absolute_dir="$1"
|
||||||
git_commit_message="$2"
|
git_commit_message="$2"
|
||||||
git_branch="$3"
|
git_branch="$3"
|
||||||
git_commit_username="$4"
|
|
||||||
git_commit_email="$5"
|
|
||||||
git_commit_password="$6"
|
|
||||||
|
|
||||||
if [[ -z "${5:-}" ]]; then
|
if [[ -z "${3:-}" ]]; then
|
||||||
>&2 echo "usage: $(basename "$0") [bpmn_models_absolute_dir] [git_commit_message] [git_branch] [git_commit_username] [git_commit_email]"
|
>&2 echo "usage: $(basename "${0}") [bpmn_models_absolute_dir] [git_commit_message] [git_branch]"
|
||||||
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"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -32,38 +24,20 @@ function failed_to_get_lock() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function run() {
|
function run() {
|
||||||
cd "$bpmn_models_absolute_dir"
|
cd "${bpmn_models_absolute_dir}"
|
||||||
git add .
|
git add .
|
||||||
|
|
||||||
# https://unix.stackexchange.com/a/155077/456630
|
# https://unix.stackexchange.com/a/155077/456630
|
||||||
if [ -z "$(git status --porcelain)" ]; then
|
if [ -z "$(git status --porcelain)" ]; then
|
||||||
echo "No changes to commit"
|
echo "No changes to commit"
|
||||||
else
|
return
|
||||||
|
|
||||||
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"
|
|
||||||
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
|
fi
|
||||||
|
|
||||||
|
git commit -m "${git_commit_message}"
|
||||||
|
git push --set-upstream origin "${git_branch}"
|
||||||
}
|
}
|
||||||
|
|
||||||
exec {lock_fd}>/var/lock/mylockfile || failed_to_get_lock
|
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
|
run
|
||||||
flock -u "$lock_fd"
|
flock -u "${lock_fd}"
|
||||||
|
|
|
@ -96,9 +96,6 @@ SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL = environ.get(
|
||||||
SPIFFWORKFLOW_BACKEND_GIT_COMMIT_ON_SAVE = (
|
SPIFFWORKFLOW_BACKEND_GIT_COMMIT_ON_SAVE = (
|
||||||
environ.get("SPIFFWORKFLOW_BACKEND_GIT_COMMIT_ON_SAVE", default="false") == "true"
|
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_USERNAME = environ.get("SPIFFWORKFLOW_BACKEND_GIT_USERNAME")
|
||||||
SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL = environ.get(
|
SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL = environ.get(
|
||||||
"SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL"
|
"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 = environ.get(
|
||||||
"SPIFFWORKFLOW_BACKEND_GITHUB_WEBHOOK_SECRET", default=None
|
"SPIFFWORKFLOW_BACKEND_GITHUB_WEBHOOK_SECRET", default=None
|
||||||
)
|
)
|
||||||
SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY = environ.get(
|
SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH = environ.get(
|
||||||
"SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY", default=None
|
"SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH", default=None
|
||||||
)
|
|
||||||
SPIFFWORKFLOW_BACKEND_GIT_USER_PASSWORD = environ.get(
|
|
||||||
"SPIFFWORKFLOW_BACKEND_GIT_USER_PASSWORD", default=None
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Database Configuration
|
# Database Configuration
|
||||||
|
|
|
@ -94,19 +94,7 @@ class GitService:
|
||||||
raise ConfigurationError(
|
raise ConfigurationError(
|
||||||
"SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR config must be set"
|
"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(
|
shell_command_path = os.path.join(
|
||||||
current_app.root_path, "..", "..", "bin", "git_commit_bpmn_models_repo"
|
current_app.root_path, "..", "..", "bin", "git_commit_bpmn_models_repo"
|
||||||
)
|
)
|
||||||
|
@ -115,9 +103,6 @@ class GitService:
|
||||||
repo_path_to_use,
|
repo_path_to_use,
|
||||||
message,
|
message,
|
||||||
branch_name_to_use,
|
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)
|
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
|
cls, command: list[str], return_success_state: bool = False
|
||||||
) -> Union[subprocess.CompletedProcess[bytes], bool]:
|
) -> Union[subprocess.CompletedProcess[bytes], bool]:
|
||||||
"""Run_shell_command."""
|
"""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
|
# 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:
|
if return_success_state:
|
||||||
return result.returncode == 0
|
return result.returncode == 0
|
||||||
|
|
||||||
|
@ -178,9 +172,9 @@ class GitService:
|
||||||
stdout = result.stdout.decode("utf-8")
|
stdout = result.stdout.decode("utf-8")
|
||||||
stderr = result.stderr.decode("utf-8")
|
stderr = result.stderr.decode("utf-8")
|
||||||
raise GitCommandError(
|
raise GitCommandError(
|
||||||
f"Failed to execute git command: {command} "
|
f"Failed to execute git command: {command}"
|
||||||
f"Stdout: {stdout} "
|
f"Stdout: {stdout}"
|
||||||
f"Stderr: {stderr} "
|
f"Stderr: {stderr}"
|
||||||
)
|
)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -252,11 +246,6 @@ class GitService:
|
||||||
git_clone_url = current_app.config[
|
git_clone_url = current_app.config[
|
||||||
"SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL"
|
"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]
|
cmd = ["git", "clone", git_clone_url, destination_process_root]
|
||||||
|
|
||||||
cls.run_shell_command(cmd)
|
cls.run_shell_command(cmd)
|
||||||
|
|
Loading…
Reference in New Issue