Pin verified pip bootstrap and resume truncated package downloads
All checks were successful
Deploy production / deploy (push) Successful in 12m37s
All checks were successful
Deploy production / deploy (push) Successful in 12m37s
This commit is contained in:
parent
7ed495ce64
commit
1f64bb9dee
@ -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-транспорт
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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" \
|
||||
|
||||
2
ops/deploy/pip-bootstrap.txt
Normal file
2
ops/deploy/pip-bootstrap.txt
Normal file
@ -0,0 +1,2 @@
|
||||
# PyPI wheel for pip 26.2.1; bootstrap itself remains hash-verified.
|
||||
pip==26.2.1 --hash=sha256:71138adf1f4ca900cdb7d289c21b7494329f2332b6d85f0e1c42108c0384ed3e
|
||||
@ -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):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user