Skip to content

Conversation

@taiphanvan2k3
Copy link
Member

@taiphanvan2k3 taiphanvan2k3 commented Nov 14, 2025

Summary by CodeRabbit

  • Chores
    • Automated deployment pipeline added for continuous integration and deployment to cloud environments.
    • Separate production and staging deployment flows configured.
    • Docker image building, versioning, and deployment automation established.

@taiphanvan2k3 taiphanvan2k3 self-assigned this Nov 14, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 14, 2025

Walkthrough

Adds a new GitHub Actions CI/CD workflow and supporting script for automating .NET Core Web API deployment to Google Cloud Run. The workflow handles Docker image building, registry tagging, and separate production/staging deployments triggered by push and manual events, with generated version tags and deployment reporting.

Changes

Cohort / File(s) Summary
GitHub Actions Workflow Configuration
.github/workflows/deploy-gcloud.yml
Defines new deployment pipeline triggered on push (main/develop), pull requests, and manual dispatch. Includes version tag generation, Docker build from src/Web.Api/Dockerfile, Artifact Registry push (versioned + latest tags), and conditional Cloud Run deployments to production (main) and staging (develop) with environment-specific variables and resource allocation. Generates deployment summary output.
GCP IAM Setup Script
scripts/ci-cd-deploy-gcloud.sh
Shell script for establishing GCP service account permissions and credentials. Grants roles/run.admin IAM binding to CI/CD service account on the project and exports service account key to github-key.json.

Sequence Diagram

sequenceDiagram
    participant GitHub as GitHub<br/>(Push/Dispatch)
    participant Workflow as Workflow<br/>Runner
    participant GCloud as Google Cloud<br/>SDK
    participant Registry as Artifact<br/>Registry
    participant CloudRun as Cloud<br/>Run

    GitHub->>Workflow: Trigger on push/dispatch
    activate Workflow
    
    Note over Workflow: Generate version tag<br/>(dispatch input or git SHA)
    
    Workflow->>GCloud: Authenticate & configure
    activate GCloud
    GCloud-->>Workflow: Auth complete
    deactivate GCloud
    
    Workflow->>Workflow: Build Docker image<br/>(webapi:latest)
    
    Workflow->>Registry: Tag & push<br/>(versioned + latest)
    activate Registry
    Registry-->>Workflow: Push complete
    deactivate Registry
    
    alt Branch = main
        Workflow->>CloudRun: Deploy production<br/>(versioned image)
        activate CloudRun
        CloudRun-->>Workflow: Prod deployed
        deactivate CloudRun
    else Branch = develop
        Workflow->>CloudRun: Deploy staging<br/>(versioned image)
        activate CloudRun
        CloudRun-->>Workflow: Staging deployed
        deactivate CloudRun
    end
    
    Workflow->>GitHub: Post deployment<br/>summary
    deactivate Workflow
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Workflow file complexity: Dense YAML with conditional deployments, multiple environment variables, service account authentication, and branch-specific logic requiring validation
  • Version tagging strategy: Inspect logic for tag generation from workflow dispatch input, git references, and fallback date+SHA pattern
  • Cloud Run deployment configuration: Verify resource allocation, environment variables (ASP.NET_ENVIRONMENT), service naming, and authentication scopes
  • GCP IAM permissions: Confirm service account roles and key handling practices for security implications
  • Path filters and triggers: Validate push triggers and branch targeting (main vs. develop) for correct deployment gating

Poem

🐰 A pipeline now springs to life,
From code to cloud without the strife,
With tags and keys in perfect place,
Our Web API runs at lightning pace!
hops excitedly 🚀

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes in the pull request—adding CI/CD workflow and deployment scripts for Google Cloud.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/add-ci-cd-scripts-for-google-cloud-deployment

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

Copy link
Contributor

@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 (6)
scripts/ci-cd-deploy-gcloud.sh (1)

4-4: Replace Vietnamese comment with English.

Maintain consistency with the English codebase by translating the comment: # Tạo key cho service account# Create key for service account.

.github/workflows/deploy-gcloud.yml (5)

80-88: Fix shell variable quoting in docker tag step (shellcheck SC2086).

Variables in the docker tag command should be quoted to prevent word splitting:

       - name: Tag Docker image
         run: |
-          REMOTE_IMAGE="${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}"
-          REMOTE_IMAGE_LATEST="${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}:latest"
+          REMOTE_IMAGE="${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}"
+          REMOTE_IMAGE_LATEST="${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}:latest"
           
-          docker tag ${{ env.IMAGE_NAME }}:latest ${REMOTE_IMAGE}
-          docker tag ${{ env.IMAGE_NAME }}:latest ${REMOTE_IMAGE_LATEST}
+          docker tag "${{ env.IMAGE_NAME }}:latest" "${REMOTE_IMAGE}"
+          docker tag "${{ env.IMAGE_NAME }}:latest" "${REMOTE_IMAGE_LATEST}"
           
           echo "REMOTE_IMAGE=${REMOTE_IMAGE}" >> $GITHUB_ENV
           echo "REMOTE_IMAGE_LATEST=${REMOTE_IMAGE_LATEST}" >> $GITHUB_ENV

96-109: Remove --quiet flag to reveal deployment errors.

The --quiet flag suppresses output, which can hide deployment failures. This makes troubleshooting difficult. Remove it to see deployment status and errors:

           gcloud run deploy ${{ env.SERVICE_NAME }} \
             --image ${{ env.REMOTE_IMAGE }} \
             --platform managed \
             --region ${{ env.REGION }} \
             --allow-unauthenticated \
             --memory 512Mi \
             --cpu 1 \
             --max-instances 10 \
             --min-instances 0 \
             --port 8080 \
             --set-env-vars "ASPNETCORE_ENVIRONMENT=Production" \
-            --quiet
+            # Removed --quiet to surface deployment status

111-125: Remove --quiet flag from staging deployment as well.

Apply the same change to maintain consistency:

           gcloud run deploy ${{ env.SERVICE_NAME }}-staging \
             --image ${{ env.REMOTE_IMAGE }} \
             --platform managed \
             --region ${{ env.REGION }} \
             --allow-unauthenticated \
             --memory 512Mi \
             --cpu 1 \
             --max-instances 5 \
             --min-instances 0 \
             --port 8080 \
             --set-env-vars "ASPNETCORE_ENVIRONMENT=Staging" \
-            --quiet
+            # Removed --quiet to surface deployment status

142-156: Optimize shell redirections and fix quoting in deployment summary (shellcheck SC2129, SC2086).

Use a single redirection block for all summary writes and add proper quoting around variables:

       - name: Create deployment summary
         run: |
+          {
             echo "## Deployment Summary 🚀"
             echo ""
-            echo "- **Version**: \`${{ steps.version.outputs.VERSION }}\`" >> $GITHUB_STEP_SUMMARY
-            echo "- **Image**: \`${{ env.REMOTE_IMAGE }}\`" >> $GITHUB_STEP_SUMMARY
-            echo "- **Branch**: \`${{ github.ref_name }}\`" >> $GITHUB_STEP_SUMMARY
-            echo "- **Commit**: \`${GITHUB_SHA::7}\`" >> $GITHUB_STEP_SUMMARY
+            echo "- **Version**: \`${{ steps.version.outputs.VERSION }}\`"
+            echo "- **Image**: \`${{ env.REMOTE_IMAGE }}\`"
+            echo "- **Branch**: \`${{ github.ref_name }}\`"
+            echo "- **Commit**: \`${GITHUB_SHA:0:7}\`"
             echo ""
-            if [ "${{ github.ref }}" == "refs/heads/main" ]; then
-              echo "- **Environment**: Production" >> $GITHUB_STEP_SUMMARY
-            elif [ "${{ github.ref }}" == "refs/heads/develop" ]; then
-              echo "- **Environment**: Staging" >> $GITHUB_STEP_SUMMARY
+            if [ "${{ github.ref }}" = "refs/heads/main" ]; then
+              echo "- **Environment**: Production"
             else
-              echo "- **Environment**: Image built only (no deployment)" >> $GITHUB_STEP_SUMMARY
+              echo "- **Environment**: Staging or Image only"
             fi
+          } >> "$GITHUB_STEP_SUMMARY"

14-21: Clarify workflow behavior on pull requests.

The workflow triggers on pull_request but only builds the image without deploying. This should be documented or the trigger removed if PR builds aren't needed. Consider adding a comment or output to clarify this behavior:

   pull_request:
     branches:
       - main
     paths:
       - 'src/**'
       - 'appsettings*.json'
       - 'Dockerfile'
       - 'docker-compose.yml'
+    # Note: PRs trigger a build only; deployment occurs on merge to main/develop
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c8350d8 and 8eed01f.

📒 Files selected for processing (2)
  • .github/workflows/deploy-gcloud.yml (1 hunks)
  • scripts/ci-cd-deploy-gcloud.sh (1 hunks)
🧰 Additional context used
🪛 actionlint (1.7.8)
.github/workflows/deploy-gcloud.yml

51-51: shellcheck reported issue in this script: SC2086:info:9:30: Double quote to prevent globbing and word splitting

(shellcheck)


80-80: shellcheck reported issue in this script: SC2086:info:7:40: Double quote to prevent globbing and word splitting

(shellcheck)


80-80: shellcheck reported issue in this script: SC2086:info:8:54: Double quote to prevent globbing and word splitting

(shellcheck)


142-142: shellcheck reported issue in this script: SC2129:style:1:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)


142-142: shellcheck reported issue in this script: SC2086:info:1:35: Double quote to prevent globbing and word splitting

(shellcheck)


142-142: shellcheck reported issue in this script: SC2086:info:2:12: Double quote to prevent globbing and word splitting

(shellcheck)


142-142: shellcheck reported issue in this script: SC2086:info:3:67: Double quote to prevent globbing and word splitting

(shellcheck)


142-142: shellcheck reported issue in this script: SC2086:info:4:52: Double quote to prevent globbing and word splitting

(shellcheck)


142-142: shellcheck reported issue in this script: SC2086:info:5:52: Double quote to prevent globbing and word splitting

(shellcheck)


142-142: shellcheck reported issue in this script: SC2086:info:6:46: Double quote to prevent globbing and word splitting

(shellcheck)


142-142: shellcheck reported issue in this script: SC2086:info:7:12: Double quote to prevent globbing and word splitting

(shellcheck)


142-142: shellcheck reported issue in this script: SC2086:info:9:43: Double quote to prevent globbing and word splitting

(shellcheck)


142-142: shellcheck reported issue in this script: SC2086:info:11:40: Double quote to prevent globbing and word splitting

(shellcheck)


142-142: shellcheck reported issue in this script: SC2086:info:13:65: Double quote to prevent globbing and word splitting

(shellcheck)

🔇 Additional comments (3)
scripts/ci-cd-deploy-gcloud.sh (1)

2-2: Verify service account name: possible typo "fucntions" vs. "functions".

The service account identifier ci-cd-fucntions-hosting@... contains fucntions, which appears to be a typo (should be functions). Please confirm this is intentional or correct it.

Also applies to: 5-5

.github/workflows/deploy-gcloud.yml (2)

102-102: Review the --allow-unauthenticated setting for security.

Both production and staging deployments use --allow-unauthenticated, making the backend API publicly accessible without authentication. This is appropriate only for public APIs. For internal or protected services, configure proper authentication.

Confirm this is intentional. If the API requires authentication, update both deployments:

-            --allow-unauthenticated \
+            --no-allow-unauthenticated \
+            --set-env-vars "GCP_SA_KEY=${{ secrets.GCP_SA_KEY }}" \

Also applies to: 118-118


50-61: Add quoting around variables to prevent word splitting (shellcheck SC2086).

The version generation logic uses unquoted variables that could be split on whitespace. Apply proper quoting:

-          if [ "${{ github.event_name }}" == "workflow_dispatch" ] && [ -n "${{ inputs.version_tag }}" ]; then
+          if [ "${{ github.event_name }}" == "workflow_dispatch" ] && [ -n "${{ inputs.version_tag }}" ]; then
             VERSION="${{ inputs.version_tag }}"
           elif [ "${{ github.ref_type }}" == "tag" ]; then
             VERSION="${{ github.ref_name }}"
           else
             # Use date + short SHA for immutable versioning
-            VERSION="$(date +%Y%m%d)-${GITHUB_SHA::7}"
+            VERSION="$(date +%Y%m%d)-${GITHUB_SHA:0:7}"
           fi

Comment on lines +1 to +5
#!/bin/bash
gcloud projects add-iam-policy-binding lucky-union-472503-c7 --member="serviceAccount:ci-cd-fucntions-hosting@lucky-union-472503-c7.iam.gserviceaccount.com" --role="roles/run.admin"

# Tạo key cho service account
gcloud iam service-accounts keys create github-key.json --iam-account=ci-cd-fucntions-hosting@lucky-union-472503-c7.iam.gserviceaccount.com No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Critical: Service account key will be exposed if not properly excluded from version control.

Creating github-key.json directly in the repository root is a severe security risk. If this file is not strictly excluded from version control, it will expose GCP credentials in the repository history.

  1. Verify that github-key.json is listed in .gitignore and add it if missing.
  2. Consider whether this script should run as a one-time setup (outside CI/CD) rather than in every workflow execution.
  3. If this must run in CI/CD, use a temporary directory and ensure the key is only stored as a GitHub secret (e.g., base64-encoded in secrets.GCP_SA_KEY), never written to disk.
+#!/bin/bash
+set -euo pipefail
+
 gcloud projects add-iam-policy-binding lucky-union-472503-c7 --member="serviceAccount:ci-cd-fucntions-hosting@lucky-union-472503-c7.iam.gserviceaccount.com" --role="roles/run.admin"
 
-# Tạo key cho service account
+# Create key for service account
-gcloud iam service-accounts keys create github-key.json --iam-account=ci-cd-fucntions-hosting@lucky-union-472503-c7.iam.gserviceaccount.com
+gcloud iam service-accounts keys create /tmp/github-key.json --iam-account=ci-cd-fucntions-hosting@lucky-union-472503-c7.iam.gserviceaccount.com
+echo "Key created at /tmp/github-key.json"

🏁 Script executed:

#!/bin/bash
# Check for .gitignore and verify github-key.json is excluded
if [ -f ".gitignore" ]; then
  echo "=== .gitignore contents ==="
  cat .gitignore
else
  echo ".gitignore does not exist"
fi

Length of output: 6924


🏁 Script executed:

#!/bin/bash
# Search for service account references with both spellings
echo "=== Searching for 'ci-cd-fucntions-hosting' (typo version) ==="
rg -n "ci-cd-fucntions-hosting" --type-list | head -20

echo ""
echo "=== Searching for 'ci-cd-functions-hosting' (correct spelling) ==="
rg -n "ci-cd-functions-hosting" --type-list | head -20

Length of output: 910


🏁 Script executed:

#!/bin/bash
# Search for github-key.json references throughout codebase
echo "=== Searching for github-key.json references ==="
rg -n "github-key\.json" -C2

echo ""
echo "=== Searching for /tmp/github-key references ==="
rg -n "tmp.*github-key" -C2

Length of output: 368


🏁 Script executed:

#!/bin/bash
# Examine the full script and look for CI/CD workflow files
echo "=== Full content of scripts/ci-cd-deploy-gcloud.sh ==="
cat scripts/ci-cd-deploy-gcloud.sh

echo ""
echo "=== Searching for workflow files that might call this script ==="
fd -e yaml -e yml . .github/workflows 2>/dev/null || echo "No .github/workflows directory found"

Length of output: 548


🏁 Script executed:

#!/bin/bash
# Check for any error handling patterns in other scripts
echo "=== Checking for set -e or set -o pipefail in shell scripts ==="
rg -n "set -[eo]" --type bash -C1 | head -30

Length of output: 92


🏁 Script executed:

#!/bin/bash
# Check workflow files for calls to the deploy script
echo "=== deploy-gcloud.yml content ==="
cat .github/workflows/deploy-gcloud.yml

echo ""
echo "=== build.yml content ==="
cat .github/workflows/build.yml

Length of output: 7577


🏁 Script executed:

#!/bin/bash
# Search for references to the ci-cd-deploy-gcloud.sh script
echo "=== Searching for ci-cd-deploy-gcloud.sh references ==="
rg -n "ci-cd-deploy-gcloud\.sh" -C3

echo ""
echo "=== Searching for github-key usage in workflows or scripts ==="
rg -n "github-key" -C2

Length of output: 389


🏁 Script executed:

#!/bin/bash
# Check if scripts contain error handling directly
echo "=== Checking scripts directory for error handling ==="
fd -e sh scripts/ -exec grep -l "set -e\|set -o pipefail\|trap.*ERR" {} \;

echo ""
echo "=== Full listing of scripts directory ==="
find scripts/ -type f -exec file {} \;

Length of output: 486


🏁 Script executed:

#!/bin/bash
# Check README or documentation for setup instructions
echo "=== Searching for README or setup documentation ==="
fd -i "readme|setup|install" . -type f | head -10

echo ""
echo "=== Searching for mentions of one-time setup or manual steps ==="
rg -i "setup|manual|one-time|initialize" README* 2>/dev/null || echo "No README found with these terms"

Length of output: 343


🏁 Script executed:

#!/bin/bash
# Final verification: search for any documentation, comments, or issues mentioning this script
echo "=== Searching for documentation or comments about manual setup ==="
rg -i "deploy-gcloud|manual setup|one-time setup|initialize gcp" -C2 --max-count=10

echo ""
echo "=== Check git history for when script was added ==="
git log --follow --oneline scripts/ci-cd-deploy-gcloud.sh 2>/dev/null | head -5 || echo "Git history unavailable"

echo ""
echo "=== Check if README mentions this script ==="
cat README.md 2>/dev/null | grep -i "deploy-gcloud\|manual\|setup" | head -10 || echo "No matches in README"

Length of output: 280


Add github-key.json to .gitignore to prevent credential exposure.

The critical security issue is that github-key.json is not listed in .gitignore. If this script creates a credentials file in the repository root, it could be accidentally committed, exposing GCP service account credentials in version control history.

Add the following line to .gitignore:

github-key.json

Note: The service account name ci-cd-fucntions-hosting is the actual account in use (not a typo). However, the script also lacks error handling—add set -euo pipefail after the shebang to ensure the script fails gracefully if any command encounters an error, rather than silently continuing.

🤖 Prompt for AI Agents
In scripts/ci-cd-deploy-gcloud.sh around lines 1 to 5, the script writes a
credentials file (github-key.json) into the repo and lacks strict error
handling; add github-key.json to the repository .gitignore (repo root) to
prevent accidental commits of credentials, and modify this script to enable
strict failure mode by inserting set -euo pipefail immediately after the shebang
so the script exits on errors/unset variables and fails safely; do not change
the service account name.

@taiphanvan2k3 taiphanvan2k3 merged commit 9de8b85 into main Nov 14, 2025
2 checks passed
@taiphanvan2k3 taiphanvan2k3 deleted the feat/add-ci-cd-scripts-for-google-cloud-deployment branch November 14, 2025 06:14
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.

2 participants