fix: QA remediation P1-D + P2 for infra/vps orchestrator (v1.8.0)

P1-D: bump package.json version 1.7.2 → 1.8.0 and add [1.8.0] CHANGELOG
entry documenting the infra/vps/ PRAB generation orchestrator addition.

P2 (security): replace StrictHostKeyChecking=no with StrictHostKeyChecking=accept-new
in all three SSH invocations in orchestrate-generation.sh. Add
UserKnownHostsFile=${KNOWN_HOSTS} (-o) to pin key verification to the
pre-seeded file rather than the root known_hosts.

install-orchestrator.sh: add ssh-keyscan step that pre-populates
/opt/prab-orchestrator/known_hosts with Hostinger's host key on first
install. Graceful degradation: if ssh-keyscan fails, logs WARN and
proceeds (accept-new will add the key on first real connect).

prab-generation.service: add justifying comment for User=root (root holds
the Hostinger SSH key + known_hosts in /root/.ssh/ and /opt/prab-orchestrator/).

Agent-Session: prab-reliability-remediation-20260622
This commit is contained in:
peptiderepo
2026-06-22 17:16:19 +00:00
parent d922a8368f
commit f3f579f5a8
5 changed files with 44 additions and 4 deletions

View File

@@ -1,5 +1,22 @@
# Changelog
## [1.8.0] - 2026-06-23
### Added
- **`infra/vps/` PRAB generation orchestrator**: systemd timer + service + bash
script that SSHes from the Coolify KVM8 VPS to Hostinger and drives
`wp prautoblogger generate --sync` in a held-open SSH session. Sidesteps
Hostinger's ~10-min background-PHP-process kill that was blocking full
generation runs. Components:
- `orchestrate-generation.sh`: main script with DRY_RUN mode, structured
logging, reaper pre-sweep, failure email alert, and shellcheck-clean quoting.
- `prab-generation.service` / `prab-generation.timer`: systemd oneshot service
(2h timeout, no auto-restart) + daily 06:00 UTC timer with 5-min jitter.
- `install-orchestrator.sh`: one-time setup script; installs units but does NOT
enable the timer (requires explicit CEO greenlight post-QA).
- Security: `StrictHostKeyChecking=accept-new` with pre-seeded known_hosts for
the Hostinger IP; no hardcoded secrets; SSH key referenced by env-var path.
## [1.7.2] - 2026-06-17
### Fixed

View File

@@ -45,6 +45,21 @@ mkdir -p "${INSTALL_DIR}"
install -m 0750 "${ORCHESTRATE_SH}" "${INSTALL_DIR}/orchestrate-generation.sh"
echo " OK: ${INSTALL_DIR}/orchestrate-generation.sh"
# Pre-seed known_hosts with Hostinger's host key so ssh(1) can verify
# the server identity without StrictHostKeyChecking=no.
# ssh-keyscan output is pinned here; re-run if Hostinger rotates its key.
KNOWN_HOSTS_FILE="${INSTALL_DIR}/known_hosts"
if [[ ! -f "${KNOWN_HOSTS_FILE}" ]]; then
echo "Pre-seeding known_hosts from Hostinger (${SSH_HOST:-145.223.107.228}:${SSH_PORT:-65002})..."
ssh-keyscan -p "${SSH_PORT:-65002}" "${SSH_HOST:-145.223.107.228}" \
> "${KNOWN_HOSTS_FILE}" 2>/dev/null \
&& chmod 0600 "${KNOWN_HOSTS_FILE}" \
&& echo " OK: ${KNOWN_HOSTS_FILE}" \
|| echo " WARN: ssh-keyscan failed — known_hosts not seeded; first SSH will add key via accept-new"
else
echo " OK: ${KNOWN_HOSTS_FILE} (already exists, not overwritten)"
fi
echo "Installing systemd units..."
install -m 0644 "${SERVICE_FILE}" "${SYSTEMD_DIR}/prab-generation.service"
install -m 0644 "${TIMER_FILE}" "${SYSTEMD_DIR}/prab-generation.timer"

View File

@@ -36,6 +36,9 @@ SSH_HOST="${SSH_HOST:-145.223.107.228}"
SSH_PORT="${SSH_PORT:-65002}"
SSH_USER="${SSH_USER:-u117248512}"
WP_PATH="${WP_PATH:-/home/u117248512/domains/peptiderepo.com/public_html}"
# Known-hosts file pre-seeded by install-orchestrator.sh with Hostinger's host key.
# Pins the server identity; StrictHostKeyChecking=accept-new adds on first connect.
KNOWN_HOSTS="${KNOWN_HOSTS:-/opt/prab-orchestrator/known_hosts}"
# ---------------------------------------------------------------------------
# Logging helpers
@@ -66,7 +69,7 @@ fi
# ---------------------------------------------------------------------------
if [[ "${DRY_RUN}" == "1" ]]; then
log "DRY_RUN=1 — echoing commands only, no generation"
log "WOULD RUN: ssh -i ${SSH_KEY} -p ${SSH_PORT} -o StrictHostKeyChecking=no -o ConnectTimeout=15 ${SSH_USER}@${SSH_HOST} \\"
log "WOULD RUN: ssh -i ${SSH_KEY} -p ${SSH_PORT} -o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 ${SSH_USER}@${SSH_HOST} \\"
log " 'wp prautoblogger generate --sync --path=${WP_PATH} 2>&1'"
log "DRY_RUN complete"
exit 0
@@ -90,7 +93,8 @@ REAP_OUT=""
# shellcheck disable=SC2029
REAP_OUT="$(ssh -i "${SSH_KEY}" \
-p "${SSH_PORT}" \
-o StrictHostKeyChecking=no \
-o StrictHostKeyChecking=accept-new \
-o UserKnownHostsFile="${KNOWN_HOSTS}" \
-o ConnectTimeout=15 \
-o ServerAliveInterval=60 \
-o ServerAliveCountMax=30 \
@@ -112,7 +116,8 @@ EXIT_CODE=0
# shellcheck disable=SC2029
RESULT_OUTPUT="$(ssh -i "${SSH_KEY}" \
-p "${SSH_PORT}" \
-o StrictHostKeyChecking=no \
-o StrictHostKeyChecking=accept-new \
-o UserKnownHostsFile="${KNOWN_HOSTS}" \
-o ConnectTimeout=15 \
-o ServerAliveInterval=60 \
-o ServerAliveCountMax=30 \

View File

@@ -7,6 +7,9 @@ After=network.target
[Service]
Type=oneshot
# root owns /root/.ssh/hostinger_prod_ed25519 and /opt/prab-orchestrator/known_hosts;
# a dedicated service user would need its own keypair + sudo-less SSH access.
# Acceptable on this dedicated lab VPS (not shared); revisit if VPS is multi-tenant.
User=root
ExecStart=/opt/prab-orchestrator/orchestrate-generation.sh
StandardOutput=journal

View File

@@ -1,6 +1,6 @@
{
"name": "peptide-e2e",
"version": "1.7.2",
"version": "1.8.0",
"description": "Playwright smoke tests for peptiderepo.com (staging + production)",
"private": true,
"scripts": {