Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 89 additions & 27 deletions .github/workflows/node-simple-pnpm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,71 @@ jobs:
npm-pkg-version: ${{ fromJSON(steps.npm-pkg-metadata.outputs.data).npm-pkg-version }}
pnpm-version: ${{ fromJSON(steps.npm-pkg-metadata.outputs.data).pnpm-version }}

preflight-require-latest:
name: preflight (require-latest)
runs-on: ubuntu-latest
# Surface SDK-version drift on PRs as a non-blocking check, but enforce it
# on the default branch and in the merge queue so publish cannot proceed
# with a stale @platforma-sdk dependency.
continue-on-error: ${{ github.ref_name != inputs.changeset-default-branch && github.event_name != 'merge_group' }}
needs:
- init
steps:
- uses: milaboratory/github-ci/actions/context@v4

- uses: milaboratory/github-ci/actions/env@v4
with:
inputs: ${{ inputs.env }}
secrets: ${{ secrets.env }}

- uses: actions/checkout@v4
with:
lfs: ${{ inputs.checkout-git-lfs }}
submodules: ${{ inputs.checkout-submodules }}
fetch-depth: '0'

- name: Check infrastructure requirements for publication
uses: milaboratory/github-ci/actions/node/require-latest@v4
with:
packages: |
@platforma-sdk/block-tools
@platforma-sdk/tengo-builder

preflight-pnpm-lock-sync:
name: preflight (pnpm-lock-sync)
runs-on: ubuntu-latest
# Surface pnpm-workspace.yaml / pnpm-lock.yaml drift on PRs as a
# non-blocking check, but enforce it on the default branch and in the
# merge queue so publish cannot proceed with a stale lockfile.
continue-on-error: ${{ github.ref_name != inputs.changeset-default-branch && github.event_name != 'merge_group' }}
needs:
- init
steps:
- uses: milaboratory/github-ci/actions/context@v4

- uses: milaboratory/github-ci/actions/env@v4
with:
inputs: ${{ inputs.env }}
secrets: ${{ secrets.env }}

- uses: actions/checkout@v4
with:
lfs: ${{ inputs.checkout-git-lfs }}
submodules: ${{ inputs.checkout-submodules }}
fetch-depth: '0'

- name: Check pnpm-lock.yaml is in sync with pnpm-workspace.yaml
shell: bash
env:
DEFAULT_BRANCH: origin/${{ inputs.changeset-default-branch }}
run: |
if git diff --name-only ${DEFAULT_BRANCH}..HEAD | grep -q -E '^pnpm-workspace.yaml$'; then
if ! git diff --name-only ${DEFAULT_BRANCH}..HEAD | grep -q -E '^pnpm-lock.yaml$'; then
echo "Changes in pnpm-workspace.yaml detected, but no updates in pnpm-lock.yaml were found in current branch"
exit 1
fi
fi

check-changesets:
name: check for changesets
runs-on: ubuntu-latest
Expand Down Expand Up @@ -525,11 +590,21 @@ jobs:
matrix:
include: ${{ fromJSON(inputs.pre-calculated-task-list) }}
needs:
- preflight-require-latest
- preflight-pnpm-lock-sync
- check-changesets
- metadata
if: >
inputs.pre-calculated && inputs.pre-calculated-task-list != '[]' &&
!failure() && !cancelled() &&
(
needs.preflight-require-latest.result == 'success' ||
needs.preflight-require-latest.result == 'skipped'
) &&
(
needs.preflight-pnpm-lock-sync.result == 'success' ||
needs.preflight-pnpm-lock-sync.result == 'skipped'
) &&
(
needs.check-changesets.result == 'success' ||
needs.check-changesets.result == 'skipped'
Expand Down Expand Up @@ -608,17 +683,7 @@ jobs:
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPMJS_TOKEN: ${{ env.NPMJS_TOKEN }}
DEFAULT_BRANCH: origin/${{ inputs.changeset-default-branch }}

run: |
if git diff --name-only ${DEFAULT_BRANCH}..HEAD | grep -q -E '^pnpm-workspace.yaml$'; then
# Changes in pnpm-workspace.yaml have to be accompanied by pnpm-lock.yaml update
if ! git diff --name-only ${DEFAULT_BRANCH}..HEAD | grep -q -E '^pnpm-lock.yaml$'; then
echo "Changes in pnpm-workspace.yaml detected, but no updates in pnpm-lock.yaml were found in current branch"
exit 1
fi
fi

pnpm install --frozen-lockfile --prefer-offline

- name: Run changeset version
Expand All @@ -641,11 +706,21 @@ jobs:
name: unified (build test publish)
runs-on: ${{ inputs.gha-runner-label }}
needs:
- preflight-require-latest
- preflight-pnpm-lock-sync
- check-changesets
- metadata
- pre-calculated-build
if: >
!failure() && !cancelled() &&
(
needs.preflight-require-latest.result == 'success' ||
needs.preflight-require-latest.result == 'skipped'
) &&
(
needs.preflight-pnpm-lock-sync.result == 'success' ||
needs.preflight-pnpm-lock-sync.result == 'skipped'
) &&
(
needs.pre-calculated-build.result == 'success' ||
needs.pre-calculated-build.result == 'skipped'
Expand Down Expand Up @@ -684,13 +759,6 @@ jobs:
token: ${{ steps.app-token.outputs.token }}
fetch-depth: '0'

- name: Check infrastructure requirements for publication
uses: milaboratory/github-ci/actions/node/require-latest@v4
with:
packages: |
@platforma-sdk/block-tools
@platforma-sdk/tengo-builder

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
Expand Down Expand Up @@ -751,17 +819,7 @@ jobs:
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPMJS_TOKEN: ${{ env.NPMJS_TOKEN }}
DEFAULT_BRANCH: origin/${{ inputs.changeset-default-branch }}

run: |
if git diff --name-only ${DEFAULT_BRANCH}..HEAD | grep -q -E '^pnpm-workspace.yaml$'; then
# Changes in pnpm-workspace.yaml have to be accompanied by pnpm-lock.yaml update
if ! git diff --name-only ${DEFAULT_BRANCH}..HEAD | grep -q -E '^pnpm-lock.yaml$'; then
echo "Changes in pnpm-workspace.yaml detected, but no updates in pnpm-lock.yaml were found in current branch"
exit 1
fi
fi

pnpm install --frozen-lockfile --prefer-offline

- name: Run changeset version
Expand Down Expand Up @@ -945,6 +1003,8 @@ jobs:
needs:
- init
- metadata
- preflight-require-latest
- preflight-pnpm-lock-sync
- check-changesets
- build-test-publish
- pre-calculated-build
Expand All @@ -966,6 +1026,8 @@ jobs:
${{ needs.pre-calculated-build.result }}
${{ needs.build-test-publish.result }}
${{ needs.check-changesets.result }}
${{ needs.preflight-require-latest.result }}
${{ needs.preflight-pnpm-lock-sync.result }}
product-name: ${{ inputs.app-name }}
override-version: ${{ format('{0}', env.NPM_PKG_VERSION) }}
override-tag: ${{ format('v{0}', env.NPM_PKG_VERSION) }}
Expand Down
17 changes: 17 additions & 0 deletions actions/docker/pl-compose/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,23 @@ runs:
# depending on moon phases and mood of the scheduler god. :(
export PL_MAIN_ROOT="$(TMPDIR=${RUNNER_WORKSPACE} mktemp --directory)"

# Run platforma as the runner user (not root) so OS file-mode permissions
# are enforced inside the container (required by exec.writable tests).
# PL_UID/PL_GID are consumed by docker-compose.yaml.
export PL_UID="$(id -u)"
export PL_GID="$(id -g)"
echo "Platforma container will run as ${PL_UID}:${PL_GID}"

# pl entrypoint (run-pl.sh) calls `id --user --name` under `set -o errexit`,
# which fails when the runner UID has no /etc/passwd entry.
# Synthesize minimal passwd + group files for the chosen UID/GID and
# bind-mount them into the container (paths exported for compose).
mkdir -p "${PL_MAIN_ROOT}/.users"
printf 'root:x:0:0:root:/root:/bin/sh\npl:x:%s:%s:pl:/pl-home:/bin/sh\n' "${PL_UID}" "${PL_GID}" > "${PL_MAIN_ROOT}/.users/passwd"
printf 'root:x:0:\npl:x:%s:\n' "${PL_GID}" > "${PL_MAIN_ROOT}/.users/group"
export PL_PASSWD_PATH="${PL_MAIN_ROOT}/.users/passwd"
export PL_GROUP_PATH="${PL_MAIN_ROOT}/.users/group"

echo "main-root=${PL_MAIN_ROOT}" >> "${GITHUB_OUTPUT}"

docker compose --file "${ACTION_PATH}/docker-compose.yaml" config | tee "${PL_MAIN_ROOT}/compose.yaml"
Expand Down
15 changes: 12 additions & 3 deletions actions/docker/pl-compose/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ name: "platform"
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"
Comment on lines 3 to 9
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.


ports:
Expand All @@ -18,7 +21,7 @@ services:

platforma:
image: ${PL_DOCKER_REGISTRY}:${PL_DOCKER_TAG}
user: root
user: "${PL_UID}:${PL_GID}"

# Packages can be large. We don't want to save them after execution.
command: |
Expand All @@ -28,7 +31,7 @@ services:
--log-dst="file:///storage/log/platforma.log"
--log-level="${PL_LOG_LEVEL:-info}"
--main-root="/storage"
--packages-dir="/packages"
--packages-dir="/storage/packages"
--primary-storage-s3="http://minio:9000/platforma-primary-bucket"
--primary-storage-s3-key="testuser"
--primary-storage-s3-secret="testpassword"
Expand All @@ -38,9 +41,11 @@ services:
ports:
- "6345:6345"

tmpfs: [ /tmp ]
# tmpfs HOME so pl/child processes have a writable home with no host pollution.
tmpfs: [ /tmp, /pl-home ]

environment:
- "HOME=/pl-home"
- "MI_LICENSE=${MI_LICENSE:-${PL_LICENSE:-}}"
- "PL_LICENSE=${PL_LICENSE:-}"
- "PL_DATA_CREATE_BUCKET=${PL_DATA_CREATE_BUCKET:-true}"
Expand All @@ -50,6 +55,10 @@ services:
- ${PL_TEST_ASSETS_DIR}:/library
- ${PL_WORKSPACE}:${PL_WORKSPACE}
- ${HTPASSWD_PATH}:/etc/htpasswd
# Inject passwd/group so the runner UID resolves to a name —
# required by pl entrypoint's `id --user --name` check.
- ${PL_PASSWD_PATH}:/etc/passwd:ro
- ${PL_GROUP_PATH}:/etc/group:ro

restart: always

Expand Down