Pin verified pip bootstrap and resume truncated package downloads
All checks were successful
Deploy production / deploy (push) Successful in 12m37s

This commit is contained in:
admin i 2026-09-10 17:37:24 +03:00
parent 7ed495ce64
commit 1f64bb9dee
5 changed files with 28 additions and 1 deletions

View File

@ -70,6 +70,9 @@ UID 10001 имеет настоящую запись пользователя `r
до создания кандидата. `npm ci` использует строгую проверку engines и повторяет
только сетевые сбои: максимум три попытки под общим таймаутом и контролем диска.
Ошибки зависимостей и postinstall не маскируются повторными попытками.
В новой Python-venv закреплён pip 26.2.1 с проверкой SHA-256 bootstrap-wheel
и ограниченной докачкой оборванных загрузок. Несовпадение хешей по-прежнему
останавливает установку; активная venv и системный pip не обновляются.
Остановка Gunicorn использует SIGTERM и достаточный таймаут мягкого завершения.
Код 143 Next.js при штатной остановке не считается аварией. Telegram-транспорт

View File

@ -68,6 +68,11 @@ attempts under one 30-minute timeout and the same disk watchdog. Dependency,
engine and postinstall failures are not retried. The per-candidate npm cache is
removed after installation and with any failed candidate.
Each Python candidate bootstraps the pinned, SHA-256-verified pip wheel in
`pip-bootstrap.txt`. Package downloads use bounded retries/resume for truncated
network transfers. TLS and package hash checks remain enabled; a real integrity
mismatch still fails the deployment. The system pip and active venv are not changed.
The deployment requires at least 4 GiB and 50,000 free inodes before creating a
release. Build and database-dump process groups have a 30-minute timeout and are
monitored every two seconds; they are stopped if free space falls below 512 MiB

View File

@ -668,7 +668,12 @@ log "Creating an isolated Python environment."
run_bounded_build /usr/bin/python3 -m venv "${NEW_RELEASE}/backend/.venv"
run_bounded_build env PIP_DISABLE_PIP_VERSION_CHECK=1 \
"${NEW_RELEASE}/backend/.venv/bin/python" -m pip install \
--no-cache-dir --requirement "${NEW_RELEASE}/backend/requirements.txt"
--no-cache-dir --timeout=60 --retries=5 --only-binary=:all: --require-hashes \
--requirement "${NEW_RELEASE}/ops/deploy/pip-bootstrap.txt"
run_bounded_build env PIP_DISABLE_PIP_VERSION_CHECK=1 \
"${NEW_RELEASE}/backend/.venv/bin/python" -m pip install \
--no-cache-dir --timeout=60 --retries=5 --resume-retries=5 \
--requirement "${NEW_RELEASE}/backend/requirements.txt"
run_bounded_build "${NEW_RELEASE}/backend/.venv/bin/python" -m pip check
run_bounded_build "${NEW_RELEASE}/backend/.venv/bin/python" -c 'import shutil; assert shutil.which("magick") or shutil.which("convert"), "ImageMagick is required for safe oversized-image processing"'
run_bounded_build "${NEW_RELEASE}/backend/.venv/bin/python" \

View File

@ -0,0 +1,2 @@
# PyPI wheel for pip 26.2.1; bootstrap itself remains hash-verified.
pip==26.2.1 --hash=sha256:71138adf1f4ca900cdb7d289c21b7494329f2332b6d85f0e1c42108c0384ed3e

View File

@ -236,6 +236,18 @@ class DeploymentLifecycleTests(unittest.TestCase):
self.assertFalse((self.releases/TARGET).exists())
self.assertFalse((self.root/'npm_attempts').exists())
def test_pip_bootstrap_is_pinned_and_download_resume_keeps_hash_checks(self):
result = self.run_deploy()
self.assertEqual(result.returncode, 0, self.output)
commands = (self.root/'commands').read_text()
self.assertIn('pip-bootstrap.txt', commands)
self.assertIn('--require-hashes', commands)
self.assertIn('--resume-retries=5', commands)
self.assertNotIn('--trusted-host', commands)
self.assertNotIn('--no-require-hashes', commands)
bootstrap = (SOURCE.parent/'pip-bootstrap.txt').read_text()
self.assertIn('pip==26.2.1 --hash=sha256:', bootstrap)
def test_source_override_is_rejected_without_touching_live_release(self):
for stage in ('origin', 'url_rewrite'):
with self.subTest(stage=stage):