From 5968df5b422986a5ca2378f547a22691be4ba332 Mon Sep 17 00:00:00 2001 From: bunker-admin Date: Thu, 16 Apr 2026 15:17:54 -0600 Subject: [PATCH] release: scripts/*.sh whitelist parity check in build-release.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the implicit runtime-scripts for-loop with two explicit arrays (RUNTIME_SCRIPTS + DEV_ONLY_SCRIPTS) and a pre-build assertion that aborts if any scripts/*.sh isn't classified. Motivation: during the v2.9.8 sprint we added three new scripts (pangolin-teardown.sh, ccp-deregister.sh, validate-env.sh) and had to manually remember to include each in the whitelist. Missing one is silent — the script just doesn't ship, and the release tarball is subtly broken in a way you only notice when the docs reference the missing script. The parity check surfaces the decision: every new scripts/*.sh must be deliberately classified as ship (RUNTIME_SCRIPTS) or don't-ship (DEV_ONLY_SCRIPTS). Adding a script and forgetting aborts the build with a clear message naming the unclassified file. Side-effect fixes from this audit: - register-with-ccp.sh is now shipped (was only in source; needed for retrofitting CCP onto existing installs) - update-env.sh is now shipped (safe .env updater used by upgrade flows) Bunker Admin --- scripts/build-release.sh | 62 +++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/scripts/build-release.sh b/scripts/build-release.sh index 338dbc20..12a2c013 100755 --- a/scripts/build-release.sh +++ b/scripts/build-release.sh @@ -117,18 +117,63 @@ mkdir -p "$STAGE_DIR/scripts" cp "$PROJECT_DIR/api/prisma/init-nocodb-db.sh" "$STAGE_DIR/scripts/" cp "$PROJECT_DIR/api/prisma/init-gancio-db.sh" "$STAGE_DIR/scripts/" -# Runtime scripts -for script in nocodb-init.sh gitea-init.sh mkdocs-entrypoint.sh \ - backup.sh restore.sh \ - upgrade.sh upgrade-check.sh upgrade-watcher.sh \ - uninstall.sh test-deployment.sh \ - validate-env.sh pangolin-teardown.sh ccp-deregister.sh; do +# Explicit allow/deny lists for scripts/*.sh. Every shell script in scripts/ +# must appear in exactly one of these arrays — the parity check below aborts +# the build if anything is unaccounted for. This catches the "added a new +# script, forgot to add it to the release" drift bug. +RUNTIME_SCRIPTS=( + # Ship in the release tarball — user-facing or invoked by containers/upgrades + install.sh + nocodb-init.sh gitea-init.sh mkdocs-entrypoint.sh + backup.sh restore.sh + upgrade.sh upgrade-check.sh upgrade-watcher.sh + uninstall.sh test-deployment.sh + validate-env.sh pangolin-teardown.sh ccp-deregister.sh register-with-ccp.sh + update-env.sh +) + +DEV_ONLY_SCRIPTS=( + # Deliberately NOT shipped — dev-machine tooling (build/release/mirror/CI) + build-and-push.sh build-release.sh + mirror-images.sh validate-compose-parity.sh +) + +# --- Parity check: every scripts/*.sh must be classified --- +declare -A KNOWN_SCRIPTS +for s in "${RUNTIME_SCRIPTS[@]}" "${DEV_ONLY_SCRIPTS[@]}"; do + KNOWN_SCRIPTS[$s]=1 +done + +UNCLASSIFIED=() +for f in "$PROJECT_DIR"/scripts/*.sh; do + [[ -f "$f" ]] || continue + name=$(basename "$f") + if [[ -z "${KNOWN_SCRIPTS[$name]:-}" ]]; then + UNCLASSIFIED+=("$name") + fi +done + +if [[ ${#UNCLASSIFIED[@]} -gt 0 ]]; then + error "build-release.sh parity check failed — unclassified scripts/*.sh:" + for name in "${UNCLASSIFIED[@]}"; do + echo " - $name" >&2 + done + echo "" >&2 + echo " Every script in scripts/*.sh must be classified as either:" >&2 + echo " RUNTIME_SCRIPTS — ships in the release tarball" >&2 + echo " DEV_ONLY_SCRIPTS — stays on dev/build machines only" >&2 + echo " Edit scripts/build-release.sh and add each to the correct array." >&2 + exit 1 +fi + +# Copy the runtime scripts +for script in "${RUNTIME_SCRIPTS[@]}"; do if [[ -f "$PROJECT_DIR/scripts/$script" ]]; then cp "$PROJECT_DIR/scripts/$script" "$STAGE_DIR/scripts/" fi done -# MkDocs build trigger +# MkDocs build trigger (python, not in the allowlist because it's .py) if [[ -f "$PROJECT_DIR/scripts/mkdocs-build-trigger.py" ]]; then cp "$PROJECT_DIR/scripts/mkdocs-build-trigger.py" "$STAGE_DIR/scripts/" fi @@ -138,9 +183,6 @@ if [[ -d "$PROJECT_DIR/scripts/systemd" ]]; then cp -r "$PROJECT_DIR/scripts/systemd" "$STAGE_DIR/scripts/" fi -# Install script (for reference) -cp "$PROJECT_DIR/scripts/install.sh" "$STAGE_DIR/scripts/" - chmod +x "$STAGE_DIR/scripts/"*.sh 2>/dev/null || true info "Scripts ($(ls "$STAGE_DIR/scripts/" | wc -l) files)"