Skip to content

⚡️(devx) improve "make bootstrap" setup time & update deps#745

Closed
sylvinus wants to merge 7 commits into
mainfrom
faster_front_build
Closed

⚡️(devx) improve "make bootstrap" setup time & update deps#745
sylvinus wants to merge 7 commits into
mainfrom
faster_front_build

Conversation

@sylvinus

@sylvinus sylvinus commented Jul 8, 2026

Copy link
Copy Markdown
Member

Upgrade or pin a few dependencies & add a "light" container set by default

Use a shared python base image

Upgrade dependencies

Summary by CodeRabbit

  • New Features

    • Added split light/full dev workflows for faster startup, restart, and bootstrap options.
    • Added new checks for frontend dependencies and additional MTA test jobs.
  • Bug Fixes

    • Updated environment file locations and Compose wiring for more reliable local and E2E setup.
    • Improved service readiness handling and dependency ordering in the dev stack.
  • Chores

    • Upgraded and pinned several runtime images and package versions for more consistent builds.
    • Updated deployment and self-hosting documentation to match the new file layout.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR reorganizes the dev workflow into light/full stack variants across the Makefile and compose.yaml, introduces a shared uv-managed Python base image consumed by backend and MTA Dockerfiles, pins numerous container images to digests, adds a frontend node_modules dependency guardrail, extends CI workflows with new build inputs and MTA test jobs, and relocates environment files from env.d to deploy/env alongside refactored PaaS deployment scripts.

Changes

Dev stack, frontend checks, and shared Python runtime

Layer / File(s) Summary
Makefile orchestration
Makefile
Adds PYTHON_UV_IMAGE, splits bootstrap/update/start/restart into light and full variants, adds start-deps, adjusts bucket expiry, and wires build-python-base into build, lint, test, migrate, and deps-lock targets.
Compose runtime services
compose.yaml
Adds shared ulimit/worker anchors, pins PostgreSQL/Mailcatcher/RustFS/Crowdin images, rewrites Keycloak with digest pin and healthcheck, adds light backend/worker services, moves frontend node_modules to a named volume, adds mta-out-uv, and updates env_file paths.
Frontend dependency guardrails
src/frontend/package.json, src/frontend/.npmrc, src/frontend/Dockerfile, src/frontend/scripts/check-node-modules.mjs, src/e2e/package.json, src/e2e/.npmrc, src/e2e/Dockerfile
Pins Node to 24.18.0, adds react-aria-components and version overrides, switches to npm ci with linked install strategy, adds check:deps/analyze scripts, and adds a node_modules size/forbidden-package scanner.
Workflow inputs and jobs
.github/workflows/docker-publish.yml, .github/workflows/messages-ghcr.yml, .github/workflows/messages.yml
Adds build_args/dockerfile inputs and image_ref output to the reusable publish workflow, adds a shared docker-publish-python-uv job feeding PYTHON_UV_IMAGE to backend/MTA builds, and adds test-mta-in/test-mta-in-py/test-mta-out CI jobs.
Shared Python uv base and service builds
deploy/python-uv/*, src/backend/Dockerfile, src/mta-in/Dockerfile*, src/mta-out/Dockerfile, src/jmap-email/Dockerfile, src/mpa/tests/Dockerfile, src/socks-proxy/tests/Dockerfile, */pyproject.toml, bin/release-jmap-email.sh, src/jmap-email/CONTRIBUTING.md, src/jmap-email/README.md
Introduces the shared uv-managed Python base image and strip-python helper, rewires downstream Dockerfiles to inherit from it, and bumps Python floor to 3.14.6 plus dependency versions across pyproject files.

Container image digest pinning

Layer / File(s) Summary
Service image pins
src/keycloak/Dockerfile, src/mpa/rspamd/Dockerfile
Pins Keycloak and rspamd base images to specific SHA256 digests.

Environment file relocation and PaaS deployment scripts

Layer / File(s) Summary
Environment file path migration
.dockerignore, .gitignore, docs/env.md, docs/self-hosting.md, src/backend/entrypoint, src/backend/messages/settings.py, src/e2e/README.md, src/e2e/compose.yaml
Updates ignore rules, docs, and e2e compose/README references from env.d/development or env.d/production to deploy/env.
PaaS deployment script refactor
Procfile, bin/scalingo_postcompile, bin/scalingo_postfrontend, deploy/paas/scalingo_postcompile, deploy/paas/scalingo_postfrontend
Converts existing bin/ scripts into deprecated shims delegating to new deploy/paas/ implementations, and updates the Procfile web command path.

Estimated code review effort: 4 (Complex) | ~75 minutes

Possibly related PRs

Suggested reviewers: jbpenrath

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main changes: faster bootstrap/dev workflow and dependency updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@compose.yaml`:
- Around line 271-301: Extract the duplicated worker settings from
worker-dev-light into a shared YAML anchor, keeping the service self-contained
without using extends. Define a base anchor for the common build, user, ulimits,
command, env_file, volumes, and mem_limit fields, then merge it into worker-dev
and worker-dev-light; preserve each service’s specific depends_on and profiles,
and remember that worker-dev-light must override environment while repeating
DJANGO_CONFIGURATION alongside OPENSEARCH_INDEX_THREADS.

In `@Makefile`:
- Around line 168-198: The start target leaves full-stack services running when
switching back from start-full, so update the start stop step to include the
orphan containers started by start-full. In the Makefile’s start and start-full
targets, make sure the stop command covers opensearch, objectstorage,
mailcatcher, mta-in-py, and mpa in addition to backend-dev, worker-dev,
worker-ui, so the light stack starts from a clean state.

In `@src/e2e/Dockerfile`:
- Line 7: The Docker image currently uses Node 24.18.0 while `@playwright/test`
is still pinned to 1.57.0, which can cause `npm install` to hang during
`playwright install --with-deps`. Update the Playwright version in the e2e setup
to 1.60.0 or newer, or change the base image in `src/e2e/Dockerfile` to a Node
version below 24.16.0, so the `npm install` flow completes reliably.

In `@src/frontend/Dockerfile`:
- Around line 12-21: The frozen frontend install path is missing the same
dependency policy check used by the normal install flow. Update the
frontend-deps stage in the Dockerfile and the install-frozen-front target in the
Makefile so they run the check:deps guardrail before or alongside npm ci,
matching the behavior already present in install-front. Use the existing
frontend install symbols (frontend-deps, install-frozen-front, and check:deps)
to keep the frozen/production path aligned with the package policy.

In `@src/frontend/scripts/check-node-modules.mjs`:
- Around line 39-60: The bare catch in walk suppresses directory read failures
and can silently truncate the scan. Update walk() in check-node-modules.mjs so
readdirSync errors are surfaced or recorded with enough context to mark the scan
as incomplete, instead of immediately returning; keep the existing traversal
logic for entries, flagIfForbidden, and bytes accounting, but make partial
failures visible to the caller or log them explicitly.
- Around line 18-19: The NODE_MODULES_LIMIT_GB parsing in check-node-modules.mjs
can turn malformed input into NaN and silently disable the size check. Update
the limit initialization around LIMIT_GB and LIMIT_BYTES to validate the
environment value explicitly, and make the script fail loudly with a clear error
when NODE_MODULES_LIMIT_GB is missing, non-numeric, or non-finite. Keep the
guardrail behavior in the main size-check logic unchanged, but ensure any
invalid limit is detected before the comparison so the check cannot no-op.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c832dd05-a245-49b9-aa8c-685025bc15a8

📥 Commits

Reviewing files that changed from the base of the PR and between 983df0f and 9538485.

⛔ Files ignored due to path filters (2)
  • src/e2e/package-lock.json is excluded by !**/package-lock.json
  • src/frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (15)
  • Makefile
  • compose.yaml
  • src/e2e/Dockerfile
  • src/e2e/package.json
  • src/frontend/.npmrc
  • src/frontend/Dockerfile
  • src/frontend/package.json
  • src/frontend/scripts/check-node-modules.mjs
  • src/jmap-email/Dockerfile
  • src/keycloak/Dockerfile
  • src/mpa/rspamd/Dockerfile
  • src/mpa/tests/Dockerfile
  • src/mta-in/Dockerfile
  • src/mta-out/Dockerfile
  • src/socks-proxy/tests/Dockerfile

Comment thread compose.yaml
Comment thread Makefile
Comment thread src/e2e/Dockerfile
Comment thread src/frontend/Dockerfile
Comment thread src/frontend/scripts/check-node-modules.mjs Outdated
Comment thread src/frontend/scripts/check-node-modules.mjs
@sylvinus sylvinus changed the title ⚡️(devx) improve "make bootstrap" setup time ⚡️(devx) improve "make bootstrap" setup time & update deps Jul 8, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/messages.yml:
- Around line 88-117: The new test jobs use actions/checkout@v6 without
disabling credential persistence, which leaves the GITHUB_TOKEN available to
subsequent make test-* commands. Update each checkout step in the test-mta-in,
test-mta-in-py, and test-mta-out jobs to set persist-credentials to false on the
Checkout repository action so the token is not written into .git/config.

In `@docker/python-uv/Dockerfile`:
- Line 15: The base image reference in the Dockerfile is still a mutable tag,
which leaves a reproducibility gap. Update the FROM declaration that uses
debian:trixie-slim to a digest-pinned reference, matching the supply-chain
approach already used for the uv image, and keep the rest of the build logic
unchanged.

In `@src/mta-out/Dockerfile`:
- Around line 90-93: The current hardening step only strips the uv-managed
interpreter via strip-python and leaves pip available from the copied /venv.
Update the runtime hardening so the Dockerfile’s strip-python step (or the
strip-python.sh helper it invokes) also removes the venv-installed pip
entrypoints and pip package metadata under /venv, using the existing
strip-python flow and related /venv copy in the Dockerfile as the place to
verify the fix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 398f3a31-782c-4345-a134-834f3e2fac5e

📥 Commits

Reviewing files that changed from the base of the PR and between 1a08eee and b71e3e2.

⛔ Files ignored due to path filters (4)
  • src/backend/uv.lock is excluded by !**/*.lock
  • src/e2e/package-lock.json is excluded by !**/package-lock.json
  • src/mta-in/uv.lock is excluded by !**/*.lock
  • src/mta-out/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (21)
  • .github/workflows/docker-publish.yml
  • .github/workflows/messages-ghcr.yml
  • .github/workflows/messages.yml
  • Makefile
  • bin/release-jmap-email.sh
  • compose.yaml
  • docker/python-uv/Dockerfile
  • docker/python-uv/strip-python.sh
  • src/backend/Dockerfile
  • src/backend/pyproject.toml
  • src/e2e/package.json
  • src/frontend/scripts/check-node-modules.mjs
  • src/jmap-email/CONTRIBUTING.md
  • src/jmap-email/Dockerfile
  • src/jmap-email/README.md
  • src/jmap-email/pyproject.toml
  • src/mta-in/Dockerfile
  • src/mta-in/Dockerfile.pymta
  • src/mta-in/pyproject.toml
  • src/mta-out/Dockerfile
  • src/mta-out/pyproject.toml

Comment thread .github/workflows/messages.yml
Comment thread deploy/python-uv/Dockerfile Outdated
Comment thread src/mta-out/Dockerfile
Comment on lines +90 to +93
# Hardening: whiteout pip/tkinter/tests/headers from the runtime (see
# strip-python). Not a size change (full Python is in an inherited layer), just
# keeps those tools out of the running container.
RUN strip-python

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

strip-python does not remove pip from the /venv virtual environment.

strip-python.sh targets $PYDIR (the uv-managed interpreter at /opt/python/...), not /venv. After COPY --from=base-with-deps /venv /venv (line 95), the venv's own pip remains accessible in the runtime image. If the intent is to keep pip out of the running container, consider also removing /venv/bin/pip* and the pip dist-info from /venv/lib/.

🔒 Proposed addition to strip-python.sh
 rm -f /bin/uv /bin/uvx
+
+# Also strip pip from the venv if it exists (runtime-prod images copy /venv
+# after strip-python runs, but the venv's pip is separate from $PYDIR's).
+rm -rf \
+    /venv/bin/pip* \
+    /venv/lib/python3.*/site-packages/pip \
+    /venv/lib/python3.*/site-packages/pip-*.dist-info
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mta-out/Dockerfile` around lines 90 - 93, The current hardening step only
strips the uv-managed interpreter via strip-python and leaves pip available from
the copied /venv. Update the runtime hardening so the Dockerfile’s strip-python
step (or the strip-python.sh helper it invokes) also removes the venv-installed
pip entrypoints and pip package metadata under /venv, using the existing
strip-python flow and related /venv copy in the Dockerfile as the place to
verify the fix.

@jbpenrath jbpenrath left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll, personnally, keep make start to start the full dev stack and allow to run the light through a make start-light 🤷‍♂️

By seeing light dev stack, for e2e test, I feel we could also disable opensearch.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the root of the issue ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mismatched old deps, 3.2GB node_modules pulling @adobe .. I've opened issues in ui-kit & cunningham

Comment thread src/frontend/package.json Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/mta-in/Dockerfile.pymta (1)

96-109: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

strip-python runs before /venv is copied — venv pip survives in the production runtime.

In runtime-prod, strip-python (line 104) targets /opt/python but executes before COPY --from=base-with-deps /venv /venv (line 108). The venv's own pip entrypoints and metadata are therefore present in the final image, contradicting the hardening intent described in the comment on lines 99-102. This same ordering affects src/mta-out/Dockerfile (line 93) and likely src/backend/Dockerfile as well.

Even if strip-python.sh was updated to handle /venv, the current Dockerfile ordering would still leave pip accessible because /venv is copied after stripping. The fix needs a Dockerfile-level change: either reorder the COPY before strip-python (and ensure strip-python.sh handles /venv), or add an explicit removal step after the copy.

🔒 Proposed fix: strip venv pip after COPY
 USER root
 RUN strip-python
-USER ${DOCKER_USER}
-
-# The distroless target below copies in an already-stripped Python instead.
 COPY --from=base-with-deps /venv /venv
+RUN rm -rf /venv/bin/pip* \
+    /venv/lib/python3.*/site-packages/pip \
+    /venv/lib/python3.*/site-packages/pip-*.dist-info
+USER ${DOCKER_USER}
+
 COPY --from=app-prod /app/src /app/src
#!/bin/bash
# Check whether strip-python.sh handles /venv and the ordering in all prod Dockerfiles
cat deploy/python-uv/strip-python.sh

echo "=== Ordering in production Dockerfiles ==="
for f in src/backend/Dockerfile src/mta-in/Dockerfile src/mta-in/Dockerfile.pymta src/mta-out/Dockerfile; do
  echo "--- $f ---"
  grep -n 'strip-python\|COPY.*\/venv' "$f"
done
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mta-in/Dockerfile.pymta` around lines 96 - 109, The production runtime
ordering in runtime-prod leaves the /venv pip artifacts unstripped because
strip-python runs before the COPY of /venv, so fix the Dockerfile flow in
Dockerfile.pymta by ensuring the venv is copied before hardening or by adding a
post-COPY removal step that strips /venv as well as /opt/python. Use the
existing runtime-prod stage and strip-python step as the anchor for the change,
and make the same ordering adjustment in the other production Dockerfiles that
follow this pattern so the final image does not retain pip entrypoints or
metadata.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@src/mta-in/Dockerfile.pymta`:
- Around line 96-109: The production runtime ordering in runtime-prod leaves the
/venv pip artifacts unstripped because strip-python runs before the COPY of
/venv, so fix the Dockerfile flow in Dockerfile.pymta by ensuring the venv is
copied before hardening or by adding a post-COPY removal step that strips /venv
as well as /opt/python. Use the existing runtime-prod stage and strip-python
step as the anchor for the change, and make the same ordering adjustment in the
other production Dockerfiles that follow this pattern so the final image does
not retain pip entrypoints or metadata.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 99e4092e-f237-455c-ba4a-fe3b2f64990d

📥 Commits

Reviewing files that changed from the base of the PR and between 2092979 and c512b7b.

📒 Files selected for processing (46)
  • .dockerignore
  • .github/workflows/crowdin_download.yml
  • .github/workflows/messages-ghcr.yml
  • .gitignore
  • Makefile
  • Procfile
  • bin/release-jmap-email.sh
  • bin/scalingo_postcompile
  • bin/scalingo_postfrontend
  • compose.yaml
  • deploy/env/backend.defaults
  • deploy/env/backend.e2e
  • deploy/env/crowdin.defaults
  • deploy/env/frontend.defaults
  • deploy/env/frontend.e2e
  • deploy/env/keycloak.defaults
  • deploy/env/keycloak.e2e
  • deploy/env/mta-in-py.defaults
  • deploy/env/mta-in.defaults
  • deploy/env/mta-in.e2e
  • deploy/env/mta-out.defaults
  • deploy/env/postgresql.defaults
  • deploy/env/socks-proxy.defaults
  • deploy/paas/scalingo_postcompile
  • deploy/paas/scalingo_postfrontend
  • deploy/paas/scalingo_run_web
  • deploy/python-uv/Dockerfile
  • deploy/python-uv/strip-python.sh
  • docs/env.md
  • docs/self-hosting.md
  • src/backend/Dockerfile
  • src/backend/entrypoint
  • src/backend/messages/settings.py
  • src/e2e/.npmrc
  • src/e2e/Dockerfile
  • src/e2e/README.md
  • src/e2e/compose.yaml
  • src/frontend/.npmrc
  • src/frontend/Dockerfile
  • src/jmap-email/Dockerfile
  • src/mpa/rspamd/Dockerfile
  • src/mpa/tests/Dockerfile
  • src/mta-in/Dockerfile
  • src/mta-in/Dockerfile.pymta
  • src/mta-out/Dockerfile
  • src/socks-proxy/tests/Dockerfile
💤 Files with no reviewable changes (4)
  • .github/workflows/crowdin_download.yml
  • deploy/python-uv/strip-python.sh
  • bin/release-jmap-email.sh
  • deploy/python-uv/Dockerfile

@sylvinus

Copy link
Copy Markdown
Member Author

merged as f4d2358

@sylvinus sylvinus closed this Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants