From 02bf1d08590174edbaca131d518d7f8b890e5b49 Mon Sep 17 00:00:00 2001 From: Anket Satbhai Date: Fri, 10 Jul 2026 18:37:19 +0530 Subject: [PATCH 1/3] feat: update smurf shared workflows for docker, helm and terraform and update document --- .github/workflows/docker-smurf.yml | 113 ++++---- .github/workflows/helm-smurf.yml | 402 +++++++++++++++++------------ .github/workflows/tf-smurf.yml | 178 +++++++++++-- docs/docker-smurf.md | 273 ++++++++++++++++++-- docs/helm-smurf.md | 291 +++++++++++++++++++-- docs/tf-smurf.md | 312 ++++++++++++++++++++-- 6 files changed, 1278 insertions(+), 291 deletions(-) diff --git a/.github/workflows/docker-smurf.yml b/.github/workflows/docker-smurf.yml index d21b24a2..4e966999 100644 --- a/.github/workflows/docker-smurf.yml +++ b/.github/workflows/docker-smurf.yml @@ -1,6 +1,7 @@ --- -name: πŸ¦Έβ€β™‚οΈ Smurf-Docker -'on': +name: Smurf-Docker + +on: workflow_call: inputs: docker_enable: @@ -54,7 +55,7 @@ name: πŸ¦Έβ€β™‚οΈ Smurf-Docker description: 'The URL of the container registry (e.g., Docker Hub, ECR, GCR, ACR).' type: string dockerfile_path: - description: Docker file directory + description: Docker file path (relative to repo root) type: string default: Dockerfile docker_build_args: @@ -113,6 +114,9 @@ name: πŸ¦Έβ€β™‚οΈ Smurf-Docker AWS_SESSION_TOKEN: required: false description: AWS Session Token for direct authentication + BUILD_ROLE: + required: false + description: AWS OIDC role for aws authentication GCP_WIP: required: false description: 'WIP Connected with Service Account' @@ -125,6 +129,12 @@ name: πŸ¦Έβ€β™‚οΈ Smurf-Docker GCP_SERVICE_ACCOUNT_KEY: required: false description: 'GCP service account JSON Key' + DOCKER_USERNAME: + required: false + description: Docker Hub username + DOCKER_PASSWORD: + required: false + description: Docker Hub access token or password aws_set_parameters: required: false description: Overriding the default values using --set flag @@ -137,37 +147,39 @@ jobs: id-token: write contents: read steps: - - name: πŸ“¦ Checkout + - name: Checkout uses: actions/checkout@v6 - # - Setup smurf CLI - name: Setup Smurf - uses: clouddrove/smurf@v1.1.3 + uses: clouddrove/smurf@v1.1.5 - - name: 🐳 Docker Image Build + - name: Docker Image Build if: inputs.docker_buildkit_enable != 'true' run: | - smurf sdkr build ${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} -f ${{ - inputs.dockerfile_path }} --platform ${{ inputs.docker_build_platform }} + smurf sdkr build ${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} \ + -f ${{ inputs.dockerfile_path }} \ + --platform ${{ inputs.docker_build_platform }} \ --build-arg ${{ inputs.docker_build_args }} - - name: 🐳 Docker Image Build with Buildkit + - name: Docker Image Build with Buildkit if: inputs.docker_buildkit_enable == 'true' run: | - smurf sdkr build ${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} -f ${{ - inputs.dockerfile_path }} --platform ${{ inputs.docker_build_platform }} - --build-arg ${{ inputs.docker_build_args }} --buildkit + smurf sdkr build ${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} \ + -f ${{ inputs.dockerfile_path }} \ + --platform ${{ inputs.docker_build_platform }} \ + --build-arg ${{ inputs.docker_build_args }} \ + --buildkit - - name: πŸ’Ύ Save Docker Image as Artifact - run: > - docker save ${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} -o ${{ - inputs.docker_image_tar }} + - name: Save Docker Image as Artifact + run: | + docker save ${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} \ + -o ${{ inputs.docker_image_tar }} - - name: ⬆️ Upload Docker Image Artifact + - name: Upload Docker Image Artifact uses: actions/upload-artifact@v7 with: - name: '${{ inputs.docker_image_name }}' - path: '${{ inputs.docker_image_tar }}' + name: docker-image + path: ${{ inputs.docker_image_tar }} docker_scan_push: if: inputs.docker_enable == 'true' && inputs.docker_push == 'true' @@ -177,23 +189,21 @@ jobs: id-token: write contents: read steps: - - name: πŸ“¦ Checkout + - name: Checkout uses: actions/checkout@v6 - # - Setup smurf CLI - name: Setup Smurf - uses: clouddrove/smurf@v1.1.3 + uses: clouddrove/smurf@v1.1.5 - - name: ⬇️ Download Docker Image Artifact + - name: Download Docker Image Artifact uses: actions/download-artifact@v8 with: - name: '${{ inputs.docker_image_name }}' + name: docker-image - - name: πŸ“₯ Load Docker Image - run: | - docker load -i ${{ inputs.docker_image_tar }} + - name: Load Docker Image + run: docker load -i ${{ inputs.docker_image_tar }} - - name: 🟦 Install AWS CLI + - name: Install AWS CLI if: ${{ inputs.provider == 'aws' }} uses: aws-actions/configure-aws-credentials@v6 with: @@ -205,14 +215,14 @@ jobs: role-duration-seconds: 900 role-skip-session-tagging: true - - name: πŸ”„ Assume another IAM Role + - name: Assume another IAM Role if: inputs.aws_assume_role == 'true' uses: aws-actions/configure-aws-credentials@v6 with: role-to-assume: ${{ inputs.aws_assume_role_arn }} aws-region: ${{ inputs.aws_region }} - - name: ☁️ Authenticate Google Cloud with WIP and Service Account + - name: Authenticate Google Cloud with WIP and Service Account if: inputs.gcp_auth_method == 'wip' uses: google-github-actions/auth@v3 with: @@ -222,31 +232,42 @@ jobs: access_token_lifetime: 300s project_id: ${{ inputs.gcp_project_id }} - - name: ☁️ Authenticate Google Cloud with Service Account JSON Key + - name: Authenticate Google Cloud with Service Account JSON Key if: inputs.gcp_auth_method == 'json' - uses: 'google-github-actions/auth@v3' + uses: google-github-actions/auth@v3 with: - credentials_json: '${{ secrets.GOOGLE_CREDENTIALS }}' + credentials_json: ${{ secrets.GOOGLE_CREDENTIALS }} + + - name: Set Docker Hub environment variables + if: inputs.docker_registry == 'hub' + run: | + echo "DOCKER_USERNAME=${{ secrets.DOCKER_USERNAME }}" >> $GITHUB_ENV + echo "DOCKER_PASSWORD=${{ secrets.DOCKER_PASSWORD }}" >> $GITHUB_ENV + shell: bash + + - name: Install Trivy + run: | + curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin + trivy --version - - name: πŸ›‘οΈ Docker Image Scan + - name: Docker Image Scan run: | smurf sdkr scan ${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} - - name: 🏷️ Docker Image Tag + - name: Docker Image Tag if: inputs.docker_push == 'true' run: | - smurf sdkr tag ${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} ${{ - inputs.docker_registry_url }}/${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} + smurf sdkr tag ${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} \ + ${{ inputs.docker_registry_url }}/${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} - - name: πŸš€ Docker Image Push - if: inputs.docker_push == 'true' && inputs.gcp_docker_push != 'true' + - name: Docker Image Push + if: inputs.docker_push == 'true' && inputs.gcp_docker_push != 'true' run: | - smurf sdkr push ${{ inputs.docker_registry }} ${{ inputs.docker_registry_url }}/${{ inputs.docker_image_name }}:${{ - inputs.docker_image_tag }} + smurf sdkr push ${{ inputs.docker_registry }} ${{ inputs.docker_registry_url }}/${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} - - name: πŸš€ Docker Image Push on gcp + - name: Docker Image Push on gcp if: inputs.docker_push == 'true' && inputs.gcp_docker_push == 'true' run: | - smurf sdkr push ${{ inputs.docker_registry }} ${{ inputs.docker_registry_url }}/${{ inputs.docker_image_name }}:${{ - inputs.docker_image_tag }} --project-id ${{ inputs.gcp_project_id }} -... + smurf sdkr push ${{ inputs.docker_registry }} \ + ${{ inputs.docker_registry_url }}/${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} \ + --project-id ${{ inputs.gcp_project_id }} diff --git a/.github/workflows/helm-smurf.yml b/.github/workflows/helm-smurf.yml index aa3ad77b..3526bc45 100644 --- a/.github/workflows/helm-smurf.yml +++ b/.github/workflows/helm-smurf.yml @@ -1,181 +1,196 @@ --- -name: πŸ¦Έβ€β™‚οΈ Smurf-Helm -'on': +name: Smurf Helm Shared Workflow + +on: workflow_call: inputs: - aws_auth_method: - description: AWS auth method to use like oidc and keys - type: string - required: false - aws_eks_cluster_name: - description: AWS eks cluster name - type: string - required: false - aws_role: - description: AWS OIDC role for aws authentication. - type: string - default: 'false' provider: - description: Cloud provider (aws, azure, gcp, digitalocean) + description: Cloud provider (aws, gcp, azure) type: string required: false default: aws - helm_enable: - description: Set to true to run helm commands + aws_region: + description: AWS region type: string required: false - default: 'false' - helm_rollback_enable: - description: Set to true for helm rollback + default: us-east-1 + aws_eks_cluster_name: + description: AWS EKS cluster name type: string required: false - default: 'false' - helm_release_name: - description: Unique ID for installed chart + aws_assume_role: + description: Assume another IAM role after initial AWS auth + type: boolean required: false + default: false + aws_assume_role_arn: + description: IAM role ARN to assume type: string - helm_chart_directory: required: false + gcp_project_id: + description: GCP project ID type: string - description: Kubernetes deployment configurations files - helm_values_file_path: required: false + gcp_region: + description: GCP region type: string - description: Values file path from helm chart directory - helm_namespace: required: false + default: us-central1 + gcp_gke_cluster_name: + description: GKE cluster name type: string - description: Boundary for Kubernetes resources - helm_revision: required: false + smurf_version: + description: Smurf CLI version type: string - description: helm_revision for Helm rollback - helm_timeout: required: false - type: string - description: helm_timeout for helm install step in seconds - helm_plugins: - description: List of Helm plugins to install + default: v1.1.5 + target_environment: + description: GitHub Environment name (empty = no gate) type: string required: false - helm_plugin_install: - description: Set to True for Helm Plugin install - type: string + default: "" + helm_enable: + description: Run lint + deploy jobs + type: boolean required: false - default: 'false' - helm_repo_add: - description: Set to True for Adding Helm Repo - type: string + default: false + helm_rollback_enable: + description: Run helm rollback job + type: boolean required: false - default: 'false' - helm_repository: - description: Helm Repository to add + default: false + helm_release_name: + description: Helm release name type: string required: false - helm_repository_url: - description: Helm Repository URL to add + helm_chart_directory: + description: Path to Helm chart directory type: string required: false - helm_flags: - description: Helm flags + helm_values_file_path: + description: Values file path (relative to repo root) type: string required: false - default: '--atomic --debug' - aws_region: - required: false + helm_namespace: + description: Kubernetes namespace type: string - description: AWS Region - default: 'us-east-1' - aws_assume_role: - description: Set to True to run Assume another IAM Role step required: false + default: default + helm_revision: + description: Revision number for rollback type: string - default: 'false' - aws_assume_role_arn: - type: string - description: AWS assume role - required: false - gcp_project_id: required: false + helm_timeout: + description: Helm install/upgrade timeout (e.g. 5m, 300s) type: string - description: 'ID of the default project to use for future API calls and invocations.' - gcp_auth_method: - description: GCP auth method to use like wip and json + required: false + default: 5m + helm_flags: + description: Extra flags for helm upgrade --install type: string required: false - gcp_docker_push: - description: Set to True to Push Images in GCP + default: "--atomic --wait --create-namespace" + helm_plugin_install: + description: Install Helm plugins before deploy + type: boolean + required: false + default: false + helm_plugins: + description: Helm plugin install command args type: string required: false - default: 'false' - gcp_region: + helm_repo_add: + description: Add Helm repo before deploy + type: boolean required: false + default: false + helm_repository: + description: Helm repository name type: string - description: GCP Region - default: 'us-central1' - gcp_gke_cluster_name: - description: GCP gke cluster name + required: false + helm_repository_url: + description: Helm repository URL type: string required: false secrets: AWS_ACCESS_KEY_ID: required: false - description: AWS Access Key ID for direct authentication + description: AWS access key (keys auth) AWS_SECRET_ACCESS_KEY: required: false - description: AWS Secret Access Key for direct authentication + description: AWS secret key (keys auth) AWS_SESSION_TOKEN: required: false - description: AWS Session Token for direct authentication - GCP_WIP: + description: AWS session token (optional) + BUILD_ROLE: required: false - description: 'WIP Connected with Service Account' - GCP_SERVICE_ACCOUNT: + description: AWS OIDC role ARN + GCP_CREDENTIALS: required: false - description: 'GCP service account' - GOOGLE_CREDENTIALS: + description: GCP service account JSON key + WORKLOAD_IDENTITY_PROVIDER: required: false - description: 'GCP service account JSON Key' - GCP_SERVICE_ACCOUNT_KEY: + description: GCP workload identity provider + SERVICE_ACCOUNT: required: false - description: 'GCP service account JSON Key' - aws_set_parameters: + description: GCP service account email (WIP auth) + GCP_PROJECT_ID: + description: 'GCP Project ID' required: false - description: Overriding the default values using --set flag + AZURE_CREDENTIALS: + required: false + description: Azure service principal JSON + helm_extra_args: + required: false + description: Extra helm CLI args (e.g. --set key=val) + +permissions: + id-token: write + contents: read jobs: - helm_lint_template: - if: inputs.helm_enable == 'true' + helm-lint: + name: Helm Lint & Template + if: ${{ inputs.helm_enable }} runs-on: ubuntu-latest steps: - - name: πŸ“¦ Checkout + - name: Checkout uses: actions/checkout@v6 - # - Setup smurf CLI - name: Setup Smurf - uses: clouddrove/smurf@v1.1.3 + uses: clouddrove/smurf@v1.1.5 + with: + version: ${{ inputs.smurf_version }} - - name: πŸ§ͺ Helm Lint - run : | - smurf selm lint ${{ inputs.helm_chart_directory }} -f ${{ inputs.helm_values_file_path }} + - name: Helm Lint + run: | + smurf selm lint "${{ inputs.helm_chart_directory }}" \ + -f "${{ inputs.helm_values_file_path }}" - - name: πŸ“ Helm Template + - name: Helm Template run: | - smurf selm template ${{ inputs.helm_release_name }} ${{ inputs.helm_chart_directory }} -f ${{ inputs.helm_values_file_path }} + smurf selm template "${{ inputs.helm_release_name }}" \ + "${{ inputs.helm_chart_directory }}" \ + -f "${{ inputs.helm_values_file_path }}" helm-deploy: - if: inputs.helm_enable == 'true' + name: Helm Deploy + if: ${{ inputs.helm_enable }} + needs: helm-lint runs-on: ubuntu-latest + environment: ${{ inputs.target_environment }} steps: - - name: πŸ“¦ Checkout + - name: Checkout uses: actions/checkout@v6 - # - Setup smurf CLI - name: Setup Smurf - uses: clouddrove/smurf@v1.1.3 + uses: clouddrove/smurf@v1.1.5 + with: + version: ${{ inputs.smurf_version }} - - name: 🟦 Install AWS CLI + - name: Configure AWS credentials if: ${{ inputs.provider == 'aws' }} uses: aws-actions/configure-aws-credentials@v6 with: @@ -187,67 +202,96 @@ jobs: role-duration-seconds: 900 role-skip-session-tagging: true - - name: πŸ”„ Assume another IAM Role - if: inputs.aws_assume_role_arn == 'true' + - name: Assume another IAM role + if: ${{ inputs.provider == 'aws' && inputs.aws_assume_role }} uses: aws-actions/configure-aws-credentials@v6 with: - role-to-assume: '${{ inputs.aws_assume_role_arn }}' + role-to-assume: ${{ inputs.aws_assume_role_arn }} aws-region: ${{ inputs.aws_region }} - - name: 🌎 Set environment variables + - name: Authenticate to Google Cloud + if: ${{ inputs.provider == 'gcp' }} + uses: google-github-actions/auth@v3 + with: + credentials_json: ${{ secrets.GCP_CREDENTIALS }} + workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ secrets.SERVICE_ACCOUNT }} + project_id: ${{ inputs.gcp_project_id }} + + - name: Set up gcloud SDK + if: ${{ inputs.provider == 'gcp' }} + uses: google-github-actions/setup-gcloud@v2 + with: + project_id: ${{ inputs.gcp_project_id }} + install_components: gke-gcloud-auth-plugin + + - name: Update kubeconfig (GKE) + if: ${{ inputs.provider == 'gcp' }} run: | - echo "AWS_DEFAULT_REGION=${{ inputs.aws_region }}" >> $GITHUB_ENV - echo "PROVIDER=${{ inputs.provider }}" >> $GITHUB_ENV - echo "EKS_CLUSTER_NAME=${{ inputs.aws_eks_cluster_name }}" >> $GITHUB_ENV - echo "GCP_PROJECT_ID=${{ inputs.gcp_project_id }}" >> $GITHUB_ENV - echo "GCP_REGION=${{ inputs.gcp_region }}" >> $GITHUB_ENV - echo "GKE_CLUSTER_NAME=${{ inputs.gcp_gke_cluster_name }}" >> $GITHUB_ENV - echo "πŸ”Ή Setting up service account key credentials..." - echo "GCP_KEY_B64=$(echo '${{ secrets.GCP_SERVICE_ACCOUNT_KEY }}' | base64 -w0)" >> $GITHUB_ENV - echo "GOOGLE_APPLICATION_CREDENTIALS=/tmp/gcp-key.json" >> $GITHUB_ENV - shell: bash - - - name: Update Kubernetes KubeConfig - run : | - aws eks update-kubeconfig --name ${{ inputs.aws_eks_cluster_name }} --region ${{ inputs.aws_region }} - - - name: πŸ”Œ Helm Plugin - if: inputs.helm_plugin_install == 'true' + gcloud container clusters get-credentials \ + "${{ inputs.gcp_gke_cluster_name }}" \ + --region "${{ inputs.gcp_region }}" \ + --project "${{ inputs.gcp_project_id }}" + + - name: Login to Azure + if: ${{ inputs.provider == 'azure' }} + uses: azure/login@v3 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Update kubeconfig (EKS) + if: ${{ inputs.provider == 'aws' }} run: | - smurf selm plugin ${{ inputs.helm_plugins }} + aws eks update-kubeconfig \ + --name "${{ inputs.aws_eks_cluster_name }}" \ + --region "${{ inputs.aws_region }}" - - name: βž• Add Helm Chart - if: inputs.helm_repo_add == 'true' + - name: Update kubeconfig (GKE) + if: ${{ inputs.provider == 'gcp' }} run: | - smurf selm repo add ${{ inputs.helm_repository }} ${{ inputs.helm_repository_url }} + gcloud container clusters get-credentials "${{ inputs.gcp_gke_cluster_name }}" \ + --region "${{ inputs.gcp_region }}" \ + --project "${{ inputs.gcp_project_id }}" - - name: ♻️ Update Helm Charts - if: inputs.helm_repo_add == 'true' + - name: Helm Plugin + if: ${{ inputs.helm_plugin_install }} + run: smurf selm plugin ${{ inputs.helm_plugins }} + + - name: Add Helm Chart Repo + if: ${{ inputs.helm_repo_add }} run: | - smurf selm repo update + smurf selm repo add "${{ inputs.helm_repository }}" "${{ inputs.helm_repository_url }}" + + - name: Update Helm Chart Repos + if: ${{ inputs.helm_repo_add }} + run: smurf selm repo update - - name: πŸš€ Helm Deploy + - name: Helm Deploy run: | - smurf selm upgrade --install ${{ inputs.helm_flags }} ${{ secrets.aws_set_parameters }} - ${{ inputs.helm_release_name }} ${{ inputs.helm_chart_directory }} -f ${{ - inputs.helm_values_file_path }} -n=${{ inputs.helm_namespace }} --timeout ${{ - inputs.helm_timeout }} + smurf selm upgrade --install \ + "${{ inputs.helm_release_name }}" \ + "${{ inputs.helm_chart_directory }}" \ + -f "${{ inputs.helm_values_file_path }}" \ + -n "${{ inputs.helm_namespace }}" \ + --timeout "${{ inputs.helm_timeout }}" \ + ${{ inputs.helm_flags }} \ + ${{ secrets.helm_extra_args }} helm-rollback: - if: inputs.helm_rollback_enable == 'true' + name: Helm Rollback + if: ${{ inputs.helm_rollback_enable }} runs-on: ubuntu-latest - permissions: - id-token: write - contents: read + environment: ${{ inputs.target_environment }} steps: - - name: πŸ“¦ Checkout Repository + - name: Checkout uses: actions/checkout@v6 - # - Setup smurf CLI - name: Setup Smurf - uses: clouddrove/smurf@v1.1.3 + uses: clouddrove/smurf@v1.1.5 + with: + version: ${{ inputs.smurf_version }} - - name: 🟦 Install AWS CLI + - name: Configure AWS credentials if: ${{ inputs.provider == 'aws' }} uses: aws-actions/configure-aws-credentials@v6 with: @@ -259,31 +303,59 @@ jobs: role-duration-seconds: 900 role-skip-session-tagging: true - - name: πŸ”„ Assume another IAM Role - if: inputs.aws_assume_role_arn == 'true' + - name: Assume another IAM role + if: ${{ inputs.provider == 'aws' && inputs.aws_assume_role }} uses: aws-actions/configure-aws-credentials@v6 with: - role-to-assume: '${{ inputs.aws_assume_role_arn }}' + role-to-assume: ${{ inputs.aws_assume_role_arn }} aws-region: ${{ inputs.aws_region }} - - name: 🌎 Set environment variables + - name: Authenticate to Google Cloud + if: ${{ inputs.provider == 'gcp' }} + uses: google-github-actions/auth@v3 + with: + credentials_json: ${{ secrets.GCP_CREDENTIALS }} + workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ secrets.SERVICE_ACCOUNT }} + project_id: ${{ inputs.gcp_project_id }} + + - name: Set up gcloud SDK + if: ${{ inputs.provider == 'gcp' }} + uses: google-github-actions/setup-gcloud@v2 + with: + project_id: ${{ inputs.gcp_project_id }} + install_components: gke-gcloud-auth-plugin + + - name: Update kubeconfig (GKE) + if: ${{ inputs.provider == 'gcp' }} + run: | + gcloud container clusters get-credentials \ + "${{ inputs.gcp_gke_cluster_name }}" \ + --region "${{ inputs.gcp_region }}" \ + --project "${{ inputs.gcp_project_id }}" + + - name: Login to Azure + if: ${{ inputs.provider == 'azure' }} + uses: azure/login@v3 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Update kubeconfig (EKS) + if: ${{ inputs.provider == 'aws' }} run: | - echo "AWS_DEFAULT_REGION=${{ inputs.aws_region }}" >> $GITHUB_ENV - echo "PROVIDER=${{ inputs.provider }}" >> $GITHUB_ENV - echo "EKS_CLUSTER_NAME=${{ inputs.aws_eks_cluster_name }}" >> $GITHUB_ENV - echo "GCP_PROJECT_ID=${{ inputs.gcp_project_id }}" >> $GITHUB_ENV - echo "GCP_REGION=${{ inputs.gcp_region }}" >> $GITHUB_ENV - echo "GKE_CLUSTER_NAME=${{ inputs.gcp_gke_cluster_name }}" >> $GITHUB_ENV - echo "GCP_KEY_B64=$(echo '${{ secrets.GCP_SERVICE_ACCOUNT_KEY }}' | base64 -w0)" >> $GITHUB_ENV - echo "GOOGLE_APPLICATION_CREDENTIALS=/tmp/gcp-key.json" >> $GITHUB_ENV - shell: bash - - - name: Update Kubernetes KubeConfig - run : | - aws eks update-kubeconfig --name ${{ inputs.aws_eks_cluster_name }} --region ${{ inputs.aws_region }} - - - name: βͺ Helm Rollback + aws eks update-kubeconfig \ + --name "${{ inputs.aws_eks_cluster_name }}" \ + --region "${{ inputs.aws_region }}" + + - name: Update kubeconfig (GKE) + if: ${{ inputs.provider == 'gcp' }} + run: | + gcloud container clusters get-credentials "${{ inputs.gcp_gke_cluster_name }}" \ + --region "${{ inputs.gcp_region }}" \ + --project "${{ inputs.gcp_project_id }}" + + - name: Helm Rollback run: | - smurf selm rollback ${{ inputs.helm_release_name }} ${{ inputs.helm_revision }} -n=${{ - inputs.helm_namespace }} -... + smurf selm rollback "${{ inputs.helm_release_name }}" \ + "${{ inputs.helm_revision }}" \ + -n "${{ inputs.helm_namespace }}" \ No newline at end of file diff --git a/.github/workflows/tf-smurf.yml b/.github/workflows/tf-smurf.yml index 740c39a5..f32fcc90 100644 --- a/.github/workflows/tf-smurf.yml +++ b/.github/workflows/tf-smurf.yml @@ -1,5 +1,5 @@ --- -name: πŸ¦Έβ€β™‚οΈ Smurf Terraform workflow +name: πŸ¦Έβ€β™‚οΈ Smurf Terraform Shared workflow on: workflow_call: inputs: @@ -23,19 +23,24 @@ on: var_file: required: false type: string - description: 'Terraform var file directory. e.g. vars/dev.tfvars' - destroy: + description: 'Terraform var file path relative to terraform_directory. e.g. vars/dev.tfvars' + run_create: required: false type: boolean default: false - description: 'Set true to destroy terraform infrastructure.' + description: 'Run plan and apply (create infrastructure).' + run_destroy: + required: false + type: boolean + default: false + description: 'Run destroy infrastructure.' approvers: required: false type: string description: 'Approvals list to approve apply or destroy' smurf_version: type: string - default: latest + default: v1.1.5 description: 'Required Smurf version' terraform_version: type: string @@ -72,7 +77,7 @@ on: description: 'If true, the action will securely generate a credentials file which can be used for authentication via gcloud and Google Cloud SDKs.' git_ssh_key_setup: required: false - type: string + type: boolean default: false description: 'If true, sets up SSH keys for Git access to clone private repositories.' target_environment: @@ -85,6 +90,16 @@ on: required: false type: boolean default: false + plan_out: + description: 'Plan filename written inside terraform_directory (e.g. tfplan)' + required: false + type: string + default: tfplan + auto_approve: + description: 'Skip manual approval before apply or destroy' + required: false + type: boolean + default: false secrets: AZURE_CREDENTIALS: required: false @@ -121,7 +136,11 @@ on: description: 'Private SSH key to register in the SSH agent' jobs: + ############################################### + # FORMAT β†’ INIT β†’ PLAN β†’ APPLY + ############################################### terraform-execution: + if: ${{ inputs.run_create }} runs-on: ubuntu-latest environment: ${{ inputs.target_environment }} @@ -133,7 +152,7 @@ jobs: uses: actions/checkout@v6 - uses: webfactory/ssh-agent@v0.10.0 - if: ${{ inputs.git_ssh_key_setup == true }} + if: ${{ inputs.git_ssh_key_setup }} with: ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} @@ -163,6 +182,15 @@ jobs: with: creds: ${{ secrets.AZURE_CREDENTIALS }} + - name: πŸ” Set Azure Terraform credentials + if: ${{ inputs.provider == 'azurerm' }} + run: | + echo "ARM_CLIENT_ID=$(echo '${{ secrets.AZURE_CREDENTIALS }}' | jq -r .clientId)" >> "$GITHUB_ENV" + echo "ARM_CLIENT_SECRET=$(echo '${{ secrets.AZURE_CREDENTIALS }}' | jq -r .clientSecret)" >> "$GITHUB_ENV" + echo "ARM_TENANT_ID=$(echo '${{ secrets.AZURE_CREDENTIALS }}' | jq -r .tenantId)" >> "$GITHUB_ENV" + echo "ARM_SUBSCRIPTION_ID=$(echo '${{ secrets.AZURE_CREDENTIALS }}' | jq -r .subscriptionId)" >> "$GITHUB_ENV" + echo "ARM_USE_AZUREAD=true" >> "$GITHUB_ENV" + - name: ☁️ Authenticate to Google Cloud if: ${{ inputs.provider == 'gcp' }} uses: 'google-github-actions/auth@v3' @@ -185,13 +213,16 @@ jobs: uses: hashicorp/setup-terraform@v4 with: terraform_version: ${{ inputs.terraform_version }} + terraform_wrapper: false - name: βš™οΈ Set up Smurf Terraform - uses: clouddrove/smurf@v1.1.3 + uses: clouddrove/smurf@v1.1.5 + with: + version: ${{ inputs.smurf_version }} - name: 🧹 Smurf Terraform Format run: | - smurf stf format + smurf stf fmt --recursive --timeout 5s - name: πŸ—οΈ Smurf Terraform Init run: | @@ -202,54 +233,157 @@ jobs: smurf stf validate --dir=${{ inputs.terraform_directory }} - name: πŸ“‹ Terraform Plan + id: tf-plan run: | - smurf stf plan --dir=${{ inputs.terraform_directory }} + cd "${{ inputs.terraform_directory }}" + ARGS="--out=${{ inputs.plan_out }}" + if [ -n "${{ inputs.var_file }}" ]; then + ARGS="$ARGS --var-file=${{ inputs.var_file }}" + fi + smurf stf plan $ARGS + EXIT=$? + echo "exitcode=$EXIT" >> "$GITHUB_OUTPUT" + exit $EXIT - name: ⏳ Approval Before Apply - if: inputs.terraform_destroy != 'true' + if: ${{ !inputs.plan_only && !inputs.auto_approve }} uses: trstringer/manual-approval@v1 with: - secret: ${{ secrets.GITHUB_TOKEN }} + secret: ${{ github.token }} approvers: ${{ inputs.approvers }} minimum-approvals: ${{ inputs['minimum-approvals'] }} - timeout-minutes: ${{ fromJson(inputs.timeout) }} + timeout-minutes: ${{ inputs.timeout }} issue-title: "Approve Terraform Apply" - name: πŸš€ Terraform Apply - if: inputs.terraform_destroy != 'true' + if: ${{ !inputs.plan_only }} run: | - smurf stf apply --auto-approve --dir=${{ inputs.terraform_directory }} + cd "${{ inputs.terraform_directory }}" + smurf stf apply "${{ inputs.plan_out }}" ############################################### # DESTROY β†’ APPROVAL β†’ DESTROY APPLY ############################################### terraform-destroy: - if: inputs.terraform_destroy == 'true' + needs: terraform-execution + if: ${{ always() && inputs.run_destroy && (inputs.run_create != true || needs.terraform-execution.result == 'success') }} runs-on: ubuntu-latest + environment: ${{ inputs.target_environment }} steps: - name: πŸ“¦ Checkout Repository uses: actions/checkout@v6 + - uses: webfactory/ssh-agent@v0.10.0 + if: ${{ inputs.git_ssh_key_setup }} + with: + ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + + - name: 🌱 Set environment variables + run: | + ( + cat <<'_EOT' + ${{ secrets.env-vars }} + _EOT + ) >> "$GITHUB_ENV" + + - name: 🟦 Install AWS CLI + if: ${{ inputs.provider == 'aws' }} + uses: aws-actions/configure-aws-credentials@v6 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-session-token: ${{ secrets.AWS_SESSION_TOKEN }} + role-to-assume: ${{ secrets.BUILD_ROLE }} + aws-region: ${{ inputs.aws_region }} + role-duration-seconds: 900 + role-skip-session-tagging: true + + - name: ☁️ Install Azure CLI + if: ${{ inputs.provider == 'azurerm' }} + uses: azure/login@v3 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: πŸ” Set Azure Terraform credentials + if: ${{ inputs.provider == 'azurerm' }} + run: | + echo "ARM_CLIENT_ID=$(echo '${{ secrets.AZURE_CREDENTIALS }}' | jq -r .clientId)" >> "$GITHUB_ENV" + echo "ARM_CLIENT_SECRET=$(echo '${{ secrets.AZURE_CREDENTIALS }}' | jq -r .clientSecret)" >> "$GITHUB_ENV" + echo "ARM_TENANT_ID=$(echo '${{ secrets.AZURE_CREDENTIALS }}' | jq -r .tenantId)" >> "$GITHUB_ENV" + echo "ARM_SUBSCRIPTION_ID=$(echo '${{ secrets.AZURE_CREDENTIALS }}' | jq -r .subscriptionId)" >> "$GITHUB_ENV" + echo "ARM_USE_AZUREAD=true" >> "$GITHUB_ENV" + + - name: ☁️ Authenticate to Google Cloud + if: ${{ inputs.provider == 'gcp' }} + uses: 'google-github-actions/auth@v3' + with: + credentials_json: '${{ secrets.GCP_CREDENTIALS }}' + create_credentials_file: ${{ inputs.create_credentials_file }} + token_format: ${{ inputs.token_format }} + workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ secrets.SERVICE_ACCOUNT }} + access_token_lifetime: ${{ inputs.access_token_lifetime }} + project_id: ${{ inputs.project_id }} + + - name: 🟦 Install doctl + if: ${{ inputs.provider == 'digitalocean' }} + uses: digitalocean/action-doctl@v2 + with: + token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + - name: πŸ› οΈ Set up Terraform uses: hashicorp/setup-terraform@v4 with: terraform_version: ${{ inputs.terraform_version }} + terraform_wrapper: false - name: βš™οΈ Set up Smurf Terraform - uses: clouddrove/smurf@v1.1.3 + uses: clouddrove/smurf@v1.1.5 + with: + version: ${{ inputs.smurf_version }} + + - name: πŸ—οΈ Smurf Terraform Init + run: | + smurf stf init --dir=${{ inputs.terraform_directory }} + + - name: πŸ”— Import orphaned Azure resources + if: ${{ inputs.provider == 'azurerm' }} + run: | + cd "${{ inputs.terraform_directory }}" + VAR_FILE="" + if [ -n "${{ inputs.var_file }}" ]; then + VAR_FILE="${{ inputs.var_file }}" + VAR_FILE="${VAR_FILE#./}" + fi + if [ ! -s terraform.tfstate ] || [ -z "$(terraform state list 2>/dev/null)" ]; then + RG=$(grep -E '^\s*resource_group_name\s*=' "$VAR_FILE" | sed -E 's/.*=\s*"([^"]+)".*/\1/') + if az group show --name "$RG" >/dev/null 2>&1; then + echo "Importing existing resource group into state: $RG" + smurf stf import --var-file="$VAR_FILE" azurerm_resource_group.test "/subscriptions/${ARM_SUBSCRIPTION_ID}/resourceGroups/${RG}" + else + echo "Resource group $RG not found in Azure β€” nothing to import." + fi + else + echo "Terraform state already populated β€” skipping import." + fi - # APPROVAL BEFORE DESTROY (FIXED) - name: ⏳ Approval Before Destroy + if: ${{ !inputs.auto_approve }} uses: trstringer/manual-approval@v1 with: - secret: ${{ secrets.GITHUB_TOKEN }} + secret: ${{ github.token }} approvers: ${{ inputs.approvers }} minimum-approvals: ${{ inputs['minimum-approvals'] }} - timeout-minutes: ${{ fromJson(inputs.timeout) }} + timeout-minutes: ${{ inputs.timeout }} issue-title: "Approve Terraform Destroy" - name: πŸ’£ Terraform Destroy run: | - smurf stf 'destroy --auto-approve --dir=${{ inputs.terraform_directory }}' -... + cd "${{ inputs.terraform_directory }}" + ARGS="--auto-approve" + if [ -n "${{ inputs.var_file }}" ]; then + ARGS="$ARGS --var-file=${{ inputs.var_file }}" + fi + smurf stf destroy $ARGS +... \ No newline at end of file diff --git a/docs/docker-smurf.md b/docs/docker-smurf.md index 3cb6be6a..3817d2e8 100644 --- a/docs/docker-smurf.md +++ b/docs/docker-smurf.md @@ -1,35 +1,264 @@ -## [Smurf-Docker-Helm Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/.github/workflows/docker-smurf.yml) +## [Smurf Docker Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/.github/workflows/docker-smurf.yml) -This workflow is used to work with Docker and Helm using Smurf. It utilizes the workflows defined in `.github/workflows/docker-smurf.yml` +Reusable workflow for building, scanning, and pushing Docker images with [Smurf SDKR](https://github.com/clouddrove/smurf) (`smurf sdkr`). -#### Usage -The following workflow can work with Docker Using Smurf tool. It can Build Images, Scan and Push. +**Shared workflow:** `.github/workflows/docker-smurf.yml` +**Caller workflow:** lives in your application repo under `.github/workflows/` and calls the shared workflow via `workflow_call`. -It handles: -- 🐳 Build Docker image -- πŸ’Ύ Save image as artifact -- πŸ›‘οΈ Scan image for vulnerabilities -- 🏷️ Tag image for registry -- πŸš€ Push image to registry (AWS / GCP / others) +### Architecture -#### Example for Smurf-Docker-Helm +``` +Your repo (caller) github-shared-workflows (shared) +───────────────── ───────────────────────────────── +.github/workflows/ + docker-caller.yml ──uses──► .github/workflows/docker-smurf.yml + β”‚ + β”œβ”€β”€ job: docker_build + β”‚ build β†’ save tar β†’ upload artifact + β”‚ + └── job: docker_scan_push (needs docker_build) + download β†’ load β†’ scan β†’ tag β†’ push +``` + +**Rule:** One caller **job** invokes one shared workflow. The shared workflow runs `docker_build` and `docker_scan_push` internally when enabled. + +### What it does + +- Build a Docker image with `smurf sdkr build` +- Save the image as a tar artifact (`docker-image`) for the scan/push job +- Scan with Trivy via `smurf sdkr scan` +- Tag and push to AWS ECR, Azure ACR, GCP GCR/Artifact Registry, or Docker Hub + +### Required repository setup + +1. Commit a `Dockerfile` at the path you pass as `dockerfile_path` (default: `Dockerfile` at repo root). +2. The `-f` flag path is **relative to the build context** (repo root by default). +3. Grant the caller repo permission to use shared workflows from `clouddrove/github-shared-workflows` (org settings β†’ Actions β†’ access). + +### Image naming + +The full pushed image is assembled in the shared workflow: + +``` +{docker_registry_url}/{docker_image_name}:{docker_image_tag} +``` + +| Input | Example | Notes | +|-------|---------|-------| +| `docker_registry_url` | `924144197303.dkr.ecr.us-east-1.amazonaws.com` | Registry host only β€” no image name or tag | +| `docker_image_name` | `smurf/smurt-test` | Repository path inside the registry | +| `docker_image_tag` | `${{ github.sha }}` | Tag applied at build and push | + +**Example full image:** +`924144197303.dkr.ecr.us-east-1.amazonaws.com/smurf/smurt-test:abc1234` + +### Inputs + +| Input | Type | Default | Description | +|-------|------|---------|-------------| +| `docker_enable` | string | β€” | Set to `'true'` to run build (and scan/push when push enabled) | +| `docker_push` | string | β€” | Set to `'true'` to scan, tag, and push after build | +| `provider` | string | `aws` | Cloud provider for auth (`aws`, `azure`, `gcp`, `digitalocean`) | +| `docker_image_name` | string | β€” | Local and registry image name (without registry host) | +| `docker_image_tag` | string | `latest` | Image tag | +| `docker_image_tar` | string | `image` | Filename for saved tar artifact | +| `docker_registry` | string | `aws` | Push target: `aws`, `az`, `gcp`, or `hub` | +| `docker_registry_url` | string | β€” | Registry URL (required for push) | +| `dockerfile_path` | string | `Dockerfile` | Dockerfile path relative to repo root | +| `docker_build_args` | string | `key1=val1` | Single `--build-arg` value | +| `docker_build_platform` | string | `linux/amd64` | Target platform | +| `docker_buildkit_enable` | string | `false` | Set to `'true'` to pass `--buildkit` | +| `aws_region` | string | `us-east-1` | AWS region for ECR auth | +| `aws_assume_role` | string | `false` | Set to `'true'` to assume `aws_assume_role_arn` | +| `aws_assume_role_arn` | string | β€” | Secondary IAM role ARN | +| `gcp_auth_method` | string | β€” | `wip` or `json` for GCP auth | +| `gcp_project_id` | string | β€” | GCP project ID | +| `gcp_region` | string | `us-central1` | GCP region | +| `gcp_docker_push` | string | `false` | Set to `'true'` to push with `--project-id` (GCP) | + +> **Note:** `docker_enable`, `docker_push`, and other toggles use the string `'true'` / `'false'`, not YAML booleans. + +### Secrets + +| Secret | Required when | Description | +|--------|---------------|-------------| +| `BUILD_ROLE` | AWS OIDC | IAM role ARN for `configure-aws-credentials` | +| `AWS_ACCESS_KEY_ID` | AWS keys | Optional static key auth | +| `AWS_SECRET_ACCESS_KEY` | AWS keys | Optional static key auth | +| `AWS_SESSION_TOKEN` | AWS keys | Optional session token | +| `GCP_WIP` | GCP WIP | Workload Identity Provider | +| `GCP_SERVICE_ACCOUNT` | GCP WIP | Service account email | +| `GOOGLE_CREDENTIALS` | GCP JSON | Service account JSON key | +| `DOCKER_USERNAME` | Docker Hub | Hub username | +| `DOCKER_PASSWORD` | Docker Hub | Hub access token or password | + +### Caller permissions + +Add to the caller workflow when using OIDC (AWS/GCP): + +```yaml +permissions: + id-token: write + contents: read +``` + +--- + +### Example: AWS ECR (push on branch) ```yaml -name: Smurf-Docker +name: Smurf Docker β€” AWS ECR + on: push: + branches: [main] + +permissions: + id-token: write + contents: read + +jobs: + docker-ecr: + uses: clouddrove/github-shared-workflows/.github/workflows/docker-smurf.yml@v2 + with: + docker_enable: 'true' + docker_push: 'true' + provider: aws + docker_registry: aws + docker_image_name: smurf/smurt-test + docker_image_tag: ${{ github.sha }} + docker_registry_url: 924144197303.dkr.ecr.us-east-1.amazonaws.com + dockerfile_path: Dockerfile + aws_region: us-east-1 + secrets: + BUILD_ROLE: ${{ secrets.BUILD_ROLE }} +``` + +**Repository secrets:** `BUILD_ROLE` (OIDC role with ECR push permissions). + +--- + +### Example: Docker Hub (manual dispatch) + +```yaml +name: Smurf Docker β€” Docker Hub + +on: + workflow_dispatch: + +permissions: + contents: read jobs: - dev: + docker-hub: uses: clouddrove/github-shared-workflows/.github/workflows/docker-smurf.yml@v2 with: - docker_image_name: # Image Name - docker_image_tag: # Image Tag - dockerfile_path: # Dockerfile path - docker_registry_url: # Registry URL - docker_registry: # Registry + docker_enable: 'true' + docker_push: 'true' + docker_registry: hub + docker_image_name: anketclouddrove/smurf-workflows + docker_image_tag: ${{ github.sha }} + docker_registry_url: docker.io + dockerfile_path: Dockerfile secrets: - set-parameters: - --set image.tag=${{ github.run_id }} - --set password=${{ secrets.PASSWORD }} -``` \ No newline at end of file + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} +``` + +--- + +### Example: GCP Artifact Registry + +```yaml +name: Smurf Docker β€” GCP + +on: + workflow_dispatch: + +permissions: + id-token: write + contents: read + +jobs: + docker-gcp: + uses: clouddrove/github-shared-workflows/.github/workflows/docker-smurf.yml@v2 + with: + docker_enable: 'true' + docker_push: 'true' + provider: gcp + docker_registry: gcp + gcp_auth_method: json + gcp_project_id: my-gcp-project + gcp_docker_push: 'true' + docker_image_name: my-app + docker_image_tag: ${{ github.sha }} + docker_registry_url: us-central1-docker.pkg.dev/my-gcp-project/my-repo + dockerfile_path: Dockerfile + secrets: + GOOGLE_CREDENTIALS: ${{ secrets.GCP_CREDENTIALS }} +``` + +For Workload Identity, set `gcp_auth_method: wip` and pass `GCP_WIP` + `GCP_SERVICE_ACCOUNT` secrets instead. + +--- + +### Example: Azure ACR + +```yaml +name: Smurf Docker β€” Azure ACR + +on: + workflow_dispatch: + +permissions: + id-token: write + contents: read + +jobs: + docker-azure: + uses: clouddrove/github-shared-workflows/.github/workflows/docker-smurf.yml@v2 + with: + docker_enable: 'true' + docker_push: 'true' + provider: azure + docker_registry: az + docker_image_name: my-app + docker_image_tag: ${{ github.sha }} + docker_registry_url: myregistry.azurecr.io + dockerfile_path: Dockerfile + secrets: + BUILD_ROLE: ${{ secrets.BUILD_ROLE }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} +``` + +> Configure Azure ACR credentials per your org’s Smurf/Azure setup. The shared workflow uses AWS credential action for `provider: aws`; for Azure registry push, align secrets with your ACR authentication method. + +--- + +### Build only (no push) + +```yaml +jobs: + docker-build: + uses: clouddrove/github-shared-workflows/.github/workflows/docker-smurf.yml@v2 + with: + docker_enable: 'true' + docker_push: 'false' + docker_image_name: my-app + docker_image_tag: ${{ github.sha }} + dockerfile_path: Dockerfile +``` + +--- + +### Troubleshooting + +| Issue | Cause | Fix | +|-------|-------|-----| +| `failed to read dockerfile` | Dockerfile not in git or wrong path | Commit `Dockerfile`; use path relative to repo root (e.g. `Dockerfile`, not `./Dockerfile` if Smurf joins paths) | +| Artifact upload fails | `/` in artifact name | Shared workflow uses fixed name `docker-image` β€” do not put `/` in `docker_image_name` for artifact naming | +| ECR login / push fails | Missing OIDC or wrong registry URL | Set `BUILD_ROLE`; hardcode full ECR host in `docker_registry_url` | +| Hub push fails | Missing env vars | Set `DOCKER_USERNAME` and `DOCKER_PASSWORD` secrets; use `docker_registry: hub` | +| Scan step fails | Trivy not installed | Handled by shared workflow β€” ensure `docker_push: 'true'` so scan job runs after successful build | +| Job skipped | Wrong toggle type | Use string `'true'`, not boolean `true`, for `docker_enable` and `docker_push` | diff --git a/docs/helm-smurf.md b/docs/helm-smurf.md index 12f7a509..64bed2af 100644 --- a/docs/helm-smurf.md +++ b/docs/helm-smurf.md @@ -1,34 +1,283 @@ -## [Smurf-Docker-Helm Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/.github/workflows/helm-smurf.yml) +## [Smurf Helm Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/.github/workflows/helm-smurf.yml) -This workflow is used to work with Helm using Smurf. It utilizes the workflows defined in `.github/workflows/helm-smurf.yml` +Reusable workflow for Helm chart lint, template, deploy, and rollback using [Smurf SELM](https://github.com/clouddrove/smurf) (`smurf selm`). -#### Usage -The following workflow can work with Helm Using Smurf tool. Talking about the Helm part it can Lint, Template, Deploy and also provides Rollback feature. +**Shared workflow:** `.github/workflows/helm-smurf.yml` +**Caller workflow:** lives in your application repo and calls the shared workflow via `workflow_call`. -It automates Helm operations for Kubernetes: -- βœ… Helm lint (validate chart) -- βœ… Helm template (render manifests) -- βœ… Helm deploy (install/upgrade release) -- βœ… Helm rollback (revert to previous version) +### Architecture -#### Example for Smurf-Docker-Helm +``` +Your repo (caller) github-shared-workflows (shared) +───────────────── ───────────────────────────────── +.github/workflows/ + helm-caller.yml ──uses──► .github/workflows/helm-smurf.yml + β”‚ + β”œβ”€β”€ job: helm-lint (helm_enable) + β”œβ”€β”€ job: helm-deploy (helm_enable, needs lint) + └── job: helm-rollback (helm_rollback_enable) +``` + +**Rule:** One caller **job** = one shared workflow invocation. Use separate caller jobs (or separate workflow files) for deploy vs rollback if you want independent triggers. + +### What it does + +- **Lint** β€” `smurf selm lint` on chart + values +- **Template** β€” `smurf selm template` to render manifests +- **Deploy** β€” `smurf selm upgrade --install` against EKS, GKE, or AKS +- **Rollback** β€” `smurf selm rollback` to a specific revision + +Cloud authentication and kubeconfig setup run inside the deploy/rollback jobs based on `provider`. + +### Required repository setup + +1. Helm chart directory committed to the repo (e.g. `./charts/my-app/`). +2. Values file path relative to repo root (e.g. `./charts/my-app/values.yaml`). +3. Cluster access via OIDC/keys (AWS), service account (GCP), or service principal (Azure). +4. Optional: GitHub **Environment** for approval gates β€” set `target_environment`. + +### Inputs + +| Input | Type | Default | Description | +|-------|------|---------|-------------| +| `provider` | string | `aws` | `aws`, `gcp`, or `azure` | +| `helm_enable` | boolean | `false` | Run lint + deploy jobs | +| `helm_rollback_enable` | boolean | `false` | Run rollback job | +| `helm_release_name` | string | β€” | Helm release name | +| `helm_chart_directory` | string | β€” | Path to chart directory | +| `helm_values_file_path` | string | β€” | Values file path (repo root relative) | +| `helm_namespace` | string | `default` | Kubernetes namespace | +| `helm_revision` | string | β€” | Revision for rollback | +| `helm_timeout` | string | `5m` | Install/upgrade timeout | +| `helm_flags` | string | `--atomic --wait --create-namespace` | Extra upgrade flags | +| `helm_plugin_install` | boolean | `false` | Install Helm plugins before deploy | +| `helm_plugins` | string | β€” | Args for `smurf selm plugin` | +| `helm_repo_add` | boolean | `false` | Add remote Helm repo before deploy | +| `helm_repository` | string | β€” | Repo name for `helm repo add` | +| `helm_repository_url` | string | β€” | Repo URL | +| `target_environment` | string | `""` | GitHub Environment name (empty = no gate) | +| `smurf_version` | string | `v1.1.5` | Smurf CLI version | +| `aws_region` | string | `us-east-1` | AWS region | +| `aws_eks_cluster_name` | string | β€” | EKS cluster name | +| `aws_assume_role` | boolean | `false` | Assume secondary IAM role | +| `aws_assume_role_arn` | string | β€” | Secondary role ARN | +| `gcp_project_id` | string | β€” | GCP project ID | +| `gcp_region` | string | `us-central1` | GCP region | +| `gcp_gke_cluster_name` | string | β€” | GKE cluster name | + +### Secrets + +| Secret | Required when | Description | +|--------|---------------|-------------| +| `BUILD_ROLE` | AWS OIDC | IAM role for EKS kubeconfig | +| `AWS_ACCESS_KEY_ID` | AWS keys | Static key auth (optional) | +| `AWS_SECRET_ACCESS_KEY` | AWS keys | Static key auth (optional) | +| `AWS_SESSION_TOKEN` | AWS keys | Optional session token | +| `GCP_CREDENTIALS` | GCP JSON | Service account JSON | +| `WORKLOAD_IDENTITY_PROVIDER` | GCP WIP | Workload Identity Provider | +| `SERVICE_ACCOUNT` | GCP WIP | GCP service account email | +| `AZURE_CREDENTIALS` | Azure | Service principal JSON | +| `helm_extra_args` | Optional | Extra CLI args (e.g. `--set image.tag=latest`) | + +### Caller permissions ```yaml -name: Smurf-Helm +permissions: + id-token: write + contents: read +``` + +--- + +### Example: AWS EKS deploy (push trigger) + +```yaml +name: Smurf Helm β€” AWS EKS + on: push: + branches: [main] + paths: + - 'charts/**' + +permissions: + id-token: write + contents: read + +jobs: + helm-deploy: + uses: clouddrove/github-shared-workflows/.github/workflows/helm-smurf.yml@v2 + with: + provider: aws + helm_enable: true + helm_release_name: temp-app + helm_chart_directory: ./temp + helm_values_file_path: ./temp/values.yaml + helm_namespace: default + aws_region: us-east-1 + aws_eks_cluster_name: my-eks-cluster + helm_timeout: 5m + secrets: + BUILD_ROLE: ${{ secrets.BUILD_ROLE }} + helm_extra_args: --set image.tag=${{ github.sha }} +``` + +--- + +### Example: GCP GKE deploy + +```yaml +name: Smurf Helm β€” GCP GKE + +on: + workflow_dispatch: + +permissions: + id-token: write + contents: read jobs: - dev: + helm-deploy: uses: clouddrove/github-shared-workflows/.github/workflows/helm-smurf.yml@v2 with: - helm_release_name: # Release name - helm_chart_directory: # Helm Chart Directory - helm_enable: # Set to True for Helm Work - helm_values_file_path: # Helm Chart Values Path - helm_namespace: # Namespace - timeout: # Timeout + provider: gcp + helm_enable: true + helm_release_name: my-app + helm_chart_directory: ./charts/my-app + helm_values_file_path: ./charts/my-app/values-prod.yaml + helm_namespace: production + gcp_project_id: my-gcp-project + gcp_region: us-central1 + gcp_gke_cluster_name: my-gke-cluster secrets: - set-parameters: - --set password=${{ secrets.PASSWORD }} -``` \ No newline at end of file + GCP_CREDENTIALS: ${{ secrets.GCP_CREDENTIALS }} + helm_extra_args: --set image.tag=${{ github.sha }} +``` + +For Workload Identity, pass `WORKLOAD_IDENTITY_PROVIDER` and `SERVICE_ACCOUNT` instead of (or in addition to) `GCP_CREDENTIALS`. + +--- + +### Example: Azure AKS deploy + +```yaml +name: Smurf Helm β€” Azure AKS + +on: + workflow_dispatch: + +permissions: + id-token: write + contents: read + +jobs: + helm-deploy: + uses: clouddrove/github-shared-workflows/.github/workflows/helm-smurf.yml@v2 + with: + provider: azure + helm_enable: true + helm_release_name: my-app + helm_chart_directory: ./charts/my-app + helm_values_file_path: ./charts/my-app/values.yaml + helm_namespace: default + secrets: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} +``` + +Ensure the Azure service principal has `Azure Kubernetes Service Cluster User Role` on the target cluster. + +--- + +### Example: Deploy + rollback (manual dispatch) + +Use one caller workflow with two jobs β€” deploy and rollback are controlled by dispatch inputs: + +```yaml +name: Smurf Helm β€” Deploy or Rollback + +on: + workflow_dispatch: + inputs: + action: + description: Action to perform + required: true + type: choice + options: + - deploy + - rollback + revision: + description: Rollback revision (required for rollback) + required: false + type: string + +permissions: + id-token: write + contents: read + +jobs: + helm-deploy: + if: ${{ github.event.inputs.action == 'deploy' }} + uses: clouddrove/github-shared-workflows/.github/workflows/helm-smurf.yml@v2 + with: + provider: aws + helm_enable: true + helm_release_name: temp-app + helm_chart_directory: ./temp + helm_values_file_path: ./temp/values.yaml + helm_namespace: default + aws_region: us-east-1 + aws_eks_cluster_name: my-eks-cluster + secrets: + BUILD_ROLE: ${{ secrets.BUILD_ROLE }} + + helm-rollback: + if: ${{ github.event.inputs.action == 'rollback' }} + uses: clouddrove/github-shared-workflows/.github/workflows/helm-smurf.yml@v2 + with: + provider: aws + helm_rollback_enable: true + helm_release_name: temp-app + helm_revision: ${{ github.event.inputs.revision }} + helm_namespace: default + aws_region: us-east-1 + aws_eks_cluster_name: my-eks-cluster + secrets: + BUILD_ROLE: ${{ secrets.BUILD_ROLE }} +``` + +--- + +### Example: Remote chart repo + plugins + +```yaml +jobs: + helm-deploy: + uses: clouddrove/github-shared-workflows/.github/workflows/helm-smurf.yml@v2 + with: + provider: aws + helm_enable: true + helm_repo_add: true + helm_repository: bitnami + helm_repository_url: https://charts.bitnami.com/bitnami + helm_plugin_install: true + helm_plugins: install diff + helm_release_name: nginx + helm_chart_directory: bitnami/nginx + helm_values_file_path: ./values/nginx.yaml + aws_eks_cluster_name: my-eks-cluster + aws_region: us-east-1 + secrets: + BUILD_ROLE: ${{ secrets.BUILD_ROLE }} +``` + +--- + +### Troubleshooting + +| Issue | Cause | Fix | +|-------|-------|-----| +| Lint passes, deploy fails on kubeconfig | Wrong cluster name or region | Verify `aws_eks_cluster_name` / `gcp_gke_cluster_name` and region inputs | +| Rollback job skipped | Flag not set | Set `helm_rollback_enable: true` and provide `helm_revision` | +| Deploy and rollback both run | Both flags true | Use separate caller jobs with `if` conditions | +| `helm_extra_args` ignored | Wrong secret name | Pass as `secrets.helm_extra_args`, not under `with` | +| Environment gate blocks deploy | `target_environment` set | Configure environment protection rules or leave empty | diff --git a/docs/tf-smurf.md b/docs/tf-smurf.md index 30c6c698..b36559a1 100644 --- a/docs/tf-smurf.md +++ b/docs/tf-smurf.md @@ -1,28 +1,310 @@ ## [Smurf Terraform Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/.github/workflows/tf-smurf.yml) -This workflow is used to work with Terraform using Smurf. It utilizes the workflows defined in `.github/workflows/tf-smurf.yml` +Reusable workflow for Terraform plan, apply, and destroy using [Smurf STF](https://github.com/clouddrove/smurf) (`smurf stf`). -#### Usage -The following workflow can work with Terraform Using Smurf. It can Format, Init, Validate, Plan, Apply and Destroy Infrastructure. +**Shared workflow:** `.github/workflows/tf-smurf.yml` +**Caller workflow:** lives in your application repo and calls the shared workflow via `workflow_call`. -#### Example for Smurf Terraform +### Architecture + +``` +Your repo (caller) github-shared-workflows (shared) +───────────────── ───────────────────────────────── +.github/workflows/ + tf-caller.yml ──uses──► .github/workflows/tf-smurf.yml + β”‚ + β”œβ”€β”€ job: terraform-execution (run_create) + β”‚ fmt β†’ init β†’ validate β†’ plan β†’ [approval] β†’ apply + β”‚ + └── job: terraform-destroy (run_destroy) + init β†’ [azure import] β†’ [approval] β†’ destroy +``` + +**Rule:** One caller **job** invokes one shared workflow. Control apply vs destroy with boolean inputs `run_create` and `run_destroy`. + +### What it does + +**Create path (`run_create: true`):** + +1. Cloud authentication (AWS, Azure, GCP, or DigitalOcean) +2. `smurf stf fmt` β†’ `init` β†’ `validate` β†’ `plan` β†’ optional manual approval β†’ `apply` + +**Destroy path (`run_destroy: true`):** + +1. Re-authenticate and `init` +2. Azure: optional import of orphaned resource group into state +3. Optional manual approval β†’ `smurf stf destroy` + +When both flags are set in one run, destroy runs after create completes successfully. + +### Required repository setup + +1. Terraform root directory committed (e.g. `./terraform/` or `./examples/complete/`). +2. Optional var file path relative to `terraform_directory` (e.g. `vars/dev.tfvars`). +3. Cloud credentials stored as repository or environment secrets. +4. For manual approval: set `approvers` to GitHub usernames (comma-separated) unless `auto_approve: true`. + +### Inputs + +| Input | Type | Default | Description | +|-------|------|---------|-------------| +| `terraform_directory` | string | **required** | Terraform root directory | +| `provider` | string | **required** | `aws`, `azurerm`, `gcp`, or `digitalocean` | +| `run_create` | boolean | `false` | Run plan/apply job | +| `run_destroy` | boolean | `false` | Run destroy job | +| `var_file` | string | β€” | Var file path relative to `terraform_directory` | +| `plan_only` | boolean | `false` | Plan only β€” skip apply | +| `plan_out` | string | `tfplan` | Plan filename inside `terraform_directory` | +| `auto_approve` | boolean | `false` | Skip manual approval steps | +| `approvers` | string | β€” | GitHub usernames for approval | +| `minimum-approvals` | string | `1` | Minimum approvers required | +| `timeout` | number | `10` | Approval timeout (minutes) | +| `target_environment` | string | `""` | GitHub Environment for gates | +| `terraform_version` | string | `1.3.6` | Terraform CLI version | +| `smurf_version` | string | `v1.1.5` | Smurf CLI version | +| `aws_region` | string | `us-east-2` | AWS region | +| `gcp_region` | string | β€” | GCP region | +| `project_id` | string | β€” | GCP project ID | +| `git_ssh_key_setup` | boolean | `false` | Enable SSH agent for private module clones | +| `create_credentials_file` | string | `true` | GCP credentials file generation | +| `token_format` | string | `access_token` | GCP token format | +| `access_token_lifetime` | string | `300s` | GCP token lifetime | + +### Secrets + +| Secret | Required when | Description | +|--------|---------------|-------------| +| `AZURE_CREDENTIALS` | Azure | Service principal JSON (`clientId`, `clientSecret`, `tenantId`, `subscriptionId`) | +| `BUILD_ROLE` | AWS OIDC | IAM role ARN | +| `AWS_ACCESS_KEY_ID` | AWS keys | Static access key | +| `AWS_SECRET_ACCESS_KEY` | AWS keys | Static secret key | +| `AWS_SESSION_TOKEN` | AWS keys | Optional session token | +| `GCP_CREDENTIALS` | GCP JSON | Service account key | +| `WORKLOAD_IDENTITY_PROVIDER` | GCP WIP | Workload Identity Provider | +| `SERVICE_ACCOUNT` | GCP WIP | Service account email | +| `DIGITALOCEAN_ACCESS_TOKEN` | DigitalOcean | API token | +| `env-vars` | Optional | Multiline env vars injected into `$GITHUB_ENV` | +| `SSH_PRIVATE_KEY` | Private modules | SSH key when `git_ssh_key_setup: true` | + +Azure credentials are also exported as `ARM_*` environment variables automatically. + +--- + +### Example: AWS apply (manual dispatch) + +```yaml +name: Smurf Terraform β€” AWS Apply + +on: + workflow_dispatch: + inputs: + apply: + description: Run plan and apply + type: boolean + default: true + +permissions: + id-token: write + contents: read + +jobs: + terraform-apply: + uses: clouddrove/github-shared-workflows/.github/workflows/tf-smurf.yml@v2 + with: + terraform_directory: ./terraform + provider: aws + run_create: ${{ github.event.inputs.apply }} + run_destroy: false + var_file: vars/dev.tfvars + aws_region: us-east-1 + approvers: your-github-username + auto_approve: false + secrets: + BUILD_ROLE: ${{ secrets.BUILD_ROLE }} +``` + +--- + +### Example: AWS destroy only + +```yaml +name: Smurf Terraform β€” AWS Destroy + +on: + workflow_dispatch: + +permissions: + id-token: write + contents: read + +jobs: + terraform-destroy: + uses: clouddrove/github-shared-workflows/.github/workflows/tf-smurf.yml@v2 + with: + terraform_directory: ./terraform + provider: aws + run_create: false + run_destroy: true + var_file: vars/dev.tfvars + aws_region: us-east-1 + approvers: your-github-username + secrets: + BUILD_ROLE: ${{ secrets.BUILD_ROLE }} +``` + +--- + +### Example: Azure apply + optional destroy + +```yaml +name: Smurf Terraform β€” Azure + +on: + workflow_dispatch: + inputs: + run_apply: + description: Plan and apply + type: boolean + default: true + run_destroy: + description: Destroy infrastructure + type: boolean + default: false + +permissions: + id-token: write + contents: read + +jobs: + terraform: + uses: clouddrove/github-shared-workflows/.github/workflows/tf-smurf.yml@v2 + with: + terraform_directory: ./examples/complete + provider: azurerm + run_create: ${{ github.event.inputs.run_apply }} + run_destroy: ${{ github.event.inputs.run_destroy }} + var_file: vars/dev.tfvars + approvers: your-github-username + auto_approve: false + secrets: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} +``` + +The destroy job includes an Azure-specific step that imports an existing resource group into state when state is empty but the group already exists in Azure (resource address: `azurerm_resource_group.test`). + +--- + +### Example: GCP with Workload Identity + +```yaml +name: Smurf Terraform β€” GCP + +on: + workflow_dispatch: + +permissions: + id-token: write + contents: read + +jobs: + terraform-apply: + uses: clouddrove/github-shared-workflows/.github/workflows/tf-smurf.yml@v2 + with: + terraform_directory: ./terraform + provider: gcp + run_create: true + run_destroy: false + project_id: my-gcp-project + gcp_region: us-central1 + var_file: vars/prod.tfvars + approvers: your-github-username + secrets: + WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }} + SERVICE_ACCOUNT: ${{ secrets.SERVICE_ACCOUNT }} +``` + +--- + +### Example: Plan only (no apply) ```yaml -name: Smurf Terraform +jobs: + terraform-plan: + uses: clouddrove/github-shared-workflows/.github/workflows/tf-smurf.yml@v2 + with: + terraform_directory: ./terraform + provider: aws + run_create: true + plan_only: true + var_file: vars/dev.tfvars + aws_region: us-east-1 + auto_approve: true + secrets: + BUILD_ROLE: ${{ secrets.BUILD_ROLE }} +``` + +--- + +### Example: DigitalOcean + +```yaml +name: Smurf Terraform β€” DigitalOcean + on: - push: + workflow_dispatch: + +jobs: + terraform: + uses: clouddrove/github-shared-workflows/.github/workflows/tf-smurf.yml@v2 + with: + terraform_directory: ./terraform + provider: digitalocean + run_create: true + var_file: vars/dev.tfvars + approvers: your-github-username + secrets: + DIGITALOCEAN_ACCESS_TOKEN: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} +``` + +--- + +### Example: Private Terraform modules (SSH) +```yaml jobs: - dev: + terraform: uses: clouddrove/github-shared-workflows/.github/workflows/tf-smurf.yml@v2 with: - terraform_directory: # Terraform Directory - aws_auth_method: # AWS auth method to use like oidc and keys - aws_role: # AWS role - aws_region: # AWS region - approvers: # Approvals list to approve apply or destroy + terraform_directory: ./terraform + provider: aws + run_create: true + git_ssh_key_setup: true + aws_region: us-east-1 secrets: - AWS_ACCESS_KEY_ID: # Specify AWS Access key ID - AWS_SECRET_ACCESS_KEY: # Specify AWS Secret Access key ID - AWS_SESSION_TOKEN: # Specify Session ID + BUILD_ROLE: ${{ secrets.BUILD_ROLE }} + SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} + env-vars: | + TF_VAR_example=production ``` + +--- + +### Job flow reference + +| `run_create` | `run_destroy` | Jobs that run | +|--------------|---------------|---------------| +| `true` | `false` | `terraform-execution` only | +| `false` | `true` | `terraform-destroy` only | +| `true` | `true` | `terraform-execution` then `terraform-destroy` (if apply succeeds) | +| `false` | `false` | Nothing runs | + +### Troubleshooting + +| Issue | Cause | Fix | +|-------|-------|-----| +| Apply blocked | Manual approval | Approve the issue created by `trstringer/manual-approval`, or set `auto_approve: true` | +| Azure destroy fails on missing state | Resource exists outside state | Destroy job attempts RG import β€” ensure var file has `resource_group_name` and resource address matches `azurerm_resource_group.test` | +| Plan file not found on apply | Wrong `plan_out` | Keep default `tfplan` or ensure plan and apply use the same filename | +| GCP auth fails | Missing WIP or JSON key | Pass `GCP_CREDENTIALS` or WIP + service account secrets | +| Destroy skipped after failed apply | By design | Fix apply first; destroy only runs when `run_create` is false or apply succeeded | +| ARM_* not set | Bad Azure JSON secret | `AZURE_CREDENTIALS` must be valid JSON with all four fields | From a7909da5300714af28e94eb8e620803041c3815e Mon Sep 17 00:00:00 2001 From: Anket Satbhai Date: Fri, 10 Jul 2026 21:58:40 +0530 Subject: [PATCH 2/3] feat: add comments and emoji --- .github/workflows/docker-smurf.yml | 103 ++++++++++++++++---------- .github/workflows/helm-smurf.yml | 115 ++++++++++++++++++----------- .github/workflows/tf-smurf.yml | 25 ++++++- 3 files changed, 159 insertions(+), 84 deletions(-) diff --git a/.github/workflows/docker-smurf.yml b/.github/workflows/docker-smurf.yml index 4e966999..b965646a 100644 --- a/.github/workflows/docker-smurf.yml +++ b/.github/workflows/docker-smurf.yml @@ -1,30 +1,27 @@ --- -name: Smurf-Docker +# Reusable Smurf SDKR workflow β€” build, scan, and push Docker images. +# Docs: docs/docker-smurf.md +name: 🐳 Smurf-Docker on: workflow_call: inputs: + # ── General toggles ────────────────────────────────────────────── docker_enable: description: Set to true to run docker commands type: string required: false - aws_auth_method: - description: AWS auth method to use like oidc and keys - type: string - required: false - aws_eks_cluster_name: - description: AWS eks cluster name + docker_push: + description: Set true for docker push type: string required: false - aws_role: - description: AWS OIDC role for aws authentication. - type: string - default: 'false' provider: description: Cloud provider (aws, azure, gcp, digitalocean) type: string required: false default: aws + + # ── Docker image & build ───────────────────────────────────────── docker_image_name: description: Docker image name type: string @@ -38,15 +35,6 @@ on: type: string required: false default: image - docker_push: - description: Set true for docker push - type: string - required: false - docker_buildkit_enable: - description: Set true to enable docker buildkit - type: string - required: false - default: 'false' docker_registry: description: 'The registry to Push Docker Image (aws, az, gcp, hub)' type: string @@ -67,6 +55,25 @@ on: description: Docker Image Build Platform type: string default: linux/amd64 + docker_buildkit_enable: + description: Set true to enable docker buildkit + type: string + required: false + default: 'false' + + # ── AWS ────────────────────────────────────────────────────────── + aws_auth_method: + description: AWS auth method to use like oidc and keys + type: string + required: false + aws_eks_cluster_name: + description: AWS eks cluster name + type: string + required: false + aws_role: + description: AWS OIDC role for aws authentication. + type: string + default: 'false' aws_region: required: false type: string @@ -81,6 +88,8 @@ on: type: string description: AWS assume role required: false + + # ── GCP ────────────────────────────────────────────────────────── gcp_project_id: required: false type: string @@ -105,6 +114,7 @@ on: required: false secrets: + # ── AWS secrets ────────────────────────────────────────────────── AWS_ACCESS_KEY_ID: required: false description: AWS Access Key ID for direct authentication @@ -117,6 +127,8 @@ on: BUILD_ROLE: required: false description: AWS OIDC role for aws authentication + + # ── GCP secrets ────────────────────────────────────────────────── GCP_WIP: required: false description: 'WIP Connected with Service Account' @@ -129,17 +141,23 @@ on: GCP_SERVICE_ACCOUNT_KEY: required: false description: 'GCP service account JSON Key' + + # ── Docker Hub secrets ─────────────────────────────────────────── DOCKER_USERNAME: required: false description: Docker Hub username DOCKER_PASSWORD: required: false description: Docker Hub access token or password + aws_set_parameters: required: false description: Overriding the default values using --set flag jobs: + ############################################### + # BUILD β†’ SAVE β†’ UPLOAD ARTIFACT + ############################################### docker_build: if: inputs.docker_enable == 'true' runs-on: ubuntu-latest @@ -147,13 +165,13 @@ jobs: id-token: write contents: read steps: - - name: Checkout + - name: πŸ“¦ Checkout uses: actions/checkout@v6 - - name: Setup Smurf + - name: βš™οΈ Setup Smurf uses: clouddrove/smurf@v1.1.5 - - name: Docker Image Build + - name: 🐳 Docker Image Build if: inputs.docker_buildkit_enable != 'true' run: | smurf sdkr build ${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} \ @@ -161,7 +179,7 @@ jobs: --platform ${{ inputs.docker_build_platform }} \ --build-arg ${{ inputs.docker_build_args }} - - name: Docker Image Build with Buildkit + - name: 🐳 Docker Image Build with Buildkit if: inputs.docker_buildkit_enable == 'true' run: | smurf sdkr build ${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} \ @@ -170,17 +188,20 @@ jobs: --build-arg ${{ inputs.docker_build_args }} \ --buildkit - - name: Save Docker Image as Artifact + - name: πŸ’Ύ Save Docker Image as Artifact run: | docker save ${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} \ -o ${{ inputs.docker_image_tar }} - - name: Upload Docker Image Artifact + - name: πŸ“€ Upload Docker Image Artifact uses: actions/upload-artifact@v7 with: name: docker-image path: ${{ inputs.docker_image_tar }} + ############################################### + # DOWNLOAD β†’ AUTH β†’ SCAN β†’ TAG β†’ PUSH + ############################################### docker_scan_push: if: inputs.docker_enable == 'true' && inputs.docker_push == 'true' runs-on: ubuntu-latest @@ -189,21 +210,22 @@ jobs: id-token: write contents: read steps: - - name: Checkout + - name: πŸ“¦ Checkout uses: actions/checkout@v6 - - name: Setup Smurf + - name: βš™οΈ Setup Smurf uses: clouddrove/smurf@v1.1.5 - - name: Download Docker Image Artifact + - name: πŸ“₯ Download Docker Image Artifact uses: actions/download-artifact@v8 with: name: docker-image - - name: Load Docker Image + - name: πŸ“‚ Load Docker Image run: docker load -i ${{ inputs.docker_image_tar }} - - name: Install AWS CLI + # ── Cloud authentication ───────────────────────────────────────── + - name: 🟦 Install AWS CLI if: ${{ inputs.provider == 'aws' }} uses: aws-actions/configure-aws-credentials@v6 with: @@ -215,14 +237,14 @@ jobs: role-duration-seconds: 900 role-skip-session-tagging: true - - name: Assume another IAM Role + - name: πŸ”‘ Assume another IAM Role if: inputs.aws_assume_role == 'true' uses: aws-actions/configure-aws-credentials@v6 with: role-to-assume: ${{ inputs.aws_assume_role_arn }} aws-region: ${{ inputs.aws_region }} - - name: Authenticate Google Cloud with WIP and Service Account + - name: ☁️ Authenticate Google Cloud with WIP and Service Account if: inputs.gcp_auth_method == 'wip' uses: google-github-actions/auth@v3 with: @@ -232,40 +254,41 @@ jobs: access_token_lifetime: 300s project_id: ${{ inputs.gcp_project_id }} - - name: Authenticate Google Cloud with Service Account JSON Key + - name: ☁️ Authenticate Google Cloud with Service Account JSON Key if: inputs.gcp_auth_method == 'json' uses: google-github-actions/auth@v3 with: credentials_json: ${{ secrets.GOOGLE_CREDENTIALS }} - - name: Set Docker Hub environment variables + - name: πŸ‹ Set Docker Hub environment variables if: inputs.docker_registry == 'hub' run: | echo "DOCKER_USERNAME=${{ secrets.DOCKER_USERNAME }}" >> $GITHUB_ENV echo "DOCKER_PASSWORD=${{ secrets.DOCKER_PASSWORD }}" >> $GITHUB_ENV shell: bash - - name: Install Trivy + # ── Scan & push ────────────────────────────────────────────────── + - name: πŸ›‘οΈ Install Trivy run: | curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin trivy --version - - name: Docker Image Scan + - name: πŸ” Docker Image Scan run: | smurf sdkr scan ${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} - - name: Docker Image Tag + - name: 🏷️ Docker Image Tag if: inputs.docker_push == 'true' run: | smurf sdkr tag ${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} \ ${{ inputs.docker_registry_url }}/${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} - - name: Docker Image Push + - name: πŸš€ Docker Image Push if: inputs.docker_push == 'true' && inputs.gcp_docker_push != 'true' run: | smurf sdkr push ${{ inputs.docker_registry }} ${{ inputs.docker_registry_url }}/${{ inputs.docker_image_name }}:${{ inputs.docker_image_tag }} - - name: Docker Image Push on gcp + - name: πŸš€ Docker Image Push on GCP if: inputs.docker_push == 'true' && inputs.gcp_docker_push == 'true' run: | smurf sdkr push ${{ inputs.docker_registry }} \ diff --git a/.github/workflows/helm-smurf.yml b/.github/workflows/helm-smurf.yml index 3526bc45..7b516662 100644 --- a/.github/workflows/helm-smurf.yml +++ b/.github/workflows/helm-smurf.yml @@ -1,14 +1,29 @@ --- -name: Smurf Helm Shared Workflow +# Reusable Smurf SELM workflow β€” lint, template, deploy, and rollback Helm charts. +# Docs: docs/helm-smurf.md +name: ⎈ Smurf Helm Shared Workflow on: workflow_call: inputs: + # ── Cloud provider ─────────────────────────────────────────────── provider: description: Cloud provider (aws, gcp, azure) type: string required: false default: aws + target_environment: + description: GitHub Environment name (empty = no gate) + type: string + required: false + default: "" + smurf_version: + description: Smurf CLI version + type: string + required: false + default: v1.1.5 + + # ── AWS ────────────────────────────────────────────────────────── aws_region: description: AWS region type: string @@ -27,6 +42,8 @@ on: description: IAM role ARN to assume type: string required: false + + # ── GCP ────────────────────────────────────────────────────────── gcp_project_id: description: GCP project ID type: string @@ -40,16 +57,8 @@ on: description: GKE cluster name type: string required: false - smurf_version: - description: Smurf CLI version - type: string - required: false - default: v1.1.5 - target_environment: - description: GitHub Environment name (empty = no gate) - type: string - required: false - default: "" + + # ── Helm toggles ───────────────────────────────────────────────── helm_enable: description: Run lint + deploy jobs type: boolean @@ -60,6 +69,8 @@ on: type: boolean required: false default: false + + # ── Helm chart & release ───────────────────────────────────────── helm_release_name: description: Helm release name type: string @@ -91,6 +102,8 @@ on: type: string required: false default: "--atomic --wait --create-namespace" + + # ── Helm plugins & repos ───────────────────────────────────────── helm_plugin_install: description: Install Helm plugins before deploy type: boolean @@ -115,6 +128,7 @@ on: required: false secrets: + # ── AWS secrets ────────────────────────────────────────────────── AWS_ACCESS_KEY_ID: required: false description: AWS access key (keys auth) @@ -127,6 +141,8 @@ on: BUILD_ROLE: required: false description: AWS OIDC role ARN + + # ── GCP secrets ────────────────────────────────────────────────── GCP_CREDENTIALS: required: false description: GCP service account JSON key @@ -136,12 +152,15 @@ on: SERVICE_ACCOUNT: required: false description: GCP service account email (WIP auth) - GCP_PROJECT_ID: + GCP_PROJECT_ID: description: 'GCP Project ID' required: false + + # ── Azure secrets ──────────────────────────────────────────────── AZURE_CREDENTIALS: required: false description: Azure service principal JSON + helm_extra_args: required: false description: Extra helm CLI args (e.g. --set key=val) @@ -151,30 +170,36 @@ permissions: contents: read jobs: + ############################################### + # LINT β†’ TEMPLATE + ############################################### helm-lint: name: Helm Lint & Template if: ${{ inputs.helm_enable }} runs-on: ubuntu-latest steps: - - name: Checkout + - name: πŸ“¦ Checkout uses: actions/checkout@v6 - - name: Setup Smurf + - name: βš™οΈ Setup Smurf uses: clouddrove/smurf@v1.1.5 with: version: ${{ inputs.smurf_version }} - - name: Helm Lint + - name: βœ… Helm Lint run: | smurf selm lint "${{ inputs.helm_chart_directory }}" \ -f "${{ inputs.helm_values_file_path }}" - - name: Helm Template + - name: πŸ“„ Helm Template run: | smurf selm template "${{ inputs.helm_release_name }}" \ "${{ inputs.helm_chart_directory }}" \ -f "${{ inputs.helm_values_file_path }}" + ############################################### + # AUTH β†’ KUBECONFIG β†’ DEPLOY + ############################################### helm-deploy: name: Helm Deploy if: ${{ inputs.helm_enable }} @@ -182,15 +207,16 @@ jobs: runs-on: ubuntu-latest environment: ${{ inputs.target_environment }} steps: - - name: Checkout + - name: πŸ“¦ Checkout uses: actions/checkout@v6 - - name: Setup Smurf + - name: βš™οΈ Setup Smurf uses: clouddrove/smurf@v1.1.5 with: version: ${{ inputs.smurf_version }} - - name: Configure AWS credentials + # ── Cloud authentication ───────────────────────────────────────── + - name: 🟦 Configure AWS credentials if: ${{ inputs.provider == 'aws' }} uses: aws-actions/configure-aws-credentials@v6 with: @@ -202,14 +228,14 @@ jobs: role-duration-seconds: 900 role-skip-session-tagging: true - - name: Assume another IAM role + - name: πŸ”‘ Assume another IAM role if: ${{ inputs.provider == 'aws' && inputs.aws_assume_role }} uses: aws-actions/configure-aws-credentials@v6 with: role-to-assume: ${{ inputs.aws_assume_role_arn }} aws-region: ${{ inputs.aws_region }} - - name: Authenticate to Google Cloud + - name: ☁️ Authenticate to Google Cloud if: ${{ inputs.provider == 'gcp' }} uses: google-github-actions/auth@v3 with: @@ -218,14 +244,14 @@ jobs: service_account: ${{ secrets.SERVICE_ACCOUNT }} project_id: ${{ inputs.gcp_project_id }} - - name: Set up gcloud SDK + - name: πŸ› οΈ Set up gcloud SDK if: ${{ inputs.provider == 'gcp' }} uses: google-github-actions/setup-gcloud@v2 with: project_id: ${{ inputs.gcp_project_id }} install_components: gke-gcloud-auth-plugin - - name: Update kubeconfig (GKE) + - name: πŸ”§ Update kubeconfig (GKE) if: ${{ inputs.provider == 'gcp' }} run: | gcloud container clusters get-credentials \ @@ -233,40 +259,41 @@ jobs: --region "${{ inputs.gcp_region }}" \ --project "${{ inputs.gcp_project_id }}" - - name: Login to Azure + - name: πŸ”΅ Login to Azure if: ${{ inputs.provider == 'azure' }} uses: azure/login@v3 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - - name: Update kubeconfig (EKS) + - name: πŸ”§ Update kubeconfig (EKS) if: ${{ inputs.provider == 'aws' }} run: | aws eks update-kubeconfig \ --name "${{ inputs.aws_eks_cluster_name }}" \ --region "${{ inputs.aws_region }}" - - name: Update kubeconfig (GKE) + - name: πŸ”§ Update kubeconfig (GKE) if: ${{ inputs.provider == 'gcp' }} run: | gcloud container clusters get-credentials "${{ inputs.gcp_gke_cluster_name }}" \ --region "${{ inputs.gcp_region }}" \ --project "${{ inputs.gcp_project_id }}" - - name: Helm Plugin + # ── Helm plugins & repos ───────────────────────────────────────── + - name: πŸ”Œ Helm Plugin if: ${{ inputs.helm_plugin_install }} run: smurf selm plugin ${{ inputs.helm_plugins }} - - name: Add Helm Chart Repo + - name: πŸ“š Add Helm Chart Repo if: ${{ inputs.helm_repo_add }} run: | smurf selm repo add "${{ inputs.helm_repository }}" "${{ inputs.helm_repository_url }}" - - name: Update Helm Chart Repos + - name: πŸ”„ Update Helm Chart Repos if: ${{ inputs.helm_repo_add }} run: smurf selm repo update - - name: Helm Deploy + - name: πŸš€ Helm Deploy run: | smurf selm upgrade --install \ "${{ inputs.helm_release_name }}" \ @@ -277,21 +304,25 @@ jobs: ${{ inputs.helm_flags }} \ ${{ secrets.helm_extra_args }} + ############################################### + # AUTH β†’ KUBECONFIG β†’ ROLLBACK + ############################################### helm-rollback: name: Helm Rollback if: ${{ inputs.helm_rollback_enable }} runs-on: ubuntu-latest environment: ${{ inputs.target_environment }} steps: - - name: Checkout + - name: πŸ“¦ Checkout uses: actions/checkout@v6 - - name: Setup Smurf + - name: βš™οΈ Setup Smurf uses: clouddrove/smurf@v1.1.5 with: version: ${{ inputs.smurf_version }} - - name: Configure AWS credentials + # ── Cloud authentication ───────────────────────────────────────── + - name: 🟦 Configure AWS credentials if: ${{ inputs.provider == 'aws' }} uses: aws-actions/configure-aws-credentials@v6 with: @@ -303,14 +334,14 @@ jobs: role-duration-seconds: 900 role-skip-session-tagging: true - - name: Assume another IAM role + - name: πŸ”‘ Assume another IAM role if: ${{ inputs.provider == 'aws' && inputs.aws_assume_role }} uses: aws-actions/configure-aws-credentials@v6 with: role-to-assume: ${{ inputs.aws_assume_role_arn }} aws-region: ${{ inputs.aws_region }} - - name: Authenticate to Google Cloud + - name: ☁️ Authenticate to Google Cloud if: ${{ inputs.provider == 'gcp' }} uses: google-github-actions/auth@v3 with: @@ -319,14 +350,14 @@ jobs: service_account: ${{ secrets.SERVICE_ACCOUNT }} project_id: ${{ inputs.gcp_project_id }} - - name: Set up gcloud SDK + - name: πŸ› οΈ Set up gcloud SDK if: ${{ inputs.provider == 'gcp' }} uses: google-github-actions/setup-gcloud@v2 with: project_id: ${{ inputs.gcp_project_id }} install_components: gke-gcloud-auth-plugin - - name: Update kubeconfig (GKE) + - name: πŸ”§ Update kubeconfig (GKE) if: ${{ inputs.provider == 'gcp' }} run: | gcloud container clusters get-credentials \ @@ -334,28 +365,28 @@ jobs: --region "${{ inputs.gcp_region }}" \ --project "${{ inputs.gcp_project_id }}" - - name: Login to Azure + - name: πŸ”΅ Login to Azure if: ${{ inputs.provider == 'azure' }} uses: azure/login@v3 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - - name: Update kubeconfig (EKS) + - name: πŸ”§ Update kubeconfig (EKS) if: ${{ inputs.provider == 'aws' }} run: | aws eks update-kubeconfig \ --name "${{ inputs.aws_eks_cluster_name }}" \ --region "${{ inputs.aws_region }}" - - name: Update kubeconfig (GKE) + - name: πŸ”§ Update kubeconfig (GKE) if: ${{ inputs.provider == 'gcp' }} run: | gcloud container clusters get-credentials "${{ inputs.gcp_gke_cluster_name }}" \ --region "${{ inputs.gcp_region }}" \ --project "${{ inputs.gcp_project_id }}" - - name: Helm Rollback + - name: βͺ Helm Rollback run: | smurf selm rollback "${{ inputs.helm_release_name }}" \ "${{ inputs.helm_revision }}" \ - -n "${{ inputs.helm_namespace }}" \ No newline at end of file + -n "${{ inputs.helm_namespace }}" diff --git a/.github/workflows/tf-smurf.yml b/.github/workflows/tf-smurf.yml index f32fcc90..05e9262e 100644 --- a/.github/workflows/tf-smurf.yml +++ b/.github/workflows/tf-smurf.yml @@ -1,8 +1,12 @@ --- +# Reusable Smurf STF workflow β€” format, plan, apply, and destroy Terraform infrastructure. +# Docs: docs/tf-smurf.md name: πŸ¦Έβ€β™‚οΈ Smurf Terraform Shared workflow + on: workflow_call: inputs: + # ── Terraform core ─────────────────────────────────────────────── terraform_directory: required: true type: string @@ -24,6 +28,8 @@ on: required: false type: string description: 'Terraform var file path relative to terraform_directory. e.g. vars/dev.tfvars' + + # ── Job toggles ────────────────────────────────────────────────── run_create: required: false type: boolean @@ -38,6 +44,8 @@ on: required: false type: string description: 'Approvals list to approve apply or destroy' + + # ── Tool versions & approval ───────────────────────────────────── smurf_version: type: string default: v1.1.5 @@ -70,6 +78,8 @@ on: required: false type: string description: 'ID of the default project to use for future API calls and invocations.' + + # ── GCP & SSH ──────────────────────────────────────────────────── create_credentials_file: required: false type: string @@ -85,6 +95,8 @@ on: required: false type: string default: "" + + # ── Plan options ───────────────────────────────────────────────── plan_only: description: "Set this to `true` to run `smurf stf plan` only" required: false @@ -101,6 +113,7 @@ on: type: boolean default: false secrets: + # ── Cloud credentials ──────────────────────────────────────────── AZURE_CREDENTIALS: required: false description: 'Azure Credentials to install Azure in github runner.' @@ -151,7 +164,8 @@ jobs: - name: πŸ“¦ Checkout Repository uses: actions/checkout@v6 - - uses: webfactory/ssh-agent@v0.10.0 + - name: πŸ”‘ Setup SSH Agent + uses: webfactory/ssh-agent@v0.10.0 if: ${{ inputs.git_ssh_key_setup }} with: ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} @@ -164,6 +178,7 @@ jobs: _EOT ) >> "$GITHUB_ENV" + # ── Cloud authentication ───────────────────────────────────────── - name: 🟦 Install AWS CLI if: ${{ inputs.provider == 'aws' }} uses: aws-actions/configure-aws-credentials@v6 @@ -209,6 +224,7 @@ jobs: with: token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + # ── Terraform & Smurf setup ────────────────────────────────────── - name: πŸ› οΈ Set up Terraform uses: hashicorp/setup-terraform@v4 with: @@ -220,6 +236,7 @@ jobs: with: version: ${{ inputs.smurf_version }} + # ── Format β†’ init β†’ validate β†’ plan β†’ apply ────────────────────── - name: 🧹 Smurf Terraform Format run: | smurf stf fmt --recursive --timeout 5s @@ -274,7 +291,8 @@ jobs: - name: πŸ“¦ Checkout Repository uses: actions/checkout@v6 - - uses: webfactory/ssh-agent@v0.10.0 + - name: πŸ”‘ Setup SSH Agent + uses: webfactory/ssh-agent@v0.10.0 if: ${{ inputs.git_ssh_key_setup }} with: ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} @@ -287,6 +305,7 @@ jobs: _EOT ) >> "$GITHUB_ENV" + # ── Cloud authentication ───────────────────────────────────────── - name: 🟦 Install AWS CLI if: ${{ inputs.provider == 'aws' }} uses: aws-actions/configure-aws-credentials@v6 @@ -332,6 +351,7 @@ jobs: with: token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + # ── Terraform & Smurf setup ────────────────────────────────────── - name: πŸ› οΈ Set up Terraform uses: hashicorp/setup-terraform@v4 with: @@ -343,6 +363,7 @@ jobs: with: version: ${{ inputs.smurf_version }} + # ── Init β†’ import β†’ approval β†’ destroy ─────────────────────────── - name: πŸ—οΈ Smurf Terraform Init run: | smurf stf init --dir=${{ inputs.terraform_directory }} From c7a2ea3e3a72b5aad2819517f03ee313e97c897a Mon Sep 17 00:00:00 2001 From: Anket Satbhai Date: Fri, 10 Jul 2026 22:08:33 +0530 Subject: [PATCH 3/3] feat: remove unused inputs and update docs --- .github/workflows/docker-smurf.yml | 21 --------------------- .github/workflows/tf-smurf.yml | 4 ---- docs/docker-smurf.md | 1 - docs/tf-smurf.md | 2 -- 4 files changed, 28 deletions(-) diff --git a/.github/workflows/docker-smurf.yml b/.github/workflows/docker-smurf.yml index b965646a..a3d51718 100644 --- a/.github/workflows/docker-smurf.yml +++ b/.github/workflows/docker-smurf.yml @@ -62,18 +62,6 @@ on: default: 'false' # ── AWS ────────────────────────────────────────────────────────── - aws_auth_method: - description: AWS auth method to use like oidc and keys - type: string - required: false - aws_eks_cluster_name: - description: AWS eks cluster name - type: string - required: false - aws_role: - description: AWS OIDC role for aws authentication. - type: string - default: 'false' aws_region: required: false type: string @@ -103,15 +91,6 @@ on: type: string required: false default: 'false' - gcp_region: - required: false - type: string - description: GCP Region - default: 'us-central1' - gcp_gke_cluster_name: - description: GCP gke cluster name - type: string - required: false secrets: # ── AWS secrets ────────────────────────────────────────────────── diff --git a/.github/workflows/tf-smurf.yml b/.github/workflows/tf-smurf.yml index 05e9262e..cfd1bdb1 100644 --- a/.github/workflows/tf-smurf.yml +++ b/.github/workflows/tf-smurf.yml @@ -20,10 +20,6 @@ on: type: string default: us-east-2 description: 'AWS region of terraform deployment.' - gcp_region: - required: false - type: string - description: 'GCP region of terraform deployment.' var_file: required: false type: string diff --git a/docs/docker-smurf.md b/docs/docker-smurf.md index 3817d2e8..fde0aa7e 100644 --- a/docs/docker-smurf.md +++ b/docs/docker-smurf.md @@ -73,7 +73,6 @@ The full pushed image is assembled in the shared workflow: | `aws_assume_role_arn` | string | β€” | Secondary IAM role ARN | | `gcp_auth_method` | string | β€” | `wip` or `json` for GCP auth | | `gcp_project_id` | string | β€” | GCP project ID | -| `gcp_region` | string | `us-central1` | GCP region | | `gcp_docker_push` | string | `false` | Set to `'true'` to push with `--project-id` (GCP) | > **Note:** `docker_enable`, `docker_push`, and other toggles use the string `'true'` / `'false'`, not YAML booleans. diff --git a/docs/tf-smurf.md b/docs/tf-smurf.md index b36559a1..c7e7757c 100644 --- a/docs/tf-smurf.md +++ b/docs/tf-smurf.md @@ -63,7 +63,6 @@ When both flags are set in one run, destroy runs after create completes successf | `terraform_version` | string | `1.3.6` | Terraform CLI version | | `smurf_version` | string | `v1.1.5` | Smurf CLI version | | `aws_region` | string | `us-east-2` | AWS region | -| `gcp_region` | string | β€” | GCP region | | `project_id` | string | β€” | GCP project ID | | `git_ssh_key_setup` | boolean | `false` | Enable SSH agent for private module clones | | `create_credentials_file` | string | `true` | GCP credentials file generation | @@ -215,7 +214,6 @@ jobs: run_create: true run_destroy: false project_id: my-gcp-project - gcp_region: us-central1 var_file: vars/prod.tfvars approvers: your-github-username secrets: