#!/usr/bin/env bash # Bring-up runs of nisse-review on this development VM (Development Plan M7.3). # # It runs as its container image (M7.6), built from the code under test, as # a transient systemd unit, so it outlives the shell that started it. It runs # on the agent host after M7.7. # # $REVIEW is mounted at the same path inside the container, so the config's # paths (state_db, the vault) mean the same there; for that it runs as root # here, as bringup.sh runs nisse-dev. In production the image runs as its # own user with a state volume (Dockerfile). # # scripts/review-bringup.sh start [REF] export REF (default HEAD), build it # into an image, start the reviewer # scripts/review-bringup.sh plan [REF] print what start would build and run # scripts/review-bringup.sh stop stop it cleanly (SIGTERM) # scripts/review-bringup.sh status the unit, and its items # scripts/review-bringup.sh logs follow its log # # Layout, under $REVIEW (default /root/nisse-review): # nisse-review.yaml, .env the config and its secrets (made by hand once) # code/ the exported code, built into the image # state.db, scratch/ its state, and repository clones kept between runs # vault/ its memory (memory/nisse-review) set -euo pipefail REVIEW=${NISSE_REVIEW:-/root/nisse-review} SRC=${NISSE_SRC:-/root/nisse} UNIT=nisse-review-bringup IMAGE=nisse-review:bringup die() { echo "review-bringup: $*" >&2; exit 1; } running() { systemctl is-active --quiet "$UNIT"; } # The container the unit runs: host networking (Gitea, LiteLLM as here), # $REVIEW at its own path, the config and secrets from it. docker_run() { echo docker run --rm --name "$UNIT" --network host --user 0 \ -v "$REVIEW:$REVIEW" -w "$REVIEW" \ -e NISSE_CONFIG="$REVIEW/nisse-review.yaml" -e NISSE_ENV="$REVIEW/.env" \ "$IMAGE" } cmd_plan() { local ref=${1:-HEAD} sha sha=$(git -C "$SRC" rev-parse --verify "$ref^{commit}") || die "unknown ref $ref" echo "git -C $SRC archive $sha | tar -x -C $REVIEW/code" echo "docker build --target review -t $IMAGE $REVIEW/code" echo "systemd-run --unit=$UNIT ... $(docker_run)" } cmd_start() { local ref=${1:-HEAD} sha [ -f "$REVIEW/nisse-review.yaml" ] && [ -f "$REVIEW/.env" ] || die "no config in $REVIEW" running && die "already running; stop it first" sha=$(git -C "$SRC" rev-parse --verify "$ref^{commit}") || die "unknown ref $ref" # Export the code under test, so edits to the working tree can't change a # running reviewer. Uncommitted changes are not part of a run. rm -rf "$REVIEW/code" && mkdir -p "$REVIEW/code" "$REVIEW/vault/memory/nisse-review" git -C "$SRC" archive "$sha" | tar -x -C "$REVIEW/code" docker build --quiet --target review -t "$IMAGE" "$REVIEW/code" > /dev/null echo "$sha" > "$REVIEW/run-info" systemctl reset-failed "$UNIT" 2>/dev/null || true # SIGTERM reaches the reviewer through docker run's signal proxy; a stop # breaks off its run, which is redone on the next start. # shellcheck disable=SC2046 systemd-run --quiet --unit="$UNIT" --collect \ --property=KillSignal=SIGTERM --property=TimeoutStopSec=120 \ $(docker_run) echo "started $UNIT at $sha" } cmd_stop() { running && systemctl stop "$UNIT" || echo "not running"; } cmd_status() { systemctl status "$UNIT" --no-pager || true [ -f "$REVIEW/state.db" ] && sqlite3 "$REVIEW/state.db" \ "SELECT id, position, status, outcome FROM work_items ORDER BY opened_at" } cmd_logs() { journalctl -u "$UNIT" -f; } case "${1:-}" in start) shift; cmd_start "$@" ;; plan) shift; cmd_plan "$@" ;; stop) cmd_stop ;; status) cmd_status ;; logs) cmd_logs ;; *) die "usage: $0 start [REF] | plan [REF] | stop | status | logs" ;; esac