diff --git a/.github/workflows/docker-smurf.yml b/.github/workflows/smurf-docker.yml similarity index 97% rename from .github/workflows/docker-smurf.yml rename to .github/workflows/smurf-docker.yml index a7e8b2f9..c428950e 100644 --- a/.github/workflows/docker-smurf.yml +++ b/.github/workflows/smurf-docker.yml @@ -1,6 +1,4 @@ --- -# Reusable Smurf SDKR workflow β€” build, scan, and push Docker images. -# Docs: docs/docker-smurf.md name: 🐳 Smurf-Docker on: @@ -148,7 +146,7 @@ jobs: uses: actions/checkout@v7 - name: βš™οΈ Setup Smurf - uses: clouddrove/smurf@v1.1.5 + uses: clouddrove/smurf@v1.1.6 - name: 🐳 Docker Image Build if: inputs.docker_buildkit_enable != 'true' @@ -193,7 +191,7 @@ jobs: uses: actions/checkout@v7 - name: βš™οΈ Setup Smurf - uses: clouddrove/smurf@v1.1.5 + uses: clouddrove/smurf@v1.1.6 - name: πŸ“₯ Download Docker Image Artifact uses: actions/download-artifact@v8 @@ -272,4 +270,4 @@ jobs: 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 }} + --project-id ${{ inputs.gcp_project_id }} \ No newline at end of file diff --git a/.github/workflows/helm-smurf.yml b/.github/workflows/smurf-helm-deploy.yml similarity index 98% rename from .github/workflows/helm-smurf.yml rename to .github/workflows/smurf-helm-deploy.yml index 56f23f9b..d7b5d1f4 100644 --- a/.github/workflows/helm-smurf.yml +++ b/.github/workflows/smurf-helm-deploy.yml @@ -1,6 +1,4 @@ --- -# Reusable Smurf SELM workflow β€” lint, template, deploy, and rollback Helm charts. -# Docs: docs/helm-smurf.md name: ⎈ Smurf Helm Shared Workflow on: @@ -182,7 +180,7 @@ jobs: uses: actions/checkout@v7 - name: βš™οΈ Setup Smurf - uses: clouddrove/smurf@v1.1.5 + uses: clouddrove/smurf@v1.1.6 with: version: ${{ inputs.smurf_version }} @@ -211,7 +209,7 @@ jobs: uses: actions/checkout@v7 - name: βš™οΈ Setup Smurf - uses: clouddrove/smurf@v1.1.5 + uses: clouddrove/smurf@v1.1.6 with: version: ${{ inputs.smurf_version }} @@ -317,7 +315,7 @@ jobs: uses: actions/checkout@v7 - name: βš™οΈ Setup Smurf - uses: clouddrove/smurf@v1.1.5 + uses: clouddrove/smurf@v1.1.6 with: version: ${{ inputs.smurf_version }} @@ -389,4 +387,4 @@ jobs: run: | smurf selm rollback "${{ inputs.helm_release_name }}" \ "${{ inputs.helm_revision }}" \ - -n "${{ inputs.helm_namespace }}" + -n "${{ inputs.helm_namespace }}" \ No newline at end of file diff --git a/.github/workflows/stf-checks.yml b/.github/workflows/smurf-tf-checks.yml similarity index 99% rename from .github/workflows/stf-checks.yml rename to .github/workflows/smurf-tf-checks.yml index 8b5e7d28..ef9f6841 100644 --- a/.github/workflows/stf-checks.yml +++ b/.github/workflows/smurf-tf-checks.yml @@ -189,4 +189,4 @@ jobs: # - Running command to check terraform formatting changes. - name: 🧹 Check Terraform format changes run: smurf stf fmt --recursive --timeout 5s -... +... \ No newline at end of file diff --git a/.github/workflows/smurf-tf-drift.yml b/.github/workflows/smurf-tf-drift.yml new file mode 100644 index 00000000..c669f2b5 --- /dev/null +++ b/.github/workflows/smurf-tf-drift.yml @@ -0,0 +1,301 @@ +--- +name: 'πŸ“‘ Smurf STF Terraform Drift Detection' + +on: + workflow_call: + inputs: + terraform_directory: + required: true + type: string + description: 'Root directory of the Terraform configuration.' + provider: + required: true + type: string + description: 'Cloud provider: aws or gcp' + aws_region: + required: false + type: string + default: us-east-1 + description: 'AWS region for Terraform deployment.' + var_file: + required: false + type: string + default: '' + description: 'Terraform var file path relative to terraform_directory. e.g. vars/dev.tfvars' + terraform_version: + type: string + default: '1.5.7' + description: 'Terraform CLI version (used for terraform show on plan file).' + smurf_version: + type: string + default: v1.1.6 + description: 'Smurf CLI version' + plan_out: + type: string + default: tfplan + description: 'Plan filename written inside terraform_directory.' + create_issue: + type: boolean + default: true + description: 'Open/update a GitHub issue when drift is detected.' + close_issue_on_clean: + type: boolean + default: true + description: 'Close open drift issues when no drift is detected.' + drift_issue_title: + type: string + default: 'Terraform Configuration Drift Detected' + description: 'Title for the drift GitHub issue.' + token_format: + required: false + type: string + default: access_token + access_token_lifetime: + required: false + type: string + default: 300s + project_id: + required: false + type: string + default: '' + create_credentials_file: + required: false + type: string + default: 'true' + backend_config: + required: false + type: string + default: '' + description: 'Backend config file path relative to terraform_directory. e.g. vars/backend.hcl' + secrets: + AWS_ACCESS_KEY_ID: + required: false + AWS_SECRET_ACCESS_KEY: + required: false + AWS_SESSION_TOKEN: + required: false + BUILD_ROLE: + required: false + GCP_CREDENTIALS: + required: false + WORKLOAD_IDENTITY_PROVIDER: + required: false + SERVICE_ACCOUNT: + required: false + env-vars: + required: false + +jobs: + smurf-stf-drift: + name: 'Smurf STF Drift Check' + runs-on: ubuntu-latest + permissions: + contents: read + issues: write + outputs: + tfplanExitCode: ${{ steps.tf-plan.outputs.exitcode }} + + steps: + - name: πŸ“¦ Checkout Repository + uses: actions/checkout@v4 + + - name: 🌱 Set environment variables + env: + ENV_VARS: ${{ secrets.env-vars }} + run: | + if [ -n "$ENV_VARS" ]; then + ( + cat <<'_EOT' + $ENV_VARS + _EOT + ) >> "$GITHUB_ENV" + fi + + - name: 🟦 Configure AWS credentials + if: ${{ inputs.provider == 'aws' }} + uses: aws-actions/configure-aws-credentials@v4 + 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: ☁️ Authenticate to Google Cloud + if: ${{ inputs.provider == 'gcp' }} + uses: google-github-actions/auth@v2 + 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: πŸ› οΈ Set up Terraform + uses: hashicorp/setup-terraform@v3 + with: + terraform_version: ${{ inputs.terraform_version }} + terraform_wrapper: false + + - name: βš™οΈ Set up Smurf + uses: clouddrove/smurf@v1.1.6 + with: + version: ${{ inputs.smurf_version }} + + - name: πŸ—οΈ Smurf Terraform Init + run: | + INIT_ARGS=(--dir=${{ inputs.terraform_directory }}) + if [ -n "${{ inputs.backend_config }}" ]; then + INIT_ARGS+=(--backend-config=${{ inputs.terraform_directory }}/${{ inputs.backend_config }}) + fi + smurf stf init "${INIT_ARGS[@]}" + + - name: πŸ”Ž Smurf Terraform Validate + run: smurf stf validate --dir=${{ inputs.terraform_directory }} + + - name: πŸ“ Smurf Terraform Plan (drift check) + id: tf-plan + working-directory: ${{ inputs.terraform_directory }} + run: | + set +e + PLAN_ARGS="--out=${{ inputs.plan_out }}" + if [ -n "${{ inputs.var_file }}" ]; then + PLAN_ARGS="$PLAN_ARGS --var-file=${{ inputs.var_file }}" + fi + smurf stf plan $PLAN_ARGS + PLAN_EXIT=$? + set -e + + if [ "$PLAN_EXIT" -ne 0 ]; then + echo "exitcode=1" >> "$GITHUB_OUTPUT" + echo "Smurf plan failed with exit code $PLAN_EXIT" + exit 1 + fi + + # Smurf removes an empty plan file when there are no changes. + if [ -f "${{ inputs.plan_out }}" ] && [ -s "${{ inputs.plan_out }}" ]; then + PLAN_JSON=$(terraform show -json "${{ inputs.plan_out }}") + ONLY_CREATE=$(echo "$PLAN_JSON" | jq -r 'if (.resource_changes | length) == 0 then false else ([.resource_changes[].change.actions[]] | all(. == "create")) end') + + if [ "$ONLY_CREATE" = "true" ]; then + echo "exitcode=3" >> "$GITHUB_OUTPUT" + echo "Bootstrap required β€” plan only contains create actions (no remote state or first run)." + else + echo "exitcode=2" >> "$GITHUB_OUTPUT" + echo "Drift detected β€” plan file exists and contains update/replace/destroy changes." + fi + else + echo "exitcode=0" >> "$GITHUB_OUTPUT" + echo "No drift detected." + fi + + - name: πŸ’Ύ Upload plan artifact + if: steps.tf-plan.outputs.exitcode == '2' || steps.tf-plan.outputs.exitcode == '3' + uses: actions/upload-artifact@v4 + with: + name: smurf-tfplan-${{ github.run_id }} + path: ${{ inputs.terraform_directory }}/${{ inputs.plan_out }} + if-no-files-found: ignore + + - name: 🧡 Build plan summary + id: tf-plan-string + if: steps.tf-plan.outputs.exitcode == '2' || steps.tf-plan.outputs.exitcode == '3' + working-directory: ${{ inputs.terraform_directory }} + run: | + TERRAFORM_PLAN=$(terraform show -no-color "${{ inputs.plan_out }}") + delimiter="$(openssl rand -hex 8)" + TITLE="## Terraform Drift Detected (Smurf STF)" + if [ "${{ steps.tf-plan.outputs.exitcode }}" = "3" ]; then + TITLE="## Bootstrap Required (Smurf STF)" + fi + { + echo "summary<<${delimiter}" + echo "$TITLE" + echo "" + echo "### Working Directory: \`${{ inputs.terraform_directory }}\`" + echo "### Provider: \`${{ inputs.provider }}\`" + echo "" + echo "
Click to expand plan output" + echo "" + echo '```terraform' + echo "$TERRAFORM_PLAN" + echo '```' + echo "
" + echo "${delimiter}" + } >> "$GITHUB_OUTPUT" + + - name: πŸ“ Publish plan to job summary + if: steps.tf-plan.outputs.exitcode == '2' || steps.tf-plan.outputs.exitcode == '3' + env: + SUMMARY: ${{ steps.tf-plan-string.outputs.summary }} + run: echo "$SUMMARY" >> "$GITHUB_STEP_SUMMARY" + + - name: 🚨 Create or update drift issue + if: inputs.create_issue && steps.tf-plan.outputs.exitcode == '2' + uses: actions/github-script@v7 + env: + SUMMARY: ${{ steps.tf-plan-string.outputs.summary }} + ISSUE_TITLE: ${{ inputs.drift_issue_title }} + with: + github-token: ${{ github.token }} + script: | + const body = `${process.env.SUMMARY}`; + const title = process.env.ISSUE_TITLE; + const creator = 'github-actions[bot]'; + + const issues = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + creator, + title, + }); + + if (issues.data.length > 0) { + const issue = issues.data[0]; + if (issue.body !== body) { + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body, + }); + } + } else { + await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title, + body, + }); + } + + - name: βœ… Close drift issue when clean + if: inputs.close_issue_on_clean && steps.tf-plan.outputs.exitcode == '0' + uses: actions/github-script@v7 + env: + ISSUE_TITLE: ${{ inputs.drift_issue_title }} + with: + github-token: ${{ github.token }} + script: | + const title = process.env.ISSUE_TITLE; + const creator = 'github-actions[bot]'; + const issues = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + creator, + title, + }); + if (issues.data.length > 0) { + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issues.data[0].number, + state: 'closed', + }); + } \ No newline at end of file diff --git a/.github/workflows/tf-smurf.yml b/.github/workflows/smurf-tf-workflow.yml similarity index 99% rename from .github/workflows/tf-smurf.yml rename to .github/workflows/smurf-tf-workflow.yml index 26c85c22..195dd0e5 100644 --- a/.github/workflows/tf-smurf.yml +++ b/.github/workflows/smurf-tf-workflow.yml @@ -107,7 +107,6 @@ on: default: false description: Run only Terraform plan without applying changes. - secrets: AZURE_CREDENTIALS: @@ -251,17 +250,11 @@ jobs: run: | if [ -n "${{ inputs.var_file }}" ]; then echo "Using tfvars: ${{ inputs.var_file }}" - cd "${{ inputs.terraform_directory }}" - - pwd - ls -la - smurf stf plan \ --var-file="${{ inputs.var_file }}" else echo "No tfvars provided" - smurf stf plan \ --dir="${{ inputs.terraform_directory }}" fi @@ -372,18 +365,12 @@ jobs: run: | if [ -n "${{ inputs.var_file }}" ]; then echo "Using tfvars: ${{ inputs.var_file }}" - cd "${{ inputs.terraform_directory }}" - - pwd - ls -la - smurf stf destroy \ --auto-approve \ --var-file="${{ inputs.var_file }}" else echo "No tfvars provided" - smurf stf destroy \ --auto-approve \ --dir="${{ inputs.terraform_directory }}" @@ -399,18 +386,12 @@ jobs: run: | if [ -n "${{ inputs.var_file }}" ]; then echo "Using tfvars: ${{ inputs.var_file }}" - cd "${{ inputs.terraform_directory }}" - - pwd - ls -la - smurf stf apply \ --auto-approve \ --var-file="${{ inputs.var_file }}" else echo "No tfvars provided" - smurf stf apply \ --auto-approve \ --dir="${{ inputs.terraform_directory }}" diff --git a/CHANGELOG.md b/CHANGELOG.md index 500a573f..47dddb1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -79,7 +79,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `terraform-lint.yml` β†’ `tf-lint.yml` - `terraform-monorepo-tag-release.yml` β†’ `tf-monorepo-tag-release.yml` - `terraform-pr-checks.yml` β†’ `tf-pr-checks.yml` - - `terraform-smurf.yml` β†’ `tf-smurf.yml` + - `terraform-smurf.yml` β†’ `smurf-tf-woorkflow.yml` - `terraform-workflow.yml` β†’ `tf-workflow.yml` - **CloudFormation workflows:** All `cloudformation-*` workflows renamed to `cf-*` diff --git a/README.md b/README.md index 42da3f01..a9a9b6bc 100644 --- a/README.md +++ b/README.md @@ -120,16 +120,18 @@ Above example is just a simple example to call workflow from github shared workf 23. [Powerpipe workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/23.powerpipe.md) 24. [Prowler workflow AWS](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/24.prowlerAWS.md) 25. [Prowler workflow GCP](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/25.prowlerGCP.md) -26. [Smurf-Docker-Helm Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/26.smurf-docker-helm.md) -27. [Smurf Terraform Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/27.smurf-terraform.md) -28. [Terraform Module Tag Release Workflow (Shared)](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/28.terraform-module-tag-release.md) --> +26. [Terraform Module Tag Release Workflow (Shared)](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/28.terraform-module-tag-release.md) +27. [Smurf-Docker Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/26.smurf-docker.md) +28. [Smurf Terraform Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/27.smurf-tf-workflow.md) +28. [Smurf Terraform Drift Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/28.smurf-tf-drift.md) +29. [Smurf helm deploy workflows](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/28.smurf-helm-deploy.md) --> ## πŸ“Š Workflow Statistics | Category | Count | Workflows | |----------|-------|-----------| -| **Terraform** | 9 | Checks, Lint, Workflow, Drift, PR Checks, Smurf, Monorepo Tag Release, STF Checks | -| **Docker** | 4 | Build Push, Scanner, Scout, Smurf Helm | +| **Terraform** | 9 | Checks, Lint, Workflow, Drift, PR Checks, Monorepo Tag Release, STF Checks | +| **Docker** | 4 | Build Push, Scanner, Scout | | **PR Automation** | 7 | Auto Assignee, Auto Merge, Checks, Claude Review, Gemini Review, Gitleaks, Lock, Stale | | **Security** | 5 | Checkov, Prowler, Powerpipe, TFSec | | **AWS** | 3 | Prowler, SSM Send Command, Remote SSH Command | @@ -138,9 +140,10 @@ Above example is just a simple example to call workflow from github shared workf | **GCP** | 1 | Prowler | | **Helm** | 1 | Deploy | | **Notification** | 1 | Slack | +| **Smurf** | 4 | docker, helm, terraform | | **Other** | 3 | Infracost, README Generation, SST | -**Total: 41 Production-Ready Workflows** +**Total: 42 Production-Ready Workflows** ## πŸš€ Table of Contents @@ -158,7 +161,7 @@ Above example is just a simple example to call workflow from github shared workf * [Example for scan and push docker image on Dockerhub](./docs/docker-build-push.md#example-for-scan-and-push-docker-image-on-dockerhub) * [Example for scan and push docker image on ECR](./docs/docker-build-push.md#example-for-scan-and-push-docker-image-on-ecr) - [Docker Scout Workflow](./docs/docker-scout.md) -- [Docker Smurf Helm Workflow](./docs/docker-smurf.md) + ### GCP Workflows - [GCP Prowler Workflow](./docs/gcp-prowler.md) @@ -193,14 +196,20 @@ Above example is just a simple example to call workflow from github shared workf * [Example for terraform checks with azure cloud](./docs/tf-checks.md#example-for-terraform-checks-with-azure-cloud) * [Example for terraform checks with aws cloud](./docs/tf-checks.md#example-for-terraform-checks-with-aws-cloud) * [Example for terraform checks with digitalocean cloud](./docs/tf-checks.md#example-for-terraform-checks-with-digitalocean-cloud) -- [Terraform Smurf Checks](./docs/stf-checks.md) - [Terraform Drift Workflow](./docs/tf-drift.md) - [Terraform Lint Workflow](./docs/tf-lint.md) - [Terraform Monorepo Tag Release Workflow](./docs/tf-monorepo-tag-release.md) - [Terraform Plan Difference Checks Workflow](./docs/tf-diff-checks.md) -- [Terraform Smurf Workflow](./docs/tf-smurf.md) - [Terraform Workflow](./docs/tf-workflow.md) +### Smurf Workflows +- [Docker Smurf Workflow](./docs/smurf-docker.md) +- [Docker helm Workflow](./docs/smurf-helm-deploy.md) +- [Terraform Smurf Workflow](./docs/smurf-tf-workflow.md) +- [Terraform Smurf Checks](./docs/smurf-tf-checks.md) +- [Terraform Smurf drift](./docs/smurf-tf-drift.md) + + ### Other Workflows - [CI/CD Pipeline Workflow](./docs/ci.md) - [Infracost Workflow](./docs/infracost.md) @@ -281,7 +290,7 @@ Please review our [Security Policy](./.github/SECURITY.md) before reporting secu ☁️ Infrastructure as Code - Deploy with confidence - [Terraform Workflow](./docs/tf-workflow.md) - Full Terraform lifecycle management -- [Terraform Smurf Checks](./docs/stf-checks.md) - Validation and testing +- [Smurf Terraform Checks](./docs/smurf-tf-checks.md) - Validation and testing - [CloudFormation Deploy](./docs/cf-deploy.md) - AWS CloudFormation deployment diff --git a/WORKFLOW_CATALOG.md b/WORKFLOW_CATALOG.md index 012e0bdb..fb1bcdab 100644 --- a/WORKFLOW_CATALOG.md +++ b/WORKFLOW_CATALOG.md @@ -29,7 +29,7 @@ Complete index of all available workflows organized by category and use case. | [tf-lint.yml](./.github/workflows/tf-lint.yml) | Lint Terraform code | Code quality checks | | [tf-drift.yml](./.github/workflows/tf-drift.yml) | Detect infrastructure drift | Compliance checking | | [tf-pr-checks.yml](./.github/workflows/tf-pr-checks.yml) | PR plan comparison | Change review | -| [tf-smurf.yml](./.github/workflows/tf-smurf.yml) | Smurf-based Terraform operations | Advanced workflows | +| [smurf-tf-workflow.yml](./.github/workflows/smurf-tf-workflow.yml) | Smurf-based Terraform operations | Advanced workflows | | [tf-monorepo-tag-release.yml](./.github/workflows/tf-monorepo-tag-release.yml) | Auto-tag modules in monorepo | Module versioning | #### CloudFormation Workflows diff --git a/docs/docker-smurf.md b/docs/smurf-docker.md similarity index 93% rename from docs/docker-smurf.md rename to docs/smurf-docker.md index fde0aa7e..705499e0 100644 --- a/docs/docker-smurf.md +++ b/docs/smurf-docker.md @@ -1,8 +1,8 @@ -## [Smurf Docker 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/smurf-docker.yml) Reusable workflow for building, scanning, and pushing Docker images with [Smurf SDKR](https://github.com/clouddrove/smurf) (`smurf sdkr`). -**Shared workflow:** `.github/workflows/docker-smurf.yml` +**Shared workflow:** `.github/workflows/smurf-docker.yml` **Caller workflow:** lives in your application repo under `.github/workflows/` and calls the shared workflow via `workflow_call`. ### Architecture @@ -11,7 +11,7 @@ Reusable workflow for building, scanning, and pushing Docker images with [Smurf Your repo (caller) github-shared-workflows (shared) ───────────────── ───────────────────────────────── .github/workflows/ - docker-caller.yml ──uses──► .github/workflows/docker-smurf.yml + docker-caller.yml ──uses──► .github/workflows/smurf-docker.yml β”‚ β”œβ”€β”€ job: docker_build β”‚ build β†’ save tar β†’ upload artifact @@ -118,7 +118,7 @@ permissions: jobs: docker-ecr: - uses: clouddrove/github-shared-workflows/.github/workflows/docker-smurf.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-docker.yml@v2 with: docker_enable: 'true' docker_push: 'true' @@ -150,7 +150,7 @@ permissions: jobs: docker-hub: - uses: clouddrove/github-shared-workflows/.github/workflows/docker-smurf.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-docker.yml@v2 with: docker_enable: 'true' docker_push: 'true' @@ -180,7 +180,7 @@ permissions: jobs: docker-gcp: - uses: clouddrove/github-shared-workflows/.github/workflows/docker-smurf.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-docker.yml@v2 with: docker_enable: 'true' docker_push: 'true' @@ -215,7 +215,7 @@ permissions: jobs: docker-azure: - uses: clouddrove/github-shared-workflows/.github/workflows/docker-smurf.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-docker.yml@v2 with: docker_enable: 'true' docker_push: 'true' @@ -240,7 +240,7 @@ jobs: ```yaml jobs: docker-build: - uses: clouddrove/github-shared-workflows/.github/workflows/docker-smurf.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-docker.yml@v2 with: docker_enable: 'true' docker_push: 'false' diff --git a/docs/helm-smurf.md b/docs/smurf-helm-deploy.md similarity index 92% rename from docs/helm-smurf.md rename to docs/smurf-helm-deploy.md index 64bed2af..a3cc4ae6 100644 --- a/docs/helm-smurf.md +++ b/docs/smurf-helm-deploy.md @@ -1,8 +1,8 @@ -## [Smurf 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/smurf-helm-deploy.yml) Reusable workflow for Helm chart lint, template, deploy, and rollback using [Smurf SELM](https://github.com/clouddrove/smurf) (`smurf selm`). -**Shared workflow:** `.github/workflows/helm-smurf.yml` +**Shared workflow:** `.github/workflows/smurf-helm-deploy.yml` **Caller workflow:** lives in your application repo and calls the shared workflow via `workflow_call`. ### Architecture @@ -11,7 +11,7 @@ Reusable workflow for Helm chart lint, template, deploy, and rollback using [Smu Your repo (caller) github-shared-workflows (shared) ───────────────── ───────────────────────────────── .github/workflows/ - helm-caller.yml ──uses──► .github/workflows/helm-smurf.yml + helm-caller.yml ──uses──► .github/workflows/smurf-helm-deploy.yml β”‚ β”œβ”€β”€ job: helm-lint (helm_enable) β”œβ”€β”€ job: helm-deploy (helm_enable, needs lint) @@ -106,7 +106,7 @@ permissions: jobs: helm-deploy: - uses: clouddrove/github-shared-workflows/.github/workflows/helm-smurf.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-helm-deploy.yml@v2 with: provider: aws helm_enable: true @@ -138,7 +138,7 @@ permissions: jobs: helm-deploy: - uses: clouddrove/github-shared-workflows/.github/workflows/helm-smurf.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-helm-deploy.yml@v2 with: provider: gcp helm_enable: true @@ -172,7 +172,7 @@ permissions: jobs: helm-deploy: - uses: clouddrove/github-shared-workflows/.github/workflows/helm-smurf.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-helm-deploy.yml@v2 with: provider: azure helm_enable: true @@ -217,7 +217,7 @@ permissions: jobs: helm-deploy: if: ${{ github.event.inputs.action == 'deploy' }} - uses: clouddrove/github-shared-workflows/.github/workflows/helm-smurf.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-helm-deploy.yml@v2 with: provider: aws helm_enable: true @@ -232,7 +232,7 @@ jobs: helm-rollback: if: ${{ github.event.inputs.action == 'rollback' }} - uses: clouddrove/github-shared-workflows/.github/workflows/helm-smurf.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-helm-deploy.yml@v2 with: provider: aws helm_rollback_enable: true @@ -252,7 +252,7 @@ jobs: ```yaml jobs: helm-deploy: - uses: clouddrove/github-shared-workflows/.github/workflows/helm-smurf.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-helm-deploy.yml@v2 with: provider: aws helm_enable: true diff --git a/docs/stf-checks.md b/docs/smurf-tf-checks.md similarity index 95% rename from docs/stf-checks.md rename to docs/smurf-tf-checks.md index 509985f4..62211d26 100644 --- a/docs/stf-checks.md +++ b/docs/smurf-tf-checks.md @@ -1,6 +1,6 @@ -## [Smurf Terraform Checks Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/.github/workflows/tf-checks.yml) +## [Smurf Terraform Checks Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/.github/workflows/smurf-tf-checks.yml) -This workflow automates smurf terraform checks including format, init, validate, and optionally plan and version compatibility testing. It utilizes the workflows defined in `.github/workflows/stf-checks.yml` +This workflow automates smurf terraform checks including format, init, validate, and optionally plan and version compatibility testing. It utilizes the workflows defined in `.github/workflows/smurf-tf-checks.yml` ### Features @@ -24,7 +24,7 @@ on: jobs: terraform-checks: - uses: clouddrove/github-shared-workflows/.github/workflows/stf-checks.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-tf-checks.yml@v2 with: working_directory: './examples/complete/' provider: 'azurerm' @@ -42,7 +42,7 @@ on: jobs: terraform-checks: - uses: clouddrove/github-shared-workflows/.github/workflows/stf-checks.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-tf-checks.yml@v2 with: working_directory: './examples/complete/' provider: 'aws' @@ -66,7 +66,7 @@ on: jobs: terraform-checks: - uses: clouddrove/github-shared-workflows/.github/workflows/stf-checks.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-tf-checks.yml@v2 with: working_directory: './examples/complete/' provider: 'aws' @@ -88,7 +88,7 @@ on: jobs: terraform-checks: - uses: clouddrove/github-shared-workflows/.github/workflows/stf-checks.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-tf-checks.yml@v2 with: working_directory: './examples/complete/' provider: 'azurerm' @@ -108,7 +108,7 @@ on: jobs: terraform-checks: - uses: clouddrove/github-shared-workflows/.github/workflows/stf-checks.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-tf-checks.yml@v2 with: working_directory: './examples/complete/' provider: 'aws' @@ -131,7 +131,7 @@ on: jobs: terraform-checks: - uses: clouddrove/github-shared-workflows/.github/workflows/stf-checks.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-tf-checks.yml@v2 with: working_directory: './examples/complete/' provider: 'digitalocean' @@ -150,7 +150,7 @@ on: jobs: terraform-checks: - uses: clouddrove/github-shared-workflows/.github/workflows/stf-checks.yml@v2 + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-tf-checks.yml@v2 with: working_directory: './examples/complete/' provider: 'gcp' diff --git a/docs/smurf-tf-drift.md b/docs/smurf-tf-drift.md new file mode 100644 index 00000000..2bf72ce4 --- /dev/null +++ b/docs/smurf-tf-drift.md @@ -0,0 +1,152 @@ +# smurf-workflows + +Reusable GitHub Actions workflows for [Smurf STF](https://github.com/clouddrove/smurf) Terraform drift detection. + +## Shared workflow + +| File | Description | +|------|-------------| +| [.github/workflows/smurf-tf-drift.yml](.github/workflows/smurf-tf-drift.yml) | Reusable drift detection workflow (`workflow_call`) | + +### What it does + +1. Authenticates to AWS or GCP +2. Runs `smurf stf init` β†’ `validate` β†’ `plan` +3. Detects drift when the plan file is non-empty +4. Uploads the plan artifact and publishes a job summary +5. Opens or updates a GitHub issue on drift; closes it when clean +6. Fails the job when drift is detected + +### Inputs + +| Input | Required | Default | Description | +|-------|----------|---------|-------------| +| `terraform_directory` | Yes | β€” | Terraform root directory | +| `provider` | Yes | β€” | `aws` or `gcp` | +| `var_file` | No | `""` | Var file path relative to `terraform_directory` | +| `backend_config` | No | `""` | Backend config path relative to `terraform_directory` | +| `aws_region` | No | `us-east-1` | AWS region | +| `terraform_version` | No | `1.5.7` | Terraform version | +| `smurf_version` | No | `v1.1.6` | Smurf CLI version | +| `plan_out` | No | `tfplan` | Plan output filename | +| `create_issue` | No | `true` | Open/update drift issue | +| `close_issue_on_clean` | No | `true` | Close drift issue when no drift | +| `drift_issue_title` | No | `Terraform Configuration Drift Detected` | Issue title | +| `project_id` | No | `""` | GCP project ID | + +### Secrets + +| Secret | Provider | Description | +|--------|----------|-------------| +| `AWS_ACCESS_KEY_ID` | AWS | Access key (static auth) | +| `AWS_SECRET_ACCESS_KEY` | AWS | Secret key (static auth) | +| `AWS_SESSION_TOKEN` | AWS | Session token (optional) | +| `BUILD_ROLE` | AWS | IAM role ARN (OIDC auth) | +| `GCP_CREDENTIALS` | GCP | Service account JSON | +| `WORKLOAD_IDENTITY_PROVIDER` | GCP | Workload Identity Provider | +| `SERVICE_ACCOUNT` | GCP | GCP service account email | +| `env-vars` | Any | Extra env vars appended to `GITHUB_ENV` | + +### Exit behavior + +| Result | Job outcome | +|--------|-------------| +| No plan changes | Pass | +| Update/replace/destroy in plan | Fail + drift issue | +| Create-only plan (no state yet) | Fail with bootstrap message | +| Init/validate/plan error | Fail | + +--- + +### AWS drift caller (sample) + +Calls the shared workflow from the same repository: + +```yaml +permissions: + contents: read + issues: write + id-token: write + +jobs: + drift-aws: + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-tf-drift.yml@v2 + with: + terraform_directory: shared + provider: aws + var_file: vars/shared.tfvars + backend_config: vars/backend.hcl + aws_region: us-east-1 + smurf_version: v1.1.6 + plan_out: drift.plan + secrets: + BUILD_ROLE: ${{ secrets.BUILD_ROLE }} + 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 }} +``` + +Triggers: `workflow_dispatch`, daily schedule, and PRs touching `shared/**` or drift workflows. + +### AWS bootstrap caller (sample) + +Standalone workflow β€” runs `smurf stf apply` once so remote state exists before drift checks: + +```yaml +jobs: + bootstrap-aws: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.BUILD_ROLE }} + aws-region: us-east-1 + - uses: clouddrove/smurf@v1.1.6 + - run: smurf stf init --dir=shared --backend-config=shared/vars/backend.hcl + - run: smurf stf apply --dir=shared --var-file=vars/shared.tfvars --auto-approve +``` + +Run bootstrap once, then use the drift caller. + +### GCP caller (sample) + +```yaml +jobs: + drift-gcp: + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-tf-drift.yml@v2 + with: + terraform_directory: terraform + provider: gcp + var_file: vars/dev.tfvars + project_id: ${{ vars.GCP_PROJECT_ID }} + secrets: + WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }} + SERVICE_ACCOUNT: ${{ secrets.SERVICE_ACCOUNT }} + GCP_CREDENTIALS: ${{ secrets.GCP_CREDENTIALS }} +``` + +--- + +## Use from another repository + +```yaml +permissions: + contents: read + issues: write + id-token: write + +jobs: + drift: + uses: clouddrove/github-shared-workflows/.github/workflows/smurf-tf-drift.yml@v2 + with: + terraform_directory: infrastructure/terraform + provider: aws + var_file: vars/prod.tfvars + backend_config: vars/backend.hcl + aws_region: us-east-1 + secrets: + BUILD_ROLE: ${{ secrets.BUILD_ROLE }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} +``` diff --git a/docs/tf-smurf.md b/docs/smurf-tf-workflow.md similarity index 100% rename from docs/tf-smurf.md rename to docs/smurf-tf-workflow.md