chore(scripts): rewrite the CI guards and operator scripts in Nushell #492
Loading…
Reference in a new issue
No description provided.
Delete branch "chore/BUNYIP-490-nushell-ci-guards"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Every script under scripts/ is now a
#!/usr/bin/env nuscript with the executable bit set, replacing the eight Bash/POSIX-sh scripts. The seven guards check.yml invokes keep their exit-code contract exactly (0 pass, 1 violation, 2 cannot-run) and their failure messages stay at least as specific; grep/sed/awk pipelines became structured Nushell (glob,parse --regex,enumerate,complete) so the file:line reporting is data rather than string surgery.Each guard was proven to still fail on a deliberately introduced violation of the invariant it protects, against throwaway fixtures: duplicate and malformed migration versions and a missing dir; an edited and a deleted committed migration plus an unreachable base ref (and a migrations README edit still exempt, BUNYIP-458); a pull_request trigger on e2e.yml, an off-allowlist
secrets.*reference, and annpm ciwithout --ignore-scripts; check.yml off the dev label, a run-time C-toolchain install, a run-time Playwright-library install, and an unannotatedruns-on(with a commented-out install still passing); each of BUNYIP-426 F4/F6/F8/F10 including a tag-only base image and an undefined build stage; a reintroduced STRIPE_* env read and a reintroduced TOTP_ENCRYPTION_KEY_PREV, with the migrations/, e2e/ and self-exclusion paths still honoured.The three non-CI scripts converted too, so no .sh remains under scripts/. init-secrets was exercised end to end: .env quote stripping, dev-placeholder rejection, byte-exact secrets with mode 600, the derived database_url, the empty-file defensive fill, the legacy flat-to-oidc/ key migration (byte-identical), and a clean idempotent re-run. refresh-ip2-datasets was exercised against a local archive: install is byte-identical and atomic, and the missing-token, unknown-id, download-failure and invalid-zip branches all exit non-zero with the temp dir cleaned up (a
tryreplaces the shell EXIT trap). purge-staging-test-accounts was exercised against a throwaway postgres: dry-run by default, refusal without --i-know-this-is-not-prod, refusal on a wrong phrase, and the committed hard delete removing exactly the matched non-admin rows and their non-cascade dependents.Two behaviour fixes fell out of that testing rather than being ports. The purge script's preview and count queries used
psql -c, which does not expand:'pattern', so both always failed with a syntax error before any row was listed; they now go in on stdin like the DELETE block already did. Andinputreads the terminal rather than stdin, so a non-interactive --commit now refuses with a clear message and exit 3 instead of an I/O error.scripts/check-no-bash.nu is new and gates the removal: it fails on any tracked .sh file or POSIX-shell shebang under scripts/, and runs from both check.yml and
just check. Every in-repo reference to an old .sh path moved with it (check.yml, justfile, CLAUDE.md, .env.example, compose.yml, migrations/README.md, docs/, and the Rust doc comments in admin.rs, dashboard.rs and stripe.rs), and the Nushell prerequisite in docs/getting-started.md now names scripts/ alongside the just recipes.#BUNYIP-490