release: scripts/*.sh whitelist parity check in build-release.sh

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
This commit is contained in:
bunker-admin 2026-04-16 15:17:54 -06:00
parent 824f3cce99
commit 5968df5b42

View File

@ -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)"