Skip to content

Update Docker Hub auth and add release promotion workflow#879

Merged
nevil-mathew merged 5 commits intomasterfrom
github-ac
Mar 6, 2026
Merged

Update Docker Hub auth and add release promotion workflow#879
nevil-mathew merged 5 commits intomasterfrom
github-ac

Conversation

@nevil-mathew
Copy link
Collaborator

@nevil-mathew nevil-mathew commented Mar 6, 2026

Summary by CodeRabbit

Release Notes

  • Chores
    • Improved Docker Hub authentication in CI/CD to make registry checks more reliable and robust.
    • Added a "Promote RC to Production" release workflow that validates RC tags, ensures RC images exist and production tags do not, retags/publishes multi-arch images, creates idempotent Git release tags, and provides clear validation/error messages.

@nevil-mathew
Copy link
Collaborator Author

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2026

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2026

Walkthrough

This PR replaces Docker Hub basic auth in the docker-image workflow with a JSON POST login flow and adds a new "Promote RC to Production Release" GitHub Actions workflow that validates tags, verifies commit reachability, retags RC images to production using docker buildx imagetools, and creates a production git tag.

Changes

Cohort / File(s) Summary
Docker Hub Authentication Update
.github/workflows/docker-image.yml
Switched Docker Hub login from basic auth (-u username:token) to a JSON POST (curl -X POST with JSON body) returning a token; subsequent manifest/existence checks updated to use token-based requests.
Production Release Promotion Workflow
.github/workflows/prod-release.yml
Added new workflow to promote RC -> production: validates RC tag format, ensures RC commit is in main, logs into Docker Hub (token flow), verifies RC image exists and prod tag absent, uses docker buildx imagetools create to retag multi-arch manifests, creates/pushes git tag, and outputs digest summary with explicit failure paths.

Sequence Diagram(s)

sequenceDiagram
    participant GH as GitHub Actions
    participant Git as Git Repository
    participant DH as Docker Hub API
    participant IT as imagetools

    GH->>GH: receive RC tag input & validate format
    GH->>Git: checkout repo (full history) and verify RC tag commit is in main
    GH->>DH: POST /users/login (JSON creds) -> receive token
    GH->>DH: check RC image manifest exists (token auth)
    GH->>DH: ensure production tag does not exist (token auth)
    GH->>IT: imagetools create rc-image:rc-tag -> prod-image:prod-tag
    IT->>DH: push/update multi-arch manifest for prod tag
    GH->>Git: create and push production git tag
    GH->>GH: inspect remote digest, set workflow outputs
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

Possibly related PRs

Poem

🐇 I hopped through tags and JSON streams,
I nudged RCs toward brighter dreams,
With imagetools I stitched the flight,
From rc to prod — a leap tonight.
Tiny paws clap for release delight! 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title Check ✅ Passed Title check skipped as CodeRabbit has written the PR title.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch github-ac

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 changed the title @coderabbitai Update Docker Hub auth and add release promotion workflow Mar 6, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/docker-image.yml:
- Around line 67-72: The curl JSON payload construction is unsafe for secrets
with quotes/backslashes/newlines; update the LOGIN_RESPONSE assignment to build
the JSON with jq (using jq -n --arg username "$DOCKERHUB_USERNAME" --arg
password "$DOCKERHUB_TOKEN" '{username:$username,password:$password}') and pipe
or pass that output to curl (e.g., --data `@-` or --data-binary `@-`) instead of
inline -d, ensuring the GitHub Actions secrets are exported into environment
variables first and the curl invocation that sets LOGIN_RESPONSE uses the
jq-generated JSON.

In @.github/workflows/prod-release.yml:
- Around line 64-68: The curl JSON payload assignment to LOGIN_RESPONSE is
vulnerable to special characters in secrets; change the POST body construction
to build safe JSON with jq (or an equivalent safe encoder) and pipe it into curl
with -d `@-` so that the username and token are passed via jq --arg (or
equivalent) instead of inline string interpolation; update the LOGIN_RESPONSE
assignment and the curl invocation (the variable and command around
LOGIN_RESPONSE and the POST to "https://hub.docker.com/v2/users/login") to use
jq to produce {"username":..., "password":...} and feed that to curl.
- Around line 109-123: The current steps "Pull RC image", "Retag image for
production", and "Push production image" use docker pull/tag/push which only
moves the amd64 manifest; instead use docker buildx imagetools create to copy
the multi-arch manifest from the RC tag to the release tag without pulling
layers. Replace the three-step pull/tag/push sequence with a single imagetools
create invocation that references the same image identifiers (use ${{
env.DOCKER_REGISTRY }}/${{ env.DOCKER_NAMESPACE }}/${{ env.DOCKER_IMAGE_NAME
}}:${{ steps.version.outputs.rc }} as the source and ...:${{
steps.version.outputs.release }} as the target), ensuring the multi-arch
manifest is preserved. Ensure the runner has buildx available or set up a step
to enable docker buildx before running imagetools create.
- Around line 138-146: The current Job summary uses docker inspect to set DIGEST
which will fail if images are created with buildx imagetools (image not local);
update the DIGEST extraction to query the remote image via imagetools instead —
replace the docker inspect block that sets DIGEST with a command using docker
buildx imagetools inspect (targeting ${{ env.DOCKER_REGISTRY }}/${{
env.DOCKER_NAMESPACE }}/${{ env.DOCKER_IMAGE_NAME }}:${{
steps.version.outputs.release }}) and parse its output to capture the image
digest, then keep the rest of the summary writes intact (references: the DIGEST
variable assignment and the Job summary block that echoes DIGEST).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e8903936-ad4e-483d-b33c-920dd4977fe8

📥 Commits

Reviewing files that changed from the base of the PR and between cdb3284 and b7bc66c.

📒 Files selected for processing (2)
  • .github/workflows/docker-image.yml
  • .github/workflows/prod-release.yml

Comment on lines +67 to 72
LOGIN_RESPONSE=$(curl -s -w "\n%{http_code}" \
-u "${{ secrets.DOCKERHUB_USERNAME }}:${{ secrets.DOCKERHUB_TOKEN }}" \
-X POST \
-H "Content-Type: application/json" \
-d '{"username": "${{ secrets.DOCKERHUB_USERNAME }}", "password": "${{ secrets.DOCKERHUB_TOKEN }}"}' \
"https://hub.docker.com/v2/users/login")
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

JSON payload is vulnerable to breakage if secrets contain special characters.

If DOCKERHUB_USERNAME or DOCKERHUB_TOKEN contains characters like ", \, or newlines, the JSON will be malformed, causing authentication failures. Consider using jq to safely construct the payload.

🛡️ Proposed fix using jq for safe JSON construction
-        LOGIN_RESPONSE=$(curl -s -w "\n%{http_code}" \
-          -X POST \
-          -H "Content-Type: application/json" \
-          -d '{"username": "${{ secrets.DOCKERHUB_USERNAME }}", "password": "${{ secrets.DOCKERHUB_TOKEN }}"}' \
-          "https://hub.docker.com/v2/users/login")
+        LOGIN_PAYLOAD=$(jq -n \
+          --arg user "${{ secrets.DOCKERHUB_USERNAME }}" \
+          --arg pass "${{ secrets.DOCKERHUB_TOKEN }}" \
+          '{username: $user, password: $pass}')
+        LOGIN_RESPONSE=$(curl -s -w "\n%{http_code}" \
+          -X POST \
+          -H "Content-Type: application/json" \
+          -d "$LOGIN_PAYLOAD" \
+          "https://hub.docker.com/v2/users/login")
📝 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
LOGIN_RESPONSE=$(curl -s -w "\n%{http_code}" \
-u "${{ secrets.DOCKERHUB_USERNAME }}:${{ secrets.DOCKERHUB_TOKEN }}" \
-X POST \
-H "Content-Type: application/json" \
-d '{"username": "${{ secrets.DOCKERHUB_USERNAME }}", "password": "${{ secrets.DOCKERHUB_TOKEN }}"}' \
"https://hub.docker.com/v2/users/login")
LOGIN_PAYLOAD=$(jq -n \
--arg user "${{ secrets.DOCKERHUB_USERNAME }}" \
--arg pass "${{ secrets.DOCKERHUB_TOKEN }}" \
'{username: $user, password: $pass}')
LOGIN_RESPONSE=$(curl -s -w "\n%{http_code}" \
-X POST \
-H "Content-Type: application/json" \
-d "$LOGIN_PAYLOAD" \
"https://hub.docker.com/v2/users/login")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/docker-image.yml around lines 67 - 72, The curl JSON
payload construction is unsafe for secrets with quotes/backslashes/newlines;
update the LOGIN_RESPONSE assignment to build the JSON with jq (using jq -n
--arg username "$DOCKERHUB_USERNAME" --arg password "$DOCKERHUB_TOKEN"
'{username:$username,password:$password}') and pipe or pass that output to curl
(e.g., --data `@-` or --data-binary `@-`) instead of inline -d, ensuring the GitHub
Actions secrets are exported into environment variables first and the curl
invocation that sets LOGIN_RESPONSE uses the jq-generated JSON.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
.github/workflows/prod-release.yml (1)

40-52: Consider explicit error handling for missing RC tag.

If the RC tag doesn't exist in the repository, git rev-list -n 1 "$RC_TAG" on line 44 will fail with a generic git error rather than a clear message. Consider adding explicit existence check:

💡 Optional: Clearer error for missing tag
     - name: Verify RC commit exists in main
       run: |
         RC_TAG="${{ steps.version.outputs.rc }}"
         git fetch origin main --tags
+        if ! git rev-parse "$RC_TAG" >/dev/null 2>&1; then
+          echo "Error: RC tag $RC_TAG does not exist in the repository"
+          exit 1
+        fi
         RC_COMMIT=$(git rev-list -n 1 "$RC_TAG")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/prod-release.yml around lines 40 - 52, The script uses git
rev-list -n 1 "$RC_TAG" without verifying the tag exists, so add an explicit
existence check for RC_TAG before calling git rev-list (e.g., test `git
rev-parse --verify "refs/tags/$RC_TAG"` or `git show-ref --tags --quiet --verify
"refs/tags/$RC_TAG"`), and if the tag is missing emit a clear error like "Error:
RC tag '$RC_TAG' does not exist" and exit 1; maintain the subsequent RC_COMMIT
and merge-base check only when the tag existence check passes (refer to RC_TAG
and RC_COMMIT in the existing block).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/prod-release.yml:
- Around line 23-34: The Validate RC tag step currently interpolates `${{
github.event.inputs.rc_tag }}` directly into the run script (creating a
command-injection vector); instead pass the input into the step's env (e.g.,
RC_TAG: ${{ github.event.inputs.rc_tag }}) and then reference the safe shell
variable $RC_TAG inside the run block when doing the regex check, RELEASE_TAG
extraction, and writes to $GITHUB_OUTPUT; ensure the variable is always quoted
(e.g., "$RC_TAG") when tested and used.

---

Nitpick comments:
In @.github/workflows/prod-release.yml:
- Around line 40-52: The script uses git rev-list -n 1 "$RC_TAG" without
verifying the tag exists, so add an explicit existence check for RC_TAG before
calling git rev-list (e.g., test `git rev-parse --verify "refs/tags/$RC_TAG"` or
`git show-ref --tags --quiet --verify "refs/tags/$RC_TAG"`), and if the tag is
missing emit a clear error like "Error: RC tag '$RC_TAG' does not exist" and
exit 1; maintain the subsequent RC_COMMIT and merge-base check only when the tag
existence check passes (refer to RC_TAG and RC_COMMIT in the existing block).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6dea12db-7680-4563-a509-138af273112e

📥 Commits

Reviewing files that changed from the base of the PR and between b7bc66c and 7a6321d.

📒 Files selected for processing (1)
  • .github/workflows/prod-release.yml

Copy link

@coderabbitai coderabbitai bot left a comment

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 the current code and only fix it if needed.

Inline comments:
In @.github/workflows/prod-release.yml:
- Around line 15-20: Add a top-level concurrency stanza to the GitHub Actions
workflow to serialize runs of the promote job: under the workflow root (above
jobs) add a concurrency block (e.g., group: "promote" and cancel-in-progress:
false) so that the promote job cannot run concurrently and promotions are
queued, preventing the race when creating Docker/Git tags; ensure the group name
is stable (e.g., "promote" or include repo/workflow identifiers) and reference
the existing promote job in your mental mapping.
- Around line 41-52: The RC commit validated in the "Verify RC commit exists in
main" step (RC_COMMIT) is not persisted and the later git tag uses the workflow
checkout HEAD; change the step to set RC_COMMIT as a step output (e.g.,
outputs.rc_commit) after computing RC_COMMIT and then in the tagging step use
that output (steps.<verify-step-id>.outputs.rc_commit) when running git tag -a
or git tag <RC_TAG> <RC_COMMIT> so the production tag explicitly points to the
validated commit rather than the current checkout head.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b0acde60-30b2-46f7-8415-d02529c90881

📥 Commits

Reviewing files that changed from the base of the PR and between 7a6321d and 6203236.

📒 Files selected for processing (1)
  • .github/workflows/prod-release.yml

@nevil-mathew nevil-mathew merged commit dca3785 into master Mar 6, 2026
1 check failed
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