Files
nisse/scripts/review-bringup.sh
T
dongarandClaude Opus 5.5 2fb654f92b
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 1m49s
CI / e2e (pull_request) Successful in 4m0s
M7.6: nisse-review's image
A `review` target in the Dockerfile: its own user (nisse-review, uid
10002), git for its clones, state and clones in /var/lib/nisse-review,
configuration at /etc/nisse-review, and only its own agent installed.
release.yml publishes gitea.dongar.net/dev/nisse-review beside nisse-dev,
at the same version. review-bringup.sh builds and runs the image, as
bringup.sh runs nisse-dev's.

The test stage adds an agent package its base lacks, without its
dependencies, since the suite's own code imports every agent's. Without
that, the tests over nisse-dev's image no longer import since
test_review_live arrived. tests/deploy/test_images.py checks the image and
that the test stage leaves what it installed as it was.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
2026-10-20 00:05:31 +00:00

91 lines
3.8 KiB
Bash
Executable File

#!/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