Skip to content

ci: publish drive9 CLI image to GHCR#517

Open
mashenjun wants to merge 1 commit into
mainfrom
shenjun/add-cli-image-workflow
Open

ci: publish drive9 CLI image to GHCR#517
mashenjun wants to merge 1 commit into
mainfrom
shenjun/add-cli-image-workflow

Conversation

@mashenjun

@mashenjun mashenjun commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add a CLI-specific Dockerfile for the drive9 binary
  • add a GHCR workflow that publishes ghcr.io/mem9-ai/drive9 with ref/SHA tags and latest on main
  • include package visibility guidance in the workflow summary

Validation

  • ruby -e 'require "yaml"; YAML.load_file(ARGV.fetch(0)); puts "ok"' .github/workflows/ghcr-cli-image.yml
  • make build-cli GOOS=linux GOARCH=amd64 VERSION=test
  • docker build -f Dockerfile.cli -t drive9-cli-ghcr-test .
  • docker run --rm drive9-cli-ghcr-test version

Summary by CodeRabbit

  • New Features
    • CLI Docker image is now automatically built and published to GitHub Container Registry (GHCR) with each push to main. The container image includes the CLI binary and is tagged with commit information for version tracking. Manual publication with custom version tags available.

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

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

Changes

CLI Docker Image Build and Publication

Layer / File(s) Summary
CLI container image definition
Dockerfile.cli
Alpine 3.19 base image, CA certificate installation, OCI metadata labels, drive9 binary copied to /drive9, entrypoint configured to run the binary.
GHCR publication workflow
.github/workflows/ghcr-cli-image.yml
Workflow triggered on main pushes or manual dispatch; clones agfs dependency, sets up Go, computes deterministic image tags from commit SHA and ref name (sanitized 80-char tag, sha-short variant, and latest for main only); builds image with OCI revision/version labels; authenticates to GHCR; pushes tag variants; and writes step summary with published image references.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • qiffang

Poem

🐰 A Dockerfile wrapped in alpine snow,
Where drive9 binaries dance and flow,
GitHub Actions orchestrates the show,
GHCR embraces, let the CLI grow!
From commit SHA to latest, all aglow. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding CI infrastructure to publish the drive9 CLI image to GHCR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch shenjun/add-cli-image-workflow

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

📥 Commits

Reviewing files that changed from the base of the PR and between e15b9d7 and b5906f4.

📒 Files selected for processing (2)
  • .github/workflows/ghcr-cli-image.yml
  • Dockerfile.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 || '' }}"

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

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

Comment thread Dockerfile.cli
Comment on lines +1 to +2
FROM public.ecr.aws/docker/library/alpine:3.19
RUN apk add --no-cache ca-certificates

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 | 🟠 Major | ⚡ Quick win

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

Learn more

(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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 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".

Comment on lines +7 to +9
- 'cmd/**'
- 'pkg/**'
- 'go.mod'

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 Badge 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 👍 / 👎.

Comment thread Dockerfile.cli
@@ -0,0 +1,9 @@
FROM public.ecr.aws/docker/library/alpine:3.19

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 Badge 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 || '' }}"

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 Badge 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 👍 / 👎.

Comment on lines +130 to +131
if [ "$PUSH_LATEST" = "true" ]; then
docker push "$IMAGE_NAME:latest"

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 Badge 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 👍 / 👎.

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.

1 participant