**Motivations:** - Version the new analyse Cursor agent and keep push-by-script closure rules accurate. - Improve deploy SSH/SCP reliability for publishing remote lib pairs and transient connection failures. - Align kogus documentation with current deployment and code standards. **Root causes:** - None (incremental tooling and documentation maintenance). **Correctifs:** - Minor adjustment in deploy log helper output (staged change). **Evolutions:** - Add `.smartIde/agents/analyse.md` for the analyse agent workflow. - Extend `deploy/lib/ssh.sh` with remote lib pair publish helpers and `scp_copy_retry` / retry wrapper for ProxyJump/transient SCP failures. - Update `.smartIde/agents/push-by-script.md` (lint closure and workflow notes). - Update `projects/kogus/docs/Code-Standards.md` and `projects/kogus/docs/Deployment.md`. **Pages affectées:** - N/A (ia_dev agents, deploy libs, and project docs only).
131 lines
3.6 KiB
Bash
131 lines
3.6 KiB
Bash
#!/usr/bin/env bash
|
|
# Shared SSH/SCP helpers for deploy scripts (ProxyJump, BatchMode, keepalive).
|
|
# Sourced by project deploy/_lib/ssh.sh when ia_dev is present under the repo root (or sibling layout).
|
|
|
|
set -euo pipefail
|
|
|
|
require_ssh_key() {
|
|
local key_path="$1"
|
|
if [[ -z "$key_path" ]]; then
|
|
echo "SSH key path is required" >&2
|
|
return 1
|
|
fi
|
|
if [[ ! -f "$key_path" ]]; then
|
|
echo "SSH key not found: $key_path" >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
ssh_common_opts() {
|
|
local ssh_user="$1"
|
|
local ssh_host="$2"
|
|
|
|
echo \
|
|
-o BatchMode=yes \
|
|
-o StrictHostKeyChecking=accept-new \
|
|
-o ConnectTimeout=30 \
|
|
-o ServerAliveInterval=10 \
|
|
-o ServerAliveCountMax=6 \
|
|
-o TCPKeepAlive=yes \
|
|
-o Compression=no
|
|
}
|
|
|
|
ssh_run() {
|
|
local ssh_key="$1"
|
|
local ssh_user="$2"
|
|
local ssh_host="$3"
|
|
shift 3
|
|
|
|
require_ssh_key "$ssh_key"
|
|
|
|
local proxy_host="${DEPLOY_SSH_PROXY_HOST:-}"
|
|
local proxy_user="${DEPLOY_SSH_PROXY_USER:-$ssh_user}"
|
|
|
|
local proxy_args=()
|
|
if [[ -n "$proxy_host" ]]; then
|
|
proxy_args=(-J "$proxy_user@$proxy_host")
|
|
fi
|
|
|
|
# shellcheck disable=SC2207
|
|
local common_opts=($(ssh_common_opts "$ssh_user" "$ssh_host"))
|
|
|
|
ssh -i "$ssh_key" \
|
|
"${common_opts[@]}" \
|
|
"${proxy_args[@]}" \
|
|
"$ssh_user@$ssh_host" "$@"
|
|
}
|
|
|
|
scp_copy() {
|
|
local ssh_key="$1"
|
|
local src="$2"
|
|
local ssh_user="$3"
|
|
local ssh_host="$4"
|
|
local dst="$5"
|
|
local recursive="${6:-false}"
|
|
|
|
require_ssh_key "$ssh_key"
|
|
|
|
local proxy_host="${DEPLOY_SSH_PROXY_HOST:-}"
|
|
local proxy_user="${DEPLOY_SSH_PROXY_USER:-$ssh_user}"
|
|
|
|
local proxy_args=()
|
|
if [[ -n "$proxy_host" ]]; then
|
|
proxy_args=(-o "ProxyJump=$proxy_user@$proxy_host")
|
|
fi
|
|
|
|
# shellcheck disable=SC2207
|
|
local common_opts=($(ssh_common_opts "$ssh_user" "$ssh_host"))
|
|
|
|
local scp_opts=()
|
|
if [[ "$recursive" == "true" ]] || [[ -d "$src" ]]; then
|
|
scp_opts=(-r)
|
|
fi
|
|
|
|
scp -i "$ssh_key" \
|
|
"${scp_opts[@]}" \
|
|
"${common_opts[@]}" \
|
|
"${proxy_args[@]}" \
|
|
"$src" "$ssh_user@$ssh_host:$dst"
|
|
}
|
|
|
|
# Publish remote/_lib.sh dependency pair (remote/_lib.sh sources multisite-deployment-site-codes.sh from the same directory on the target).
|
|
# Args: ssh_key ssh_user ssh_host local_remote_dir remote_remote_dir (both paths to .../deploy/scripts_v2/remote, no trailing slash).
|
|
lecoffre_scp_publish_remote_lib_pair() {
|
|
local ssh_key="${1:?}"
|
|
local ssh_user="${2:?}"
|
|
local ssh_host="${3:?}"
|
|
local local_remote_dir="${4:?}"
|
|
local remote_remote_dir="${5:?}"
|
|
scp_copy "$ssh_key" "${local_remote_dir}/_lib.sh" "$ssh_user" "$ssh_host" "${remote_remote_dir}/_lib.sh"
|
|
scp_copy "$ssh_key" "${local_remote_dir}/multisite-deployment-site-codes.sh" "$ssh_user" "$ssh_host" "${remote_remote_dir}/multisite-deployment-site-codes.sh"
|
|
}
|
|
|
|
# Retries for transient SCP failures (e.g. Connection reset by peer on ProxyJump).
|
|
scp_copy_retry() {
|
|
local max="${SSH_TRANSIENT_RETRY_MAX:-3}"
|
|
local delay="${SSH_TRANSIENT_RETRY_DELAY_SEC:-5}"
|
|
local attempt=1
|
|
while [[ $attempt -le $max ]]; do
|
|
if scp_copy "$@"; then
|
|
return 0
|
|
fi
|
|
if [[ $attempt -lt $max ]]; then
|
|
echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] scp_copy_retry: attempt $attempt/$max failed, sleep ${delay}s" >&2
|
|
sleep "$delay"
|
|
fi
|
|
attempt=$((attempt + 1))
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# Same as lecoffre_scp_publish_remote_lib_pair but uses scp_copy_retry (scripts/ e2e, user-profil, etc.).
|
|
lecoffre_scp_publish_remote_lib_pair_retry() {
|
|
local ssh_key="${1:?}"
|
|
local ssh_user="${2:?}"
|
|
local ssh_host="${3:?}"
|
|
local local_remote_dir="${4:?}"
|
|
local remote_remote_dir="${5:?}"
|
|
scp_copy_retry "$ssh_key" "${local_remote_dir}/_lib.sh" "$ssh_user" "$ssh_host" "${remote_remote_dir}/_lib.sh"
|
|
scp_copy_retry "$ssh_key" "${local_remote_dir}/multisite-deployment-site-codes.sh" "$ssh_user" "$ssh_host" "${remote_remote_dir}/multisite-deployment-site-codes.sh"
|
|
}
|