Files
praxis/scripts/proxmox/firstboot-hook.sh
T
Praxis CI 6cf63cb064 docs(P01): verify — APPROVE_WITH_NOTES, 4 P0 fixed, 18/20 REQ covered
Verification layers:
  Structural: PASS (all scripts executable, syntax clean, Dockerfile valid)
  Behavioral: PASS (121 bats, 77 pytest, docker build succeeds, compose valid)
  Security: PASS (no secrets committed, .dockerignore excludes .env*, env_file pattern)
  Quality: PASS (coreci patterns followed, no coreci refs, G-104/G-105/G-106 verified)

P0 issues found and auto-fixed:
  1. docker-compose.yml: removed invalid restart_policy key, fixed env_file syntax
  2. pyproject.toml: added fastapi + uvicorn deps (v0.1 gap exposed by Dockerfile)
  3. timing.sh: renamed coreci_deploy_timing → praxis_deploy_timing (TASK-03-07)
  4. firstboot-hook.sh: fixed idempotency check (/opt/praxis/.git not /usr/local/bin/praxis-deploy)

P1+ issues: 8 (1 fixed: lxc-config.sh default alignment, 7 noted for post-hoc review)
REQ coverage: 18/20 covered, 2 deferred (live first-boot timing + live E2E require cluster)
Must-haves: 25/28 pass, 2 partial (comment-only diffs, no Makefile), 1 deferred

---ci---
project: praxis
phase: 1
milestone: v0.2
status: verify
---/ci---
2026-08-03 18:37:45 +00:00

87 lines
3.0 KiB
Bash
Executable File

#!/bin/sh
# Praxis — Proxmox LXC first-boot hookscript.
#
# Adapted from coreci/scripts/proxmox/firstboot-hook.sh.
# Coreci fetches a pre-built Go binary + pct-pushes it; praxis installs
# Docker inside the CT, clones the repo from Gitea, builds the image,
# and starts the service via systemd (D-022, D-028, D-029).
#
# Referenced by lxc-config.sh via hookscript=local:snippets/praxis-firstboot.sh.
# Proxmox invokes this script at CT lifecycle phases on the PVE HOST
# (not inside the CT). The `post-start` phase does the work.
#
# G-101 FIX: GITEA_TOKEN is baked into this snippet by stage-snippet.sh
# (the hookscript runs on the PVE host where lxc.environment is invisible).
# The token is used to clone the private Gitea repo inside the CT.
#
# Proxmox passes: $1 = VMID, $2 = phase
# Environment (baked in by stage-snippet.sh):
# GITEA_TOKEN — bearer token for the private Gitea repo
# PRAXIS_VERSION — git ref (default: main)
# GITEA_HOST — Gitea hostname (default: git.cloudinit.dev)
set -eu
vmid="${1:-}"
phase="${2:-}"
log() { printf '[praxis-hook %s] %s\n' "$phase" "$*" >&2; }
case "$phase" in
post-start) : ;;
*) exit 0 ;;
esac
log "VMID=${vmid} — first-boot praxis install (Docker-in-LXC)"
VERSION="${PRAXIS_VERSION:-main}"
GITEA_HOST="${GITEA_HOST:-git.cloudinit.dev}"
GITEA_ORG="coreci"
GITEA_REPO="praxis"
CLONE_URL="https://${GITEA_TOKEN}@${GITEA_HOST}/${GITEA_ORG}/${GITEA_REPO}.git"
# Idempotency: skip if praxis is already installed and running.
# Check for the repo clone + active service (not a binary — praxis uses
# docker compose, not a /usr/local/bin binary like coreci).
if pct exec "$vmid" -- sh -c '[ -d /opt/praxis/.git ] && systemctl is-active --quiet praxis' 2>/dev/null; then
log "praxis already installed and active — skipping"
exit 0
fi
# Step 1: Install Docker + docker-compose-v2 inside the CT (D-028).
# Debian 12 standard template + nesting=1 supports Docker.
log "installing Docker inside CT ${vmid}"
pct exec "$vmid" -- sh -c '
set -e
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq docker.io docker-compose-v2 git curl
systemctl enable --now docker
'
# Step 2: Clone the praxis repo inside the CT (D-029).
# Clone to /opt/praxis (persistent across container restarts).
log "cloning praxis repo (ref=${VERSION}) into CT"
pct exec "$vmid" -- sh -c "
set -e
mkdir -p /opt/praxis
cd /opt/praxis
git clone --depth 1 --branch '${VERSION}' '${CLONE_URL}' . 2>&1 || {
# If the specific branch doesn't exist, fall back to main
log 'falling back to main branch'
git clone --depth 1 '${CLONE_URL}' . 2>&1
}
"
# Step 3: Write the env file from lxc.environment (passed via the CT's env).
# The lxc.environment vars are available inside the CT's environment.
# install-service.sh writes /etc/praxis/server.env from these.
log "running install-service inside CT"
pct exec "$vmid" -- sh -c '
set -e
cd /opt/praxis
sh scripts/install-service.sh
'
log "praxis installed and started in CT ${vmid}"
exit 0