Skip to content

Merge v4-beta to v4 (2026-05-22)#165

Open
dbolotin wants to merge 11 commits into
v4from
merge-2026-05-22
Open

Merge v4-beta to v4 (2026-05-22)#165
dbolotin wants to merge 11 commits into
v4from
merge-2026-05-22

Conversation

@dbolotin
Copy link
Copy Markdown
Member

@dbolotin dbolotin commented May 22, 2026

Merge v4-beta into v4

Greptile Summary

This PR switches the Platforma and MinIO containers from running as root to running as the GitHub Actions runner's UID/GID, and synthesizes minimal /etc/passwd and /etc/group files so the Platforma entrypoint's id --user --name call succeeds. It also relocates --packages-dir from the standalone /packages path to /storage/packages (within the bound storage volume) and adds a tmpfs /pl-home with HOME set accordingly.

  • Non-root execution: Both services now use user: \"${PL_UID}:${PL_GID}\" sourced from id -u/id -g in the launch step; a synthetic passwd+group file is bind-mounted into the platforma container to satisfy entrypoint username lookups.
  • packages-dir relocation: --packages-dir is moved from /packages to /storage/packages, consolidating all mutable state inside the already-bound main-root volume.
  • Teardown gap: The post-step that runs docker compose logs/down does not declare PL_UID, PL_GID, PL_PASSWD_PATH, or PL_GROUP_PATH, so Docker Compose will receive empty values for those variables when parsing the compose file during teardown.

Confidence Score: 3/5

The launch path looks correct, but the teardown post-step is missing the newly added env vars, which is likely to break log collection and container shutdown on every run.

The new env vars (PL_UID, PL_GID, PL_PASSWD_PATH, PL_GROUP_PATH) are set only in the launch step's inline shell, not in the GitHub Actions env: block of the post-step. Docker Compose will substitute empty strings when parsing the compose file during teardown, producing an invalid user: ":" directive and empty-source volume mounts, likely preventing docker compose logs and docker compose down from executing cleanly.

The post-step env: block in actions/docker/pl-compose/action.yaml (around line 152) needs the four new variables added.

Important Files Changed

Filename Overview
actions/docker/pl-compose/action.yaml Exports PL_UID/PL_GID and synthesizes minimal passwd+group files for non-root container execution; the teardown post-step is missing these new env vars, which will likely break docker compose log collection and container shutdown.
actions/docker/pl-compose/docker-compose.yaml Both services now run as the runner UID/GID; platforma gets passwd/group injected and packages-dir moved to /storage/packages; minio gets non-root user but no passwd injection.

Sequence Diagram

sequenceDiagram
    participant GHA as GitHub Actions Runner
    participant Shell as launch-pl step
    participant Compose as Docker Compose
    participant MinIO as minio (UID:GID)
    participant PL as platforma (UID:GID)

    GHA->>Shell: run launch step
    Shell->>Shell: "export PL_UID=$(id -u), PL_GID=$(id -g)"
    Shell->>Shell: mkdir .users/ and write passwd+group files
    Shell->>Shell: export PL_PASSWD_PATH, PL_GROUP_PATH
    Shell->>Compose: docker compose up
    Compose->>MinIO: "start with user=PL_UID:PL_GID"
    Compose->>PL: "start with user=PL_UID:PL_GID"
    Compose->>PL: bind-mount /etc/passwd (synthetic)
    Compose->>PL: bind-mount /etc/group (synthetic)
    Note over PL: id --user --name resolves to pl
    PL->>PL: "run with --packages-dir=/storage/packages"

    Note over GHA,PL: Post-step (teardown)
    GHA->>Compose: docker compose logs/down (PL_UID/GID/PASSWD/GROUP not in env)
    Note over Compose: user: colon and empty volume paths may cause config parse error
Loading

Comments Outside Diff (1)

  1. actions/docker/pl-compose/action.yaml, line 152-176 (link)

    P1 Missing env vars in teardown post-step

    The post-step that runs docker compose logs, docker compose images, and docker compose down doesn't include PL_UID, PL_GID, PL_PASSWD_PATH, or PL_GROUP_PATH. Docker Compose will substitute empty strings for these, producing user: ":" (invalid) and volume mounts with empty source paths. This is likely to cause compose config-parsing errors, which would prevent logs from being collected and leave the platform containers running after the job ends.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: actions/docker/pl-compose/action.yaml
    Line: 152-176
    
    Comment:
    **Missing env vars in teardown post-step**
    
    The post-step that runs `docker compose logs`, `docker compose images`, and `docker compose down` doesn't include `PL_UID`, `PL_GID`, `PL_PASSWD_PATH`, or `PL_GROUP_PATH`. Docker Compose will substitute empty strings for these, producing `user: ":"` (invalid) and volume mounts with empty source paths. This is likely to cause compose config-parsing errors, which would prevent logs from being collected and leave the `platform` containers running after the job ends.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
actions/docker/pl-compose/action.yaml:152-176
**Missing env vars in teardown post-step**

The post-step that runs `docker compose logs`, `docker compose images`, and `docker compose down` doesn't include `PL_UID`, `PL_GID`, `PL_PASSWD_PATH`, or `PL_GROUP_PATH`. Docker Compose will substitute empty strings for these, producing `user: ":"` (invalid) and volume mounts with empty source paths. This is likely to cause compose config-parsing errors, which would prevent logs from being collected and leave the `platform` containers running after the job ends.

### Issue 2 of 2
actions/docker/pl-compose/docker-compose.yaml:3-9
**MinIO running as non-root without `/etc/passwd` injection**

The `minio` service now runs as `${PL_UID}:${PL_GID}` but doesn't have `/etc/passwd` or `/etc/group` bind-mounted. If MinIO's startup or any entrypoint script calls `id --user --name` (or similar), it will fail for the same reason that prompted the passwd injection for the `platforma` service. This may be intentional if MinIO is known not to need user-name resolution, but it's worth verifying.

Reviews (1): Last reviewed commit: "pl-compose: run minio as runner UID/GID ..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

dbolotin added 5 commits May 22, 2026 19:10
- docker-compose.yaml: replace user: root with user: $PL_UID:$PL_GID
  (resolved at action-launch time via id -u / id -g).
- Add tmpfs /pl-home and HOME=/pl-home so child processes have a writable
  home without host pollution.
- action.yaml: export PL_UID and PL_GID before docker compose up.

Switch internal sub-action references from @v4 to @v4-beta to match
beta-branch convention; merge-beta.sh restores @v4 at promotion time.

Motivation: enable exec.builder writable: false tests in platforma PR
#1648 — they require OS file-mode enforcement which root bypasses.
pl entrypoint run-pl.sh runs `id --user --name` under `set -o errexit`.
With user: $PL_UID:$PL_GID and no matching entry, the entrypoint
aborts immediately. Generate a minimal passwd+group file pair
containing root and a synthetic pl user for the resolved UID/GID,
then bind-mount them read-only into the container.
pl runs as non-root and cannot mkdir /packages at image root.
/storage is bind-mounted from a runner-owned host path and is
already writable by the resolved UID/GID.
When platforma runs as non-root and minio stays root, minio writes
.minio.sys/tmp/.trash/*.bkp files that the runner cannot remove
during cleanup. Switching minio to the same UID/GID keeps every
file in PL_MAIN_ROOT owned by the runner — rm -rf cleanup works
without sudo.
When platforma runs as non-root and minio stays root, minio writes
.minio.sys/tmp/.trash/*.bkp files that the runner cannot remove
during cleanup. Switching minio to the same UID/GID keeps every
file in PL_MAIN_ROOT owned by the runner — rm -rf cleanup works
without sudo.
Comment on lines 3 to 9
services:
minio:
image: quay.io/minio/minio
# Run as the runner UID/GID — keeps all files in PL_MAIN_ROOT owned by
# one user so cleanup (rm -rf) works without sudo.
user: "${PL_UID}:${PL_GID}"
command: server /data/minio --address "0.0.0.0:9000" --console-address "0.0.0.0:9001"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 MinIO running as non-root without /etc/passwd injection

The minio service now runs as ${PL_UID}:${PL_GID} but doesn't have /etc/passwd or /etc/group bind-mounted. If MinIO's startup or any entrypoint script calls id --user --name (or similar), it will fail for the same reason that prompted the passwd injection for the platforma service. This may be intentional if MinIO is known not to need user-name resolution, but it's worth verifying. Has MinIO been confirmed to not require /etc/passwd username resolution when running as a non-default UID?

Prompt To Fix With AI
This is a comment left during a code review.
Path: actions/docker/pl-compose/docker-compose.yaml
Line: 3-9

Comment:
**MinIO running as non-root without `/etc/passwd` injection**

The `minio` service now runs as `${PL_UID}:${PL_GID}` but doesn't have `/etc/passwd` or `/etc/group` bind-mounted. If MinIO's startup or any entrypoint script calls `id --user --name` (or similar), it will fail for the same reason that prompted the passwd injection for the `platforma` service. This may be intentional if MinIO is known not to need user-name resolution, but it's worth verifying. Has MinIO been confirmed to not require `/etc/passwd` username resolution when running as a non-default UID?

How can I resolve this? If you propose a fix, please make it concise.

PaulNewling and others added 6 commits May 22, 2026 13:11
Extract require-latest, the pnpm-workspace/lock drift guard, and the
scan-pnpm-repo Trivy scan from build-test-publish into separate
preflight and security-scan jobs. Both are non-blocking on PRs and
blocking on the default branch and in the merge queue, mirroring the
existing check-changesets pattern. build-test-publish gates publish on
both via needs + if.
scan-pnpm-repo discovers images via dist/artifacts/*.json which is only
populated by the build step. A pre-build security-scan job silently
passes in auto-discovery mode (scan_npm_package returns 0 when no
images are found and _require_docker=false), making the Trivy gate a
no-op. Restore scan-pnpm-repo as a step in build-test-publish after
the build. preflight (require-latest + lockfile drift) is unaffected
since those checks have no artifact dependency.
…re-latest

Surface publish-time gates as PR-visible jobs
The previous single 'preflight' job collapsed both checks under one
PR status row, and when require-latest failed the pnpm-lock-sync step
was skipped (job-level continue-on-error does not propagate to step
ordering inside the job).

Split into 'preflight-require-latest' and 'preflight-pnpm-lock-sync'
so each surfaces as its own PR-visible check, each carries its own
job-level continue-on-error, and a failure in one no longer hides the
other. Downstream needs: in pre-calculated-build, build-test-publish,
and notify slack release updated to depend on both new jobs.

Follow-up to #164.
preflight: split into require-latest and pnpm-lock-sync jobs
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