fix(agent): bound host110 monitoring repair
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / tests (push) Has been cancelled

This commit is contained in:
ogt
2026-07-14 20:45:38 +08:00
parent 604184bc97
commit 5f4f1ab865
9 changed files with 387 additions and 40 deletions

View File

@@ -15,13 +15,58 @@ source "$(dirname "$0")/common.sh"
SERVICE="awoooi"
AWOOOI_HOST="192.168.0.188"
AWOOOI_DB_USER="awoooi"
AWOOOI_DB_PASS="awoooi_prod_2026"
AWOOOI_DB_PASS="${AWOOOI_DB_PASS:-}"
AWOOOI_DB_HOST="localhost"
AWOOOI_DB_PORT="5432"
K3S_DB_USER="postgres"
LOCAL_REPO="${BACKUP_BASE}/awoooi"
DUMP_DIR="/tmp/awoooi-backup-$$"
quote_remote() {
printf "%q" "$1"
}
pgpass_escape() {
local value="$1"
value="${value//\\/\\\\}"
value="${value//:/\\:}"
printf '%s' "${value}"
}
pgpass_line() {
local database="$1"
printf '%s:%s:%s:%s:%s\n' \
"$(pgpass_escape "${AWOOOI_DB_HOST}")" \
"$(pgpass_escape "${AWOOOI_DB_PORT}")" \
"$(pgpass_escape "${database}")" \
"$(pgpass_escape "${AWOOOI_DB_USER}")" \
"$(pgpass_escape "${AWOOOI_DB_PASS}")"
}
remote_pgpass_wrapper() {
local command="$1"
printf 'umask 077; pgpass=$(mktemp "${TMPDIR:-/tmp}/awoooi-pgpass.XXXXXX") || exit 1; cleanup() { rm -f "$pgpass"; }; trap cleanup EXIT HUP INT TERM; cat > "$pgpass"; PGPASSFILE="$pgpass" %s' "${command}"
}
run_remote_pg_dump() {
local database="$1"
local output_file="$2"
local stderr_file="${output_file}.stderr"
local command
command="pg_dump --no-password -U $(quote_remote "${AWOOOI_DB_USER}") -h $(quote_remote "${AWOOOI_DB_HOST}") -p $(quote_remote "${AWOOOI_DB_PORT}") $(quote_remote "${database}")"
if pgpass_line "${database}" \
| ssh "ollama@${AWOOOI_HOST}" "$(remote_pgpass_wrapper "${command}")" \
>"${output_file}" 2>"${stderr_file}"; then
rm -f "${stderr_file}"
return 0
fi
tail -40 "${stderr_file}" | sed -E 's/(password=)[^ ]+/\1REDACTED/g' >&2 || true
rm -f "${stderr_file}"
return 1
}
# 保留策略覆寫(比其他服務更長)
KEEP_DAILY=14 # 14 天每日
KEEP_WEEKLY=8 # 8 週每週
@@ -31,6 +76,12 @@ main() {
local start_time=$(date +%s)
local failed=0
if [ -z "${AWOOOI_DB_PASS}" ]; then
log_error "AWOOOI_DB_PASS is unavailable; refusing an unauthenticated or hardcoded fallback"
notify_clawbot "failed" "${SERVICE}" "AWOOOI DB backup credential unavailable"
exit 1
fi
log_info "========== 開始 AWOOOI 資料庫備份 =========="
mkdir -p "${DUMP_DIR}"
@@ -38,9 +89,8 @@ main() {
log_info "Dump awoooi_prod..."
local timestamp=$(date "+%Y%m%d_%H%M%S")
if ssh ollama@${AWOOOI_HOST} "PGPASSWORD='${AWOOOI_DB_PASS}' pg_dump \
-U ${AWOOOI_DB_USER} -h ${AWOOOI_DB_HOST} -p ${AWOOOI_DB_PORT} \
awoooi_prod" > "${DUMP_DIR}/awoooi_prod_${timestamp}.sql" 2>&1; then
if run_remote_pg_dump \
"awoooi_prod" "${DUMP_DIR}/awoooi_prod_${timestamp}.sql"; then
local size=$(du -h "${DUMP_DIR}/awoooi_prod_${timestamp}.sql" | cut -f1)
log_success "awoooi_prod dump 完成 (${size})"
else
@@ -50,9 +100,8 @@ main() {
# Step 2: awoooi_dev dump
log_info "Dump awoooi_dev..."
if ssh ollama@${AWOOOI_HOST} "PGPASSWORD='${AWOOOI_DB_PASS}' pg_dump \
-U ${AWOOOI_DB_USER} -h ${AWOOOI_DB_HOST} -p ${AWOOOI_DB_PORT} \
awoooi_dev 2>/dev/null" > "${DUMP_DIR}/awoooi_dev_${timestamp}.sql" 2>/dev/null; then
if run_remote_pg_dump \
"awoooi_dev" "${DUMP_DIR}/awoooi_dev_${timestamp}.sql"; then
local size=$(du -h "${DUMP_DIR}/awoooi_dev_${timestamp}.sql" | cut -f1)
log_success "awoooi_dev dump 完成 (${size})"
else
@@ -61,9 +110,8 @@ main() {
# Step 3: k3s_datastore dumpKine 後端)
log_info "Dump k3s_datastore..."
if ssh ollama@${AWOOOI_HOST} "PGPASSWORD='${AWOOOI_DB_PASS}' pg_dump \
-U ${AWOOOI_DB_USER} -h ${AWOOOI_DB_HOST} -p ${AWOOOI_DB_PORT} \
k3s_datastore 2>/dev/null" > "${DUMP_DIR}/k3s_datastore_${timestamp}.sql" 2>/dev/null; then
if run_remote_pg_dump \
"k3s_datastore" "${DUMP_DIR}/k3s_datastore_${timestamp}.sql"; then
local size=$(du -h "${DUMP_DIR}/k3s_datastore_${timestamp}.sql" | cut -f1)
log_success "k3s_datastore dump 完成 (${size})"
else

View File

@@ -0,0 +1,25 @@
from __future__ import annotations
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[3]
SCRIPT = ROOT / "scripts" / "backup" / "backup-awoooi.sh"
def test_daily_backup_has_no_hardcoded_database_password() -> None:
text = SCRIPT.read_text(encoding="utf-8")
assignment = re.search(r"^AWOOOI_DB_PASS=(.+)$", text, re.MULTILINE)
assert assignment is not None
assert assignment.group(1) == '"${AWOOOI_DB_PASS:-}"'
assert "PGPASSWORD='${AWOOOI_DB_PASS}'" not in text
assert 'PGPASSFILE="$pgpass"' in text
assert "pg_dump --no-password" in text
def test_daily_backup_fails_closed_without_runtime_credential() -> None:
text = SCRIPT.read_text(encoding="utf-8")
assert 'if [ -z "${AWOOOI_DB_PASS}" ]; then' in text
assert "refusing an unauthenticated or hardcoded fallback" in text