#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" resolve_repo_root() { local candidate for candidate in "${SCRIPT_DIR}/.." "${SCRIPT_DIR}/../.." "${PWD}"; do if [[ -f "${candidate}/credentials/.env" ]]; then (cd "${candidate}" && pwd) return 0 fi done return 1 } if ! REPO_ROOT="$(resolve_repo_root)"; then echo "Error: could not locate repository root containing credentials/.env" >&2 exit 1 fi ENV_FILE="${REPO_ROOT}/credentials/.env" if [[ ! -f "${ENV_FILE}" ]]; then echo "Error: credentials file not found: ${ENV_FILE}" >&2 exit 1 fi load_env_value() { local key="$1" local line line="$(grep -E "^${key}=" "${ENV_FILE}" | tail -n 1 || true)" line="${line#*=}" line="${line%\"}" line="${line#\"}" line="${line%\'}" line="${line#\'}" printf '%s' "${line}" } SSH_HOST="$(load_env_value REMOTE_SSH_HOST)" SSH_PORT="$(load_env_value REMOTE_SSH_PORT)" SSH_USER="$(load_env_value REMOTE_SSH_USER)" SSH_KEY_RAW="$(load_env_value REMOTE_SSH_KEY)" REMOTE_MYSQL_HOST="$(load_env_value REMOTE_MYSQL_HOST)" REMOTE_MYSQL_PORT="$(load_env_value REMOTE_MYSQL_PORT)" LOCAL_PORT="${LOCAL_PORT:-13306}" if [[ -z "${SSH_HOST}" || -z "${SSH_USER}" || -z "${SSH_KEY_RAW}" ]]; then echo "Error: missing REMOTE_SSH_* values in ${ENV_FILE}" >&2 exit 1 fi if [[ -z "${SSH_PORT}" ]]; then SSH_PORT=22; fi if [[ -z "${REMOTE_MYSQL_HOST}" ]]; then REMOTE_MYSQL_HOST=127.0.0.1; fi if [[ -z "${REMOTE_MYSQL_PORT}" ]]; then REMOTE_MYSQL_PORT=3306; fi if [[ "${SSH_KEY_RAW}" = /* ]]; then SSH_KEY_PATH="${SSH_KEY_RAW}" else SSH_KEY_PATH="${REPO_ROOT}/${SSH_KEY_RAW}" fi if [[ ! -f "${SSH_KEY_PATH}" ]]; then echo "Error: SSH key not found: ${SSH_KEY_PATH}" >&2 exit 1 fi CONTROL_SOCKET="/tmp/mailshot-mysql-tunnel-${LOCAL_PORT}.sock" SSH_TARGET="${SSH_USER}@${SSH_HOST}" start_tunnel() { if ssh -S "${CONTROL_SOCKET}" -p "${SSH_PORT}" -O check "${SSH_TARGET}" >/dev/null 2>&1; then echo "Tunnel already running on 127.0.0.1:${LOCAL_PORT}" return 0 fi ssh -f -N \ -M -S "${CONTROL_SOCKET}" \ -o BatchMode=yes \ -o ExitOnForwardFailure=yes \ -o StrictHostKeyChecking=accept-new \ -i "${SSH_KEY_PATH}" \ -p "${SSH_PORT}" \ -L "127.0.0.1:${LOCAL_PORT}:${REMOTE_MYSQL_HOST}:${REMOTE_MYSQL_PORT}" \ "${SSH_TARGET}" echo "Tunnel started: 127.0.0.1:${LOCAL_PORT} -> ${REMOTE_MYSQL_HOST}:${REMOTE_MYSQL_PORT} via ${SSH_TARGET}:${SSH_PORT}" echo "Use in DBeaver: host=127.0.0.1 port=${LOCAL_PORT}" } stop_tunnel() { if ssh -S "${CONTROL_SOCKET}" -p "${SSH_PORT}" -O exit "${SSH_TARGET}" >/dev/null 2>&1; then rm -f "${CONTROL_SOCKET}" || true echo "Tunnel stopped for 127.0.0.1:${LOCAL_PORT}" else echo "No active tunnel found for 127.0.0.1:${LOCAL_PORT}" fi } status_tunnel() { if ssh -S "${CONTROL_SOCKET}" -p "${SSH_PORT}" -O check "${SSH_TARGET}" >/dev/null 2>&1; then echo "Tunnel is running on 127.0.0.1:${LOCAL_PORT}" else echo "Tunnel is not running on 127.0.0.1:${LOCAL_PORT}" fi } CMD="${1:-start}" case "${CMD}" in start) start_tunnel ;; stop) stop_tunnel ;; status) status_tunnel ;; *) echo "Usage: $(basename "$0") [start|stop|status]" exit 1 ;; esac