ci: publish drive9 CLI image to GHCR#517
Conversation
📝 WalkthroughWalkthroughThe PR adds containerization and publication infrastructure for the CLI application: a Dockerfile defines an Alpine-based image with the drive9 binary, and a GitHub Actions workflow automates building, tagging deterministically from commit metadata, and pushing to GHCR. ChangesCLI Docker Image Build and Publication
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Poem
🚥 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)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/ghcr-cli-image.yml:
- Line 60: The workflow currently injects a GitHub expression directly into
shell code via OVERRIDE_TAG="${{ github.event_name == 'workflow_dispatch' &&
inputs.image_tag || '' }}", which is a command-injection risk; instead move that
expression to a safe GitHub Actions environment variable (e.g. define
OVERRIDE_TAG in an env: block using the expression), then reference it in your
shell step as a quoted shell variable ("$OVERRIDE_TAG") and optionally
sanitize/validate its contents in Bash (e.g. check allowed pattern) before
using; update the occurrences that reference the inline expression (the
OVERRIDE_TAG assignment and the other instance at line 72) to use the new env
variable and quoted/sanitized usage.
In `@Dockerfile.cli`:
- Around line 1-2: The Dockerfile currently runs as root by default, which is a
container hardening risk; modify the image build to create a dedicated non-root
user and group (e.g., add a user like "appuser"), set appropriate ownership on
any runtime directories/files created during build, switch to that user with a
USER instruction before the final CMD/ENTRYPOINT, and ensure no privileged
operations require root at runtime so the container runs as the non-root user.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: bb14a170-574c-4e56-a46d-bdc9b9db72f9
📒 Files selected for processing (2)
.github/workflows/ghcr-cli-image.ymlDockerfile.cli
|
|
||
| FULL_SHA="$(git rev-parse HEAD)" | ||
| SHORT_SHA="$(git rev-parse --short=7 HEAD)" | ||
| OVERRIDE_TAG="${{ github.event_name == 'workflow_dispatch' && inputs.image_tag || '' }}" |
There was a problem hiding this comment.
Avoid direct ${{ }} interpolation inside shell code (command injection risk).
Line 60 and Line 72 inject workflow-dispatch input directly into Bash source text. A crafted input containing quotes/shell syntax can break out before your validation logic runs.
Suggested fix
- name: Resolve image tags
+ env:
+ OVERRIDE_TAG_INPUT: ${{ github.event_name == 'workflow_dispatch' && inputs.image_tag || '' }}
+ REF_NAME_INPUT: ${{ github.event_name == 'workflow_dispatch' && inputs.publish_ref || github.ref_name }}
run: |
set -euo pipefail
FULL_SHA="$(git rev-parse HEAD)"
SHORT_SHA="$(git rev-parse --short=7 HEAD)"
- OVERRIDE_TAG="${{ github.event_name == 'workflow_dispatch' && inputs.image_tag || '' }}"
+ OVERRIDE_TAG="${OVERRIDE_TAG_INPUT}"
if [ -n "$OVERRIDE_TAG" ]; then
case "$OVERRIDE_TAG" in
@@
else
- REF_NAME="${{ github.event_name == 'workflow_dispatch' && inputs.publish_ref || github.ref_name }}"
+ REF_NAME="${REF_NAME_INPUT}"
REF_NAME=${REF_NAME#refs/heads/}
REF_NAME=${REF_NAME#refs/tags/}Also applies to: 72-72
🧰 Tools
🪛 zizmor (1.25.2)
[error] 60-60: 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/ghcr-cli-image.yml at line 60, The workflow currently
injects a GitHub expression directly into shell code via OVERRIDE_TAG="${{
github.event_name == 'workflow_dispatch' && inputs.image_tag || '' }}", which is
a command-injection risk; instead move that expression to a safe GitHub Actions
environment variable (e.g. define OVERRIDE_TAG in an env: block using the
expression), then reference it in your shell step as a quoted shell variable
("$OVERRIDE_TAG") and optionally sanitize/validate its contents in Bash (e.g.
check allowed pattern) before using; update the occurrences that reference the
inline expression (the OVERRIDE_TAG assignment and the other instance at line
72) to use the new env variable and quoted/sanitized usage.
Source: Linters/SAST tools
| FROM public.ecr.aws/docker/library/alpine:3.19 | ||
| RUN apk add --no-cache ca-certificates |
There was a problem hiding this comment.
Run the image as a non-root user.
Line 1-2 and Line 7-9 build a root-default image with no USER drop. That’s an avoidable container hardening gap; compromise impact is higher if the process runs as root.
Suggested fix
FROM public.ecr.aws/docker/library/alpine:3.19
RUN apk add --no-cache ca-certificates
+RUN addgroup -S drive9 && adduser -S -G drive9 drive9
LABEL org.opencontainers.image.source="https://github.com/mem9-ai/drive9"
LABEL org.opencontainers.image.description="drive9 CLI container image"
-COPY ./bin/drive9 /drive9
+COPY --chown=drive9:drive9 ./bin/drive9 /drive9
+USER drive9
ENTRYPOINT ["/drive9"]Also applies to: 7-9
🧰 Tools
🪛 Trivy (0.69.3)
[error] 1-1: Image user should not be 'root'
Specify at least 1 USER command in Dockerfile with non-root user as argument
Rule: DS-0002
(IaC/Dockerfile)
🤖 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 `@Dockerfile.cli` around lines 1 - 2, The Dockerfile currently runs as root by
default, which is a container hardening risk; modify the image build to create a
dedicated non-root user and group (e.g., add a user like "appuser"), set
appropriate ownership on any runtime directories/files created during build,
switch to that user with a USER instruction before the final CMD/ENTRYPOINT, and
ensure no privileged operations require root at runtime so the container runs as
the non-root user.
Source: Linters/SAST tools
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b5906f42b3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| - 'cmd/**' | ||
| - 'pkg/**' | ||
| - 'go.mod' |
There was a problem hiding this comment.
Include internal dependencies in image trigger
With this paths filter, pushes that only touch internal/** do not run the publisher, but the CLI binary depends on github.com/mem9-ai/dat9/internal/schemaspec (checked with go list -deps ./cmd/drive9). If that internal package changes on main, GHCR keeps serving the previous CLI image until another listed path changes, so the published tags can lag behind the repository state.
Useful? React with 👍 / 👎.
| @@ -0,0 +1,9 @@ | |||
| FROM public.ecr.aws/docker/library/alpine:3.19 | |||
There was a problem hiding this comment.
Use a supported Alpine base image
As of June 8, 2026, alpine:3.19 is past its November 1, 2025 end-of-support date in Alpine's release table (https://www.alpinelinux.org/releases/), so every newly published CLI image starts from a base that no longer receives normal security updates. Since this Dockerfile creates a new public GHCR artifact, bump the base to a currently supported Alpine branch before publishing it.
Useful? React with 👍 / 👎.
|
|
||
| FULL_SHA="$(git rev-parse HEAD)" | ||
| SHORT_SHA="$(git rev-parse --short=7 HEAD)" | ||
| OVERRIDE_TAG="${{ github.event_name == 'workflow_dispatch' && inputs.image_tag || '' }}" |
There was a problem hiding this comment.
Avoid interpolating dispatch inputs into shell
For manually dispatched runs, this line substitutes inputs.image_tag directly into the shell script before the validation below runs. A tag override containing shell syntax such as command substitution is evaluated while assigning OVERRIDE_TAG, so anyone allowed to dispatch this workflow can execute arbitrary commands with this job's packages: write token; pass the input through env: or another non-interpolated channel before validating it.
Useful? React with 👍 / 👎.
| if [ "$PUSH_LATEST" = "true" ]; then | ||
| docker push "$IMAGE_NAME:latest" |
There was a problem hiding this comment.
Prevent stale runs from moving latest backwards
This workflow has no concurrency guard or final origin/main check before pushing latest. When two pushes to main overlap, the older build can finish after the newer build and execute this push last, repointing ghcr.io/mem9-ai/drive9:latest to an older commit even though the SHA-specific tags are correct.
Useful? React with 👍 / 👎.
Summary
Validation
Summary by CodeRabbit