nas-burnin/scripts/regenerate-lockfile.sh
Brandon Walter 992e2c47b3
Some checks are pending
Security scan / pip-audit (push) Waiting to run
Security scan / bandit (push) Waiting to run
Security scan / gitleaks (push) Waiting to run
deps: pin transitive dependencies via lockfile (1.0.0-25)
Closes the unpinned-deps gotcha that broke production once already
(Starlette 1.0 shipping in 2026-04 changed the TemplateResponse
signature; our floating requirements.txt picked it up on the next
rebuild and the dashboard 500'd until 1.0.0-12 patched the call sites).

Mechanics:
* `requirements.in` — human-edited input, identical contents to the
  old `requirements.txt`.
* `requirements.txt` — now an autogenerated lockfile (876 lines, every
  transitive pinned with sha256 hashes). Regenerated via
  `scripts/regenerate-lockfile.sh`, which runs `pip-compile
  --generate-hashes --strip-extras` in a clean python:3.12-slim
  container so the script has no host dependencies.
* Dockerfile installs with `pip install --require-hashes` — refuses
  any package whose sha256 doesn't match the lockfile, defending
  against compromised PyPI mirrors and accidental version drift.

Verification:
* Container boots clean on the hash-locked install (1.0.0-25).
* /health returns 200 with all checks green.
* Daily security scan (pip-audit + bandit + gitleaks) returns 0 findings
  against the new lockfile.

Future deps changes: edit requirements.in, run the regenerate script,
review the diff, rebuild, commit both files. README §"Updating
dependencies" walks through it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 17:15:02 -04:00

45 lines
1.5 KiB
Bash
Executable file

#!/usr/bin/env bash
# Regenerate requirements.txt from requirements.in.
#
# Run this whenever you add, remove, or change a constraint in
# requirements.in — never edit requirements.txt by hand. The output is
# a fully-pinned lockfile with sha256 hashes, consumed at image-build
# time with `pip install --require-hashes`.
#
# Runs pip-compile in a clean python:3.12-slim container so this script
# has no host dependencies — Docker is enough.
#
# Usage:
# ./scripts/regenerate-lockfile.sh
#
# After it runs:
# - Review the diff (`git diff requirements.txt`) — bumps to
# transitive deps may be CVE fixes or breaking changes
# - Rebuild the container locally to confirm install + boot
# - Commit requirements.in AND requirements.txt together
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"
if [ ! -f requirements.in ]; then
echo "fatal: requirements.in not found in $REPO_ROOT" >&2
exit 1
fi
echo "Regenerating requirements.txt from requirements.in ..."
docker run --rm \
-v "$REPO_ROOT:/work" \
-w /work \
python:3.12-slim \
bash -c "
pip install --quiet --no-cache-dir --disable-pip-version-check pip-tools 2>&1 | tail -3
pip-compile --quiet --generate-hashes --strip-extras \
--output-file=requirements.txt requirements.in
chown $(id -u):$(id -g) requirements.txt
"
echo "Done. New lockfile is $(wc -l < requirements.txt) lines."
echo "Review: git diff requirements.txt"
echo "Verify: docker compose build app && docker compose up -d app"