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
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:
@@ -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 dump(Kine 後端)
|
||||
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
|
||||
|
||||
25
scripts/backup/tests/test_backup_awoooi_secret_contract.py
Normal file
25
scripts/backup/tests/test_backup_awoooi_secret_contract.py
Normal 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
|
||||
Reference in New Issue
Block a user