From 6d77775bd6ee97ac88b493d6b3a0e92bc786ab8e Mon Sep 17 00:00:00 2001 From: reachableceo Date: Mon, 27 Jul 2026 10:13:04 -0500 Subject: [PATCH] test(validation): preserve sandbox access across SSH hardening MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit secharden-ssh intentionally replaces authorized_keys with the managed production key set, which locks out the bootstrap/dev key the validation harness uses to drive the VM. After the first deploy that reaches SSH hardening, the harness could no longer connect to fetch logs or run the test suite, breaking the iteration loop. Add restore_vm_access(): after each deploy, if SSH is unreachable, it re-injects the validation pubkey OUT OF BAND via the Proxmox guest agent (qm guest exec runs as root inside the VM and does not depend on SSH). The injected payload is prefixed with a newline to avoid key concatenation when the managed file lacks a trailing newline. Config: ACCESS_PUBKEY (default ~/.ssh/id_ed25519.pub), RESTORE_ACCESS=1. Disable with RESTORE_ACCESS=0. 🤖 Generated with [Crush](https://github.com/charmassociates/crush) Assisted-by: GLM-5 via Crush --- Project-Tests/vm-validation.sh | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Project-Tests/vm-validation.sh b/Project-Tests/vm-validation.sh index db55399..b6d924e 100755 --- a/Project-Tests/vm-validation.sh +++ b/Project-Tests/vm-validation.sh @@ -54,6 +54,11 @@ VM_ID="${VM_ID:-}" REPO_URL="${REPO_URL:-https://git.knownelement.com/KNEL/KNELServerBuild.git}" REMOTE_REPO="${REMOTE_REPO:-KNELServerBuild}" SNAP_PREFIX="${SNAP_PREFIX:-pre-knel-deploy}" +ACCESS_PUBKEY="${ACCESS_PUBKEY:-$HOME/.ssh/id_ed25519.pub}" +# Re-inject the validation pubkey after each deploy (secharden-ssh replaces +# authorized_keys with the managed production key set, locking out the +# bootstrap/dev key). Set RESTORE_ACCESS=0 to disable. +RESTORE_ACCESS="${RESTORE_ACCESS:-1}" HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_SRC="$(cd "$HERE/.." && pwd)" @@ -99,6 +104,34 @@ resolve_remote_repo() { vm "cd ~/${REMOTE_REPO} 2>/dev/null && pwd" } +# Re-inject the validation pubkey into ~$VM_USER/.ssh/authorized_keys OUT OF +# BAND via the Proxmox guest agent (qm guest exec runs as root inside the VM +# and does not depend on SSH). This is necessary because secharden-ssh replaces +# authorized_keys with the managed production key set, which would otherwise +# lock out the bootstrap key used to drive validation. No-op if SSH still works. +restore_vm_access() { + [[ "$RESTORE_ACCESS" = "1" ]] || { log "RESTORE_ACCESS=0; skipping access restore."; return 0; } + [[ -f "$ACCESS_PUBKEY" ]] || { log "WARN: ACCESS_PUBKEY not found ($ACCESS_PUBKEY); cannot restore access."; return 0; } + if vm 'true' >/dev/null 2>&1; then + log "SSH access already works; no need to restore." + return 0 + fi + log "SSH access lost (expected after secharden-ssh). Restoring via Proxmox guest agent..." + local payload_b64 + # Leading newline guards against the managed authorized_keys lacking a + # trailing newline (which would otherwise concatenate two keys into one). + payload_b64="$(printf '\n%s' "$(cat "$ACCESS_PUBKEY")" | base64 -w0)" + prox "qm guest exec $VM_ID -- /bin/sh -c 'echo $payload_b64 | base64 -d >> /home/${VM_USER}/.ssh/authorized_keys'" \ + >/dev/null 2>&1 || { log "WARN: guest-agent key append failed."; return 0; } + prox "qm guest exec $VM_ID -- /bin/sh -c 'chown ${VM_USER}:${VM_USER} /home/${VM_USER}/.ssh/authorized_keys; chmod 600 /home/${VM_USER}/.ssh/authorized_keys'" \ + >/dev/null 2>&1 || true + if vm 'true' >/dev/null 2>&1; then + log "Access restored." + else + log "WARN: access still not working after restore. Check the deployed sshd_config." + fi +} + # --------------------------------------------------------------------------- # Commands # --------------------------------------------------------------------------- @@ -211,6 +244,11 @@ cmd_deploy() { runner_abs="$(vm "cd ~/${REMOTE_REPO}/Project-Tests/.run && pwd")/remote-setup-runner.sh" vmroot "bash '$runner_abs' '$repo_abs'" 2>&1 | tee -a "$LOCAL_LOG" || true + # secharden-ssh (run near the end of setup) replaces authorized_keys with the + # managed production key set, locking out the bootstrap key. Restore the + # validation key out-of-band BEFORE we try to fetch the log over SSH. + restore_vm_access + # Fetch the remote log for full fidelity (strip ANSI color codes). vm "sed -r 's/\\x1B\\[[0-9;]*[mK]//g' /tmp/knel-setup.log 2>/dev/null || cat /tmp/knel-setup.log" \ > "$LOCAL_LOG_DIR/setup-output-${STAMP}.log" 2>/dev/null || true