Use Debian SSH key for Gitea deploys
Homelab Main / validate-and-deploy (push) Failing after 18s
Details
Homelab Main / validate-and-deploy (push) Failing after 18s
Details
This commit is contained in:
parent
cc657fad6c
commit
c470e64070
|
|
@ -174,9 +174,11 @@ jobs:
|
||||||
deploy_dir="${HOMELAB_DEPLOY_DIR:-/home/jv/my-homelab-configs}"
|
deploy_dir="${HOMELAB_DEPLOY_DIR:-/home/jv/my-homelab-configs}"
|
||||||
test -d "${deploy_dir}/.git"
|
test -d "${deploy_dir}/.git"
|
||||||
|
|
||||||
git -C "${deploy_dir}" remote set-url gitea https://lab2025.duckdns.org/git/jv/my-homelab-configs.git || \
|
gitea_ssh_url="${GITEA_SSH_URL:-ssh://git@192.168.100.89:32222/jv/my-homelab-configs.git}"
|
||||||
git -C "${deploy_dir}" remote add gitea https://lab2025.duckdns.org/git/jv/my-homelab-configs.git
|
gitea_ssh_command="${GITEA_SSH_COMMAND:-ssh -i /home/jv/.ssh/id_ed25519 -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new}"
|
||||||
git -C "${deploy_dir}" fetch gitea main
|
git -C "${deploy_dir}" remote set-url gitea "${gitea_ssh_url}" || \
|
||||||
|
git -C "${deploy_dir}" remote add gitea "${gitea_ssh_url}"
|
||||||
|
GIT_SSH_COMMAND="${gitea_ssh_command}" git -C "${deploy_dir}" fetch gitea main
|
||||||
git -C "${deploy_dir}" checkout main
|
git -C "${deploy_dir}" checkout main
|
||||||
git -C "${deploy_dir}" reset --hard "${{ gitea.sha }}"
|
git -C "${deploy_dir}" reset --hard "${{ gitea.sha }}"
|
||||||
git -C "${deploy_dir}" remote set-url local-bootstrap /home/jv/git-server/my-homelab-configs.git || \
|
git -C "${deploy_dir}" remote set-url local-bootstrap /home/jv/git-server/my-homelab-configs.git || \
|
||||||
|
|
|
||||||
|
|
@ -414,6 +414,14 @@ changes still require a manual Debian run. Lower-risk app changes proceed to
|
||||||
`./lab.sh apps` after validation passes, which skips Gitea, Pimox, cluster,
|
`./lab.sh apps` after validation passes, which skips Gitea, Pimox, cluster,
|
||||||
platform, and edge changes.
|
platform, and edge changes.
|
||||||
|
|
||||||
|
`./lab.sh bootstrap-gitea-repo` also registers the Debian host SSH public key
|
||||||
|
with the Gitea repository and switches the Debian working copy's `gitea` remote
|
||||||
|
to `ssh://git@192.168.100.89:32222/jv/my-homelab-configs.git`. The default key
|
||||||
|
is `/home/jv/.ssh/id_ed25519.pub`; set `LAB_GITEA_REPO_SSH_KEY_PATH` to use a
|
||||||
|
different Debian-host key, or `LAB_GITEA_REPO_SSH_BOOTSTRAP=false` to leave SSH
|
||||||
|
access unchanged. The Actions deploy job fetches the persistent Debian checkout
|
||||||
|
through that SSH endpoint.
|
||||||
|
|
||||||
Enable Actions for the repository in Gitea, then create a repository-level runner
|
Enable Actions for the repository in Gitea, then create a repository-level runner
|
||||||
token from:
|
token from:
|
||||||
|
|
||||||
|
|
|
||||||
152
lab.sh
152
lab.sh
|
|
@ -1447,6 +1447,136 @@ PY
|
||||||
"${api_base}/user/repos" >/dev/null
|
"${api_base}/user/repos" >/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gitea_public_key_registered() {
|
||||||
|
local api_base="$1"
|
||||||
|
local auth_user="$2"
|
||||||
|
local auth_password="$3"
|
||||||
|
local owner="$4"
|
||||||
|
local repo_name="$5"
|
||||||
|
local public_key_path="$6"
|
||||||
|
local repo_keys
|
||||||
|
local user_keys
|
||||||
|
|
||||||
|
user_keys="$(curl -fsS -u "${auth_user}:${auth_password}" "${api_base}/user/keys?limit=100")"
|
||||||
|
repo_keys="$(curl -fsS -u "${auth_user}:${auth_password}" "${api_base}/repos/${owner}/${repo_name}/keys?limit=100")"
|
||||||
|
|
||||||
|
GITEA_PUBLIC_KEY="$(<"${public_key_path}")" \
|
||||||
|
GITEA_USER_KEYS="${user_keys}" \
|
||||||
|
GITEA_REPO_KEYS="${repo_keys}" \
|
||||||
|
python3 - <<'PY'
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
public_key = os.environ["GITEA_PUBLIC_KEY"].strip()
|
||||||
|
for env_name in ("GITEA_USER_KEYS", "GITEA_REPO_KEYS"):
|
||||||
|
for key in json.loads(os.environ[env_name]) or []:
|
||||||
|
if key.get("key", "").strip() == public_key:
|
||||||
|
sys.exit(0)
|
||||||
|
sys.exit(1)
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
create_gitea_repo_deploy_key() {
|
||||||
|
local api_base="$1"
|
||||||
|
local auth_user="$2"
|
||||||
|
local auth_password="$3"
|
||||||
|
local owner="$4"
|
||||||
|
local repo_name="$5"
|
||||||
|
local title="$6"
|
||||||
|
local public_key_path="$7"
|
||||||
|
local read_only="$8"
|
||||||
|
local payload
|
||||||
|
|
||||||
|
payload="$(
|
||||||
|
GITEA_DEPLOY_KEY_TITLE="${title}" \
|
||||||
|
GITEA_PUBLIC_KEY="$(<"${public_key_path}")" \
|
||||||
|
GITEA_DEPLOY_KEY_READ_ONLY="${read_only}" \
|
||||||
|
python3 - <<'PY'
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
print(json.dumps({
|
||||||
|
"title": os.environ["GITEA_DEPLOY_KEY_TITLE"],
|
||||||
|
"key": os.environ["GITEA_PUBLIC_KEY"].strip(),
|
||||||
|
"read_only": os.environ["GITEA_DEPLOY_KEY_READ_ONLY"] == "true",
|
||||||
|
}))
|
||||||
|
PY
|
||||||
|
)"
|
||||||
|
|
||||||
|
curl -fsS \
|
||||||
|
-u "${auth_user}:${auth_password}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-X POST \
|
||||||
|
-d "${payload}" \
|
||||||
|
"${api_base}/repos/${owner}/${repo_name}/keys" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_gitea_repo_ssh_access() {
|
||||||
|
local api_base="$1"
|
||||||
|
local auth_user="$2"
|
||||||
|
local auth_password="$3"
|
||||||
|
local owner="$4"
|
||||||
|
local repo_name="$5"
|
||||||
|
local ssh_host="$6"
|
||||||
|
local ssh_port="$7"
|
||||||
|
local key_path="$8"
|
||||||
|
local key_title="$9"
|
||||||
|
local key_read_only="${10}"
|
||||||
|
local key_dir
|
||||||
|
local known_hosts
|
||||||
|
local public_key_path
|
||||||
|
local read_only_json="false"
|
||||||
|
local ssh_repo_url
|
||||||
|
|
||||||
|
if [[ "${key_path}" =~ [[:space:]] || "${key_path}" == *"'"* ]]; then
|
||||||
|
echo "LAB_GITEA_REPO_SSH_KEY_PATH cannot contain whitespace or single quotes." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
key_dir="$(dirname "${key_path}")"
|
||||||
|
public_key_path="${key_path}.pub"
|
||||||
|
mkdir -p "${key_dir}"
|
||||||
|
chmod 0700 "${key_dir}"
|
||||||
|
|
||||||
|
if [[ ! -s "${key_path}" && ! -s "${public_key_path}" ]]; then
|
||||||
|
ssh-keygen -t ed25519 -N "" -f "${key_path}" -C "${key_title}" >/dev/null
|
||||||
|
elif [[ -s "${key_path}" && ! -s "${public_key_path}" ]]; then
|
||||||
|
ssh-keygen -y -f "${key_path}" >"${public_key_path}"
|
||||||
|
elif [[ ! -s "${key_path}" ]]; then
|
||||||
|
echo "Public key ${public_key_path} exists, but private key ${key_path} is missing." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod 0600 "${key_path}"
|
||||||
|
chmod 0644 "${public_key_path}"
|
||||||
|
|
||||||
|
if truthy "${key_read_only}"; then
|
||||||
|
read_only_json="true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if gitea_public_key_registered "${api_base}" "${auth_user}" "${auth_password}" "${owner}" "${repo_name}" "${public_key_path}"; then
|
||||||
|
echo "Gitea already has Debian host SSH key ${public_key_path}."
|
||||||
|
else
|
||||||
|
create_gitea_repo_deploy_key "${api_base}" "${auth_user}" "${auth_password}" "${owner}" "${repo_name}" "${key_title}" "${public_key_path}" "${read_only_json}"
|
||||||
|
echo "Added Debian host SSH key ${public_key_path} to ${owner}/${repo_name}."
|
||||||
|
fi
|
||||||
|
|
||||||
|
known_hosts="${HOME}/.ssh/known_hosts"
|
||||||
|
touch "${known_hosts}"
|
||||||
|
chmod 0644 "${known_hosts}"
|
||||||
|
if ! ssh-keygen -F "[${ssh_host}]:${ssh_port}" -f "${known_hosts}" >/dev/null 2>&1; then
|
||||||
|
ssh-keyscan -p "${ssh_port}" "${ssh_host}" >>"${known_hosts}" 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
ssh_repo_url="ssh://git@${ssh_host}:${ssh_port}/${owner}/${repo_name}.git"
|
||||||
|
git -C "${REPO_ROOT}" remote set-url gitea "${ssh_repo_url}" 2>/dev/null ||
|
||||||
|
git -C "${REPO_ROOT}" remote add gitea "${ssh_repo_url}"
|
||||||
|
git -C "${REPO_ROOT}" config core.sshCommand "ssh -i ${key_path} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new"
|
||||||
|
git -C "${REPO_ROOT}" ls-remote gitea HEAD >/dev/null
|
||||||
|
echo "Gitea SSH remote: ${ssh_repo_url}"
|
||||||
|
}
|
||||||
|
|
||||||
bootstrap_gitea_repo() {
|
bootstrap_gitea_repo() {
|
||||||
local mode="${LAB_GITEA_REPO_BOOTSTRAP:-true}"
|
local mode="${LAB_GITEA_REPO_BOOTSTRAP:-true}"
|
||||||
local gitea_host="${LAB_GITEA_HOST:-${LAB_RASPBERRY_HOST:-192.168.100.89}}"
|
local gitea_host="${LAB_GITEA_HOST:-${LAB_RASPBERRY_HOST:-192.168.100.89}}"
|
||||||
|
|
@ -1454,6 +1584,7 @@ bootstrap_gitea_repo() {
|
||||||
local gitea_key="${LAB_GITEA_SSH_KEY_PATH:-${LAB_RASPBERRY_SSH_KEY_PATH:-/home/jv/.ssh/id_ed25519}}"
|
local gitea_key="${LAB_GITEA_SSH_KEY_PATH:-${LAB_RASPBERRY_SSH_KEY_PATH:-/home/jv/.ssh/id_ed25519}}"
|
||||||
local container_name="${LAB_GITEA_CONTAINER_NAME:-homelab-gitea}"
|
local container_name="${LAB_GITEA_CONTAINER_NAME:-homelab-gitea}"
|
||||||
local http_port="${LAB_GITEA_HTTP_PORT:-3000}"
|
local http_port="${LAB_GITEA_HTTP_PORT:-3000}"
|
||||||
|
local ssh_port="${LAB_GITEA_SSH_PORT:-32222}"
|
||||||
local root_url="${LAB_GITEA_ROOT_URL:-https://lab2025.duckdns.org/git/}"
|
local root_url="${LAB_GITEA_ROOT_URL:-https://lab2025.duckdns.org/git/}"
|
||||||
local repo_owner="${LAB_GITEA_REPO_OWNER:-jv}"
|
local repo_owner="${LAB_GITEA_REPO_OWNER:-jv}"
|
||||||
local repo_name="${LAB_GITEA_REPO_NAME:-my-homelab-configs}"
|
local repo_name="${LAB_GITEA_REPO_NAME:-my-homelab-configs}"
|
||||||
|
|
@ -1463,6 +1594,10 @@ bootstrap_gitea_repo() {
|
||||||
local credentials_file="${LAB_GITEA_BOOTSTRAP_CREDENTIALS_FILE:-${HOME}/.config/homelab/gitea-bootstrap.env}"
|
local credentials_file="${LAB_GITEA_BOOTSTRAP_CREDENTIALS_FILE:-${HOME}/.config/homelab/gitea-bootstrap.env}"
|
||||||
local bootstrap_password="${LAB_GITEA_BOOTSTRAP_PASSWORD:-}"
|
local bootstrap_password="${LAB_GITEA_BOOTSTRAP_PASSWORD:-}"
|
||||||
local allow_dirty="${LAB_GITEA_BOOTSTRAP_ALLOW_DIRTY:-false}"
|
local allow_dirty="${LAB_GITEA_BOOTSTRAP_ALLOW_DIRTY:-false}"
|
||||||
|
local ssh_bootstrap="${LAB_GITEA_REPO_SSH_BOOTSTRAP:-true}"
|
||||||
|
local ssh_key_path="${LAB_GITEA_REPO_SSH_KEY_PATH:-/home/jv/.ssh/id_ed25519}"
|
||||||
|
local ssh_key_title="${LAB_GITEA_REPO_DEPLOY_KEY_TITLE:-debian-host-${repo_name}}"
|
||||||
|
local ssh_key_read_only="${LAB_GITEA_REPO_DEPLOY_KEY_READ_ONLY:-false}"
|
||||||
local api_base
|
local api_base
|
||||||
local public_repo_url
|
local public_repo_url
|
||||||
local direct_repo_url
|
local direct_repo_url
|
||||||
|
|
@ -1490,6 +1625,10 @@ bootstrap_gitea_repo() {
|
||||||
echo "LAB_GITEA_BOOTSTRAP_EMAIL cannot contain a single quote." >&2
|
echo "LAB_GITEA_BOOTSTRAP_EMAIL cannot contain a single quote." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
if ! [[ "${ssh_port}" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo "LAB_GITEA_SSH_PORT must be numeric." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -z "${bootstrap_password}" && -r "${credentials_file}" ]]; then
|
if [[ -z "${bootstrap_password}" && -r "${credentials_file}" ]]; then
|
||||||
# shellcheck disable=SC1090
|
# shellcheck disable=SC1090
|
||||||
|
|
@ -1625,6 +1764,19 @@ ASKPASS_EOT
|
||||||
|
|
||||||
remote_status="$(git -C "${REPO_ROOT}" remote get-url gitea)"
|
remote_status="$(git -C "${REPO_ROOT}" remote get-url gitea)"
|
||||||
echo "Gitea remote: ${remote_status}"
|
echo "Gitea remote: ${remote_status}"
|
||||||
|
if ! disabled_value "${ssh_bootstrap}"; then
|
||||||
|
ensure_gitea_repo_ssh_access \
|
||||||
|
"${api_base}" \
|
||||||
|
"${bootstrap_user}" \
|
||||||
|
"${bootstrap_password}" \
|
||||||
|
"${repo_owner}" \
|
||||||
|
"${repo_name}" \
|
||||||
|
"${gitea_host}" \
|
||||||
|
"${ssh_port}" \
|
||||||
|
"${ssh_key_path}" \
|
||||||
|
"${ssh_key_title}" \
|
||||||
|
"${ssh_key_read_only}"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install_gitea_backup_timer() {
|
install_gitea_backup_timer() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue