From e93201a5c6cb0d70ae1f32b427ef4d0a00892014 Mon Sep 17 00:00:00 2001 From: "Marcel T." <105316958+MarcelT87@users.noreply.github.com> Date: Mon, 5 Oct 2026 16:21:59 +0200 Subject: [PATCH 1/3] fix: validate and recover existing virtualenv --- install.sh | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/install.sh b/install.sh index 53a1dbc..b9f94fd 100644 --- a/install.sh +++ b/install.sh @@ -5,25 +5,82 @@ ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) cd "$ROOT" PYTHON_BIN=${PYTHON:-python3} +VENV_DIR=".venv" + +python_supported() { + "$1" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 11) else 1)' >/dev/null 2>&1 +} if ! command -v "$PYTHON_BIN" >/dev/null 2>&1; then echo "error: $PYTHON_BIN was not found" >&2 exit 2 fi -if ! "$PYTHON_BIN" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 11) else 1)'; then +if ! python_supported "$PYTHON_BIN"; then echo "error: Python 3.11 or newer is required" >&2 "$PYTHON_BIN" --version >&2 || true exit 2 fi -if [ ! -d .venv ]; then +if [ -L "$VENV_DIR" ]; then + echo "error: $VENV_DIR is a symbolic link; refusing to modify it" >&2 + echo "move or remove that link, then run: bash install.sh" >&2 + exit 2 +fi + +if [ -e "$VENV_DIR" ] && [ ! -d "$VENV_DIR" ]; then + echo "error: $VENV_DIR exists but is not a directory" >&2 + echo "move or remove it, then run: bash install.sh" >&2 + exit 2 +fi + +if [ -d "$VENV_DIR" ]; then + if [ ! -f "$VENV_DIR/pyvenv.cfg" ]; then + echo "error: $VENV_DIR exists but does not look like a Python virtual environment" >&2 + echo "move or remove that directory, then run: bash install.sh" >&2 + echo "no files were removed" >&2 + exit 2 + fi + + if ( + [ ! -x "$VENV_DIR/bin/python" ] || + ! python_supported "$VENV_DIR/bin/python" || + ! "$VENV_DIR/bin/python" -m pip --version >/dev/null 2>&1 + ); then + echo "Existing .venv is unusable or uses an unsupported Python." + echo "Recreating the local virtual environment..." + rm -rf "$VENV_DIR" + else + echo "Using existing virtual environment." + fi +fi + +if [ ! -d "$VENV_DIR" ]; then echo "Creating virtual environment..." - "$PYTHON_BIN" -m venv .venv + "$PYTHON_BIN" -m venv "$VENV_DIR" +fi + +if [ ! -x "$VENV_DIR/bin/python" ]; then + echo "error: virtual environment creation did not provide $VENV_DIR/bin/python" >&2 + echo "check that Python virtual-environment support is installed, then rerun install.sh" >&2 + exit 2 +fi + +if ! python_supported "$VENV_DIR/bin/python"; then + echo "error: virtual environment Python is older than 3.11" >&2 + "$VENV_DIR/bin/python" --version >&2 || true + echo "remove $VENV_DIR and rerun: bash install.sh" >&2 + exit 2 +fi + +if ! "$VENV_DIR/bin/python" -m pip --version >/dev/null 2>&1; then + echo "error: pip is not available inside $VENV_DIR" >&2 + echo "remove $VENV_DIR and rerun: bash install.sh" >&2 + exit 2 fi echo "Installing ebus-evidence..." -.venv/bin/python -m pip install -e . +"$VENV_DIR/bin/python" -m pip install -e . cat > evidence <<'EOF' #!/usr/bin/env sh From 8e3bfa4c45c4c4285ce77491dd50b48f3c491b1d Mon Sep 17 00:00:00 2001 From: "Marcel T." <105316958+MarcelT87@users.noreply.github.com> Date: Mon, 5 Oct 2026 16:22:53 +0200 Subject: [PATCH 2/3] test: cover existing virtualenv recovery --- .github/workflows/tests.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 457bde4..b1de53e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -68,6 +68,23 @@ jobs: ./evidence --version ./evidence --help + - name: Reinstall reuses a healthy virtualenv + run: | + bash install.sh | tee /tmp/evidence-reinstall.log + grep -F "Using existing virtual environment." /tmp/evidence-reinstall.log + ./evidence --version + + - name: Broken recognized virtualenv is recreated without touching data + run: | + mkdir -p data + printf 'keep-me\n' > data/install-preserve-marker + rm .venv/bin/python + bash install.sh | tee /tmp/evidence-recreate.log + grep -F "Recreating the local virtual environment..." /tmp/evidence-recreate.log + test -x .venv/bin/python + grep -Fx "keep-me" data/install-preserve-marker + ./evidence --version + - name: Beginner workflow on synthetic raw log run: | cp tests/fixtures/sample.raw /tmp/ebusd-evidence-test.raw @@ -93,5 +110,22 @@ jobs: ./evidence verify data/evidence.zip ./evidence verify --submission data/evidence.zip + - name: Unknown .venv directory is never deleted automatically + run: | + rm -rf .venv + mkdir .venv + printf 'do-not-delete\n' > .venv/KEEP + if bash install.sh > /tmp/evidence-unsafe-venv.log 2>&1; then + cat /tmp/evidence-unsafe-venv.log + echo "installer unexpectedly accepted an unknown .venv directory" >&2 + exit 1 + fi + cat /tmp/evidence-unsafe-venv.log + grep -F "does not look like a Python virtual environment" /tmp/evidence-unsafe-venv.log + grep -Fx "do-not-delete" .venv/KEEP + rm -rf .venv + bash install.sh + ./evidence --version + - name: Bootstrap leaves checkout clean run: test -z "$(git status --porcelain)" From 3e5c8db6dac89eb9d3ae8434869a690fed6423cc Mon Sep 17 00:00:00 2001 From: "Marcel T." <105316958+MarcelT87@users.noreply.github.com> Date: Mon, 5 Oct 2026 16:23:08 +0200 Subject: [PATCH 3/3] docs: explain safe virtualenv recovery --- docs/INSTALL.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 16f01e7..9a8b139 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -128,6 +128,9 @@ The installer: - checks for Python 3.11+; - creates a local `.venv` when needed; +- reuses a healthy existing `.venv`; +- automatically recreates a recognizable but unusable project-local `.venv`; +- refuses to delete an unexpected directory or symbolic link named `.venv`; - installs the current checkout; - enables the local `./evidence` launcher. @@ -147,6 +150,27 @@ Check: You do not need to activate the virtual environment when using `./evidence`. +### Re-running the installer + +Running + +```bash +bash install.sh +``` + +again is safe for normal upgrades. + +If the existing project-local `.venv` is healthy, it is reused. If it is a +recognizable Python virtual environment but its Python/pip is missing, +unsupported or unusable, only that disposable `.venv` is recreated. + +Runtime data such as `data/` and collected Evidence is not removed by this +repair. + +If `.venv` is instead an unexpected ordinary directory or a symbolic link, +the installer stops and asks you to move/remove it manually rather than +deleting unknown files. + ### Advanced/manual installation The standard Python path remains supported: