From b4dcc3d2eeed3c4d76e92089478699e51d9d6310 Mon Sep 17 00:00:00 2001 From: Sam Ainsworth Date: Tue, 4 Feb 2025 17:39:18 +0000 Subject: [PATCH 01/17] feat: add terraform plan job --- .github/workflows/terraform-core.yml | 6 +- .github/workflows/terraform-plan-apply.yml | 20 -- .github/workflows/terraform-plan.yml | 204 +++++++++++++++++++++ _test-terraform-plan.yml | 34 ++++ 4 files changed, 242 insertions(+), 22 deletions(-) create mode 100644 .github/workflows/terraform-plan.yml create mode 100644 _test-terraform-plan.yml diff --git a/.github/workflows/terraform-core.yml b/.github/workflows/terraform-core.yml index 4bb2b74..f42d971 100644 --- a/.github/workflows/terraform-core.yml +++ b/.github/workflows/terraform-core.yml @@ -327,7 +327,7 @@ jobs: id: download_plan if: ( inputs.download_existing_plan == true && steps.state_empty.outputs.state_empty == 'false' ) with: - name: "${{ env.state_name }}-artefacts" + name: "${{ env.state_name }}--${{ inputs.environment_name }}-artefacts" path: ${{ matrix.stack.directory }} - name: Decrypt Terraform plan @@ -443,14 +443,16 @@ jobs: pass_file=$(mktemp) printf "%s" "$ENCRYPTION_PASSPHRASE" > "$pass_file" gpg --batch --symmetric --passphrase-file "$pass_file" tfplan + gpg --batch --symmetric --passphrase-file "$pass_file" tfplan.json - name: Upload Terraform Plan and matrix uses: actions/upload-artifact@v4 if: ${{ inputs.upload_plan }} with: - name: "${{ env.state_name }}-artefacts" + name: "${{ env.state_name }}-${{ inputs.environment_name }}-artefacts" path: | ${{ matrix.stack.directory }}/tfplan.gpg + ${{ matrix.stack.directory }}/tfplan.json.gpg ${{ matrix.stack.directory }}/updated_matrix.json ${{ matrix.stack.directory }}/${{ inputs.artefact_path }} if-no-files-found: warn diff --git a/.github/workflows/terraform-plan-apply.yml b/.github/workflows/terraform-plan-apply.yml index 3e6aa7e..08fe797 100644 --- a/.github/workflows/terraform-plan-apply.yml +++ b/.github/workflows/terraform-plan-apply.yml @@ -240,26 +240,6 @@ jobs: artefact_path: ${{ inputs.artefact_path }} secrets: inherit - # update-deployment: - # name: Update Github deployment - # if: always() - # runs-on: ubuntu-latest - # steps: - # - run: | - # deployid=$(gh api -H "Accept: application/vnd.github+json" \ - # --method GET \ - # -H "X-GitHub-Api-Version: 2022-11-28" \ - # -f 'q=sha:${{ github.sha }};environment:${{ inputs.environment_name }}' \ - # /repos/ukhsa-collaboration/${{ github.event.repository.name }}/deployments) - - # gh api \ - # --method POST \ - # -H "Accept: application/vnd.github+json" \ - # -H "X-GitHub-Api-Version: 2022-11-28" \ - # /repos/OWNER/${{ github.event.repository.name }}/deployments/"$deployid"/statuses \ - # -f "state=success" \ - # -f "description=Deployment finished successfully." - post-deployment-qa-checks: name: Run post deployment QA checks. uses: ./.github/workflows/terraform-post-deployment-qa.yml diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml new file mode 100644 index 0000000..debbc38 --- /dev/null +++ b/.github/workflows/terraform-plan.yml @@ -0,0 +1,204 @@ +name: "[CI] Plan Terraform Stacks" +on: + workflow_call: + inputs: + environment_name: + required: false + default: dev + type: string + aws_region: + required: false + default: eu-west-2 + type: string + repo: + required: false + type: string + default: ${{ github.repository }} + ref: + required: false + type: string + default: ${{ github.ref }} + + secrets: + AWS_ROLE_NAME: + required: false + AWS_ACCOUNT_ID: + required: false + AWS_ACCESS_KEY_ID: + required: false + AWS_SECRET_ACCESS_KEY: + required: false + TF_MODULES_SSH_DEPLOY_KEY: + required: false + REPO_SSH_DEPLOY_KEY: + required: false + TF_PLAN_ENCRYPTION_PASSPHRASE: + required: true + description: "The passphrase used to encrypt Terraform Plans before uploading them as Github Artifacts" + + +jobs: + define_matrix: + name: Define directory matrix for build + runs-on: ubuntu-latest + outputs: + stack_config: "${{ steps.stack_config.outputs.json_directory_list }}" + steps: + - uses: actions/checkout@v4 + with: + repository: ${{ inputs.repo }} + ref: ${{ inputs.ref }} + ssh-key: ${{ secrets.REPO_SSH_DEPLOY_KEY }} + - name: Determine order to run Terraform stacks + uses: >- + ukhsa-collaboration/devops-github-actions/.github/actions/terraform-dependency-sort@v0.8.0 + id: stack_config + + filter_matrix: + name: Filter matrix for only planned changes + needs: + - define_matrix + runs-on: ubuntu-latest + outputs: + filtered_matrix: ${{ steps.filter_matrix.outputs.filtered_matrix }} + steps: + - name: Filter Stacks + env: + ENVIRONMENT_NAME: ${{ inputs.environment_name }} + id: filter_matrix + run: | + echo '${{ needs.define_matrix.outputs.stack_config }}' > initial_matrix.json + + filtered_matrix=$(jq -c --arg env_name "${ENVIRONMENT_NAME}" ' + [ .[] + | select(.planned_changes == true) + | if .runner_label == "self-hosted" + then .runner_label = ["self-hosted", $env_name] + else . + end + ] + ' initial_matrix.json) + + echo "Filtered Matrix: $filtered_matrix" + echo "filtered_matrix=$filtered_matrix" >> $GITHUB_OUTPUT + + plan: + name: Plan Terraform + uses: ./.github/workflows/terraform-core.yml + needs: + - filter_matrix + with: + environment_name: ${{ inputs.environment_name }} + aws_region: ${{ inputs.aws_region }} + repo: ${{ inputs.repo }} + ref: ${{ inputs.ref }} + stack_config: "${{ needs.filter_matrix.outputs.filtered_matrix }}" + terraform_action: "apply" + execute_terraform_plan: false + upload_plan: true + download_existing_plan: false + secrets: inherit + + comment: + name: Comment plan on Pull Request + if: github.event_name == 'pull_request' + needs: + - plan + - filter_matrix + runs-on: "${{ matrix.stack.runner_label }}" + strategy: + matrix: + stack: "${{ fromJSON(needs.filter_matrix.outputs.filtered_matrix) }}" + steps: + - name: Export variables + id: variables + run: | + echo "state_name=$(basename ${{ matrix.stack.directory }})" >> $GITHUB_OUTPUT + + - uses: actions/download-artifact@v4 + with: + name: "${{ steps.variables.outputs.state_name }}-${{ inputs.environment_name }}-artefacts" + path: "${{ inputs.environment_name }}/${{ steps.variables.outputs.state_name }}/" + + - name: Decrypt Terraform Plan + working-directory: "${{ inputs.environment_name }}/${{ steps.variables.outputs.state_name }}/" + run: | + pass_file=$(mktemp) + printf "%s" "$ENCRYPTION_PASSPHRASE" > "$pass_file" + gpg --decrypt --batch --passphrase-file "$pass_file" --out tfplan.json tfplan.json.gpg + + - name: Comment plan on PR + uses: actions/github-script@v7 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + script: | + const fs = require('fs'); + const path = require('path'); + + try { + const issue_number = context.payload.pull_request.number; + const owner = context.repo.owner; + const repo = context.repo.repo; + const environment = "${{ inputs.environment_name }}"; + const stack = "${{ steps.variables.outputs.state_name }}"; + const commentIdentifier = ``; + const filePath = path.join(process.env.GITHUB_WORKSPACE, environment, stack, 'tfplan.json'); + + // Debugging Step: Check if file exists before reading + if (!fs.existsSync(filePath)) { + console.log(`❌ Terraform plan file not found: ${filePath}`); + core.setFailed('Terraform plan file not found.'); + return; + } + + const fileContent = fs.readFileSync(filePath, 'utf8'); + + // Fetch all comments in the PR + const comments = await github.rest.issues.listComments({ + owner, + repo, + issue_number, + }); + + // Check if there's an existing comment with our unique identifier + const botComment = comments.data.find(comment => comment.body.includes(commentIdentifier)); + + // Format the comment with a collapsible section + const fullCommentBody = ` + ### 🛠 Terraform Plan Output (${environment.toUpperCase()}) + Click below to expand the Terraform plan results. + +
+ Show Plan for \`${environment}\` + + \`\`\`markdown + ${fileContent} + \`\`\` + + ${commentIdentifier} +
+ `; + + if (botComment) { + // Update the existing comment + await github.rest.issues.updateComment({ + owner, + repo, + comment_id: botComment.id, + body: fullCommentBody, + }); + console.log(`✅ Updated existing PR comment for environment: ${environment}`); + } else { + // Create a new comment + await github.rest.issues.createComment({ + owner, + repo, + issue_number, + body: fullCommentBody, + }); + console.log(`✅ Created a new PR comment for environment: ${environment}`); + } + } catch (error) { + core.setFailed(`🚨 Failed to comment on PR for environment ${environment}: ${error.message}`); + } \ No newline at end of file diff --git a/_test-terraform-plan.yml b/_test-terraform-plan.yml new file mode 100644 index 0000000..7640f60 --- /dev/null +++ b/_test-terraform-plan.yml @@ -0,0 +1,34 @@ +name: "Test Plan Terraform stacks" +# Regression testing to try and catch and breaking changes + +on: + pull_request: + branches: + - main + paths: + - .github/workflows/terraform-plan.yml + - .github/workflows/_test-terraform-plan.yml + - .github/workflows/terraform-core.yml + - .github/workflows/terraform-code-check.yml + +jobs: + plan_tf_stacks_regression_test: + name: Test using devops-terraform-example-project@main + uses: ./.github/workflows/terraform-plan.yml + with: + repo: ukhsa-collaboration/devops-terraform-example-project + ref: "main" + permissions: + packages: read + actions: read + contents: read + security-events: write + statuses: write + checks: write + id-token: write + secrets: + REPO_SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }} + AWS_ACCOUNT_ID: ${{ secrets.TEST_AWS_ACCOUNT_ID }} + AWS_ROLE_NAME: ${{ secrets.TEST_AWS_ROLE_NAME }} + TF_MODULES_SSH_DEPLOY_KEY: ${{ secrets.TF_MODULES_SSH_DEPLOY_KEY }} + TF_PLAN_ENCRYPTION_PASSPHRASE: ${{ secrets.TF_PLAN_ENCRYPTION_PASSPHRASE }} \ No newline at end of file From a934c345d4a2796b2dc8bf02645d6536496169bd Mon Sep 17 00:00:00 2001 From: Sam Ainsworth Date: Tue, 4 Feb 2025 18:06:43 +0000 Subject: [PATCH 02/17] Add missing encryption key --- .github/workflows/terraform-plan.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml index debbc38..9035a58 100644 --- a/.github/workflows/terraform-plan.yml +++ b/.github/workflows/terraform-plan.yml @@ -122,6 +122,8 @@ jobs: - name: Decrypt Terraform Plan working-directory: "${{ inputs.environment_name }}/${{ steps.variables.outputs.state_name }}/" + env: + ENCRYPTION_PASSPHRASE: ${{ secrets.TF_PLAN_ENCRYPTION_PASSPHRASE }} run: | pass_file=$(mktemp) printf "%s" "$ENCRYPTION_PASSPHRASE" > "$pass_file" From 62c63aab60a625727e6ccbcc4500e605db3eac77 Mon Sep 17 00:00:00 2001 From: Sam Ainsworth Date: Tue, 4 Feb 2025 18:17:29 +0000 Subject: [PATCH 03/17] Fix path --- .github/workflows/terraform-plan.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml index 9035a58..6519813 100644 --- a/.github/workflows/terraform-plan.yml +++ b/.github/workflows/terraform-plan.yml @@ -116,12 +116,13 @@ jobs: echo "state_name=$(basename ${{ matrix.stack.directory }})" >> $GITHUB_OUTPUT - uses: actions/download-artifact@v4 + id: download with: name: "${{ steps.variables.outputs.state_name }}-${{ inputs.environment_name }}-artefacts" - path: "${{ inputs.environment_name }}/${{ steps.variables.outputs.state_name }}/" + path: "${{ inputs.environment_name }}/${{ steps.variables.outputs.state_name }}" - name: Decrypt Terraform Plan - working-directory: "${{ inputs.environment_name }}/${{ steps.variables.outputs.state_name }}/" + working-directory: ${{ steps.download.outputs.download-path }} env: ENCRYPTION_PASSPHRASE: ${{ secrets.TF_PLAN_ENCRYPTION_PASSPHRASE }} run: | From 4e418a84875fe53516f1e902ffe8b1b7290ad62f Mon Sep 17 00:00:00 2001 From: Sam Ainsworth Date: Tue, 4 Feb 2025 18:27:10 +0000 Subject: [PATCH 04/17] add debug --- .github/workflows/terraform-plan.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml index 6519813..63a08b4 100644 --- a/.github/workflows/terraform-plan.yml +++ b/.github/workflows/terraform-plan.yml @@ -126,6 +126,8 @@ jobs: env: ENCRYPTION_PASSPHRASE: ${{ secrets.TF_PLAN_ENCRYPTION_PASSPHRASE }} run: | + pwd + ls -lah . pass_file=$(mktemp) printf "%s" "$ENCRYPTION_PASSPHRASE" > "$pass_file" gpg --decrypt --batch --passphrase-file "$pass_file" --out tfplan.json tfplan.json.gpg From be5e44956dfbeb560211aeae151d91053ae504bc Mon Sep 17 00:00:00 2001 From: Sam Ainsworth Date: Tue, 4 Feb 2025 18:36:10 +0000 Subject: [PATCH 05/17] remove artefact path --- .github/workflows/terraform-core.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/terraform-core.yml b/.github/workflows/terraform-core.yml index f42d971..6b71947 100644 --- a/.github/workflows/terraform-core.yml +++ b/.github/workflows/terraform-core.yml @@ -58,11 +58,6 @@ on: type: string default: "3.12" description: "The version of python required when building packages via Terraform" - artefact_path: - required: false - type: string - default: "" - description: "If there are artefacts created from data sources, specify the path from the TF stack dir here so they are uploaded before applying" secrets: AWS_ROLE_NAME: @@ -454,7 +449,6 @@ jobs: ${{ matrix.stack.directory }}/tfplan.gpg ${{ matrix.stack.directory }}/tfplan.json.gpg ${{ matrix.stack.directory }}/updated_matrix.json - ${{ matrix.stack.directory }}/${{ inputs.artefact_path }} if-no-files-found: warn compression-level: 1 retention-days: 1 From efe1d7b72be6e45e1204cd891af86f435ae954a8 Mon Sep 17 00:00:00 2001 From: Sam Ainsworth Date: Tue, 4 Feb 2025 18:47:03 +0000 Subject: [PATCH 06/17] script corrections --- .github/workflows/terraform-plan.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml index 63a08b4..cc3512b 100644 --- a/.github/workflows/terraform-plan.yml +++ b/.github/workflows/terraform-plan.yml @@ -138,15 +138,17 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: script: | + const core = require('@actions/core'); const fs = require('fs'); const path = require('path'); + const environment = "${{ inputs.environment_name }}"; + const stack = "${{ steps.variables.outputs.state_name }}"; + try { const issue_number = context.payload.pull_request.number; const owner = context.repo.owner; const repo = context.repo.repo; - const environment = "${{ inputs.environment_name }}"; - const stack = "${{ steps.variables.outputs.state_name }}"; const commentIdentifier = ``; const filePath = path.join(process.env.GITHUB_WORKSPACE, environment, stack, 'tfplan.json'); @@ -159,17 +161,14 @@ jobs: const fileContent = fs.readFileSync(filePath, 'utf8'); - // Fetch all comments in the PR const comments = await github.rest.issues.listComments({ owner, repo, issue_number, }); - // Check if there's an existing comment with our unique identifier const botComment = comments.data.find(comment => comment.body.includes(commentIdentifier)); - // Format the comment with a collapsible section const fullCommentBody = ` ### 🛠 Terraform Plan Output (${environment.toUpperCase()}) Click below to expand the Terraform plan results. @@ -206,4 +205,4 @@ jobs: } } catch (error) { core.setFailed(`🚨 Failed to comment on PR for environment ${environment}: ${error.message}`); - } \ No newline at end of file + } From a75a60e4b0218b2c82534b0973e25b4995eb1dc0 Mon Sep 17 00:00:00 2001 From: Sam Ainsworth Date: Tue, 4 Feb 2025 18:53:20 +0000 Subject: [PATCH 07/17] core --- .github/workflows/terraform-plan.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml index cc3512b..fd61da7 100644 --- a/.github/workflows/terraform-plan.yml +++ b/.github/workflows/terraform-plan.yml @@ -138,7 +138,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: script: | - const core = require('@actions/core'); const fs = require('fs'); const path = require('path'); From a7df212c4500b4c8a36d987eb817b51cd7abb1f6 Mon Sep 17 00:00:00 2001 From: Sam Ainsworth Date: Wed, 5 Feb 2025 11:21:49 +0000 Subject: [PATCH 08/17] update commentds --- .github/workflows/terraform-plan.yml | 69 +++++++++++++++++++--------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml index fd61da7..d81cdc4 100644 --- a/.github/workflows/terraform-plan.yml +++ b/.github/workflows/terraform-plan.yml @@ -151,7 +151,6 @@ jobs: const commentIdentifier = ``; const filePath = path.join(process.env.GITHUB_WORKSPACE, environment, stack, 'tfplan.json'); - // Debugging Step: Check if file exists before reading if (!fs.existsSync(filePath)) { console.log(`❌ Terraform plan file not found: ${filePath}`); core.setFailed('Terraform plan file not found.'); @@ -160,6 +159,49 @@ jobs: const fileContent = fs.readFileSync(filePath, 'utf8'); + let planJson; + try { + planJson = JSON.parse(fileContent); + } catch (parseError) { + core.setFailed(`Failed to parse tfplan.json: ${parseError.message}`); + return; + } + + const summary = { create: [], update: [], delete: [], replace: [] }; + + const changes = planJson.resource_changes || []; + changes.forEach(change => { + const address = change.address; + const actions = change.change.actions; + // If the actions include both delete and create, it's a replacement. + if (actions.includes("delete") && actions.includes("create")) { + summary.replace.push(address); + } else if (actions.includes("create")) { + summary.create.push(address); + } else if (actions.includes("update")) { + summary.update.push(address); + } else if (actions.includes("delete")) { + summary.delete.push(address); + } + }); + + let summaryText = `### Terraform Plan Summary (${environment.toUpperCase()}/${stack.toUpperCase()})\n\n`; + if (summary.delete.length > 0) { + summaryText += `🔴 **Resources to be destroyed:**\n${summary.delete.map(addr => `- ${addr}`).join("\n")}\n\n`; + } + if (summary.update.length > 0) { + summaryText += `🟡 **Resources to be updated:**\n${summary.update.map(addr => `- ${addr}`).join("\n")}\n\n`; + } + if (summary.create.length > 0) { + summaryText += `🟢 **Resources to be created:**\n${summary.create.map(addr => `- ${addr}`).join("\n")}\n\n`; + } + if (summary.replace.length > 0) { + summaryText += `🟣 **Resources to be replaced:**\n${summary.replace.map(addr => `- ${addr}`).join("\n")}\n\n`; + } + + // Append the comment identifier so that subsequent runs can update the correct comment. + summaryText += commentIdentifier; + const comments = await github.rest.issues.listComments({ owner, repo, @@ -168,39 +210,22 @@ jobs: const botComment = comments.data.find(comment => comment.body.includes(commentIdentifier)); - const fullCommentBody = ` - ### 🛠 Terraform Plan Output (${environment.toUpperCase()}) - Click below to expand the Terraform plan results. - -
- Show Plan for \`${environment}\` - - \`\`\`markdown - ${fileContent} - \`\`\` - - ${commentIdentifier} -
- `; - if (botComment) { - // Update the existing comment await github.rest.issues.updateComment({ owner, repo, comment_id: botComment.id, - body: fullCommentBody, + body: summaryText, }); - console.log(`✅ Updated existing PR comment for environment: ${environment}`); + console.log(`✅ Updated existing PR comment for environment: ${environment} / stack: ${stack}`); } else { - // Create a new comment await github.rest.issues.createComment({ owner, repo, issue_number, - body: fullCommentBody, + body: summaryText, }); - console.log(`✅ Created a new PR comment for environment: ${environment}`); + console.log(`✅ Created a new PR comment for environment: ${environment} / stack: ${stack}`); } } catch (error) { core.setFailed(`🚨 Failed to comment on PR for environment ${environment}: ${error.message}`); From eaaac1fded7c38262e99bd8b100c5a3ac305afc5 Mon Sep 17 00:00:00 2001 From: Sam Ainsworth Date: Wed, 5 Feb 2025 11:42:29 +0000 Subject: [PATCH 09/17] Add TF Plan --- .github/workflows/terraform-plan.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml index d81cdc4..94953e4 100644 --- a/.github/workflows/terraform-plan.yml +++ b/.github/workflows/terraform-plan.yml @@ -126,11 +126,17 @@ jobs: env: ENCRYPTION_PASSPHRASE: ${{ secrets.TF_PLAN_ENCRYPTION_PASSPHRASE }} run: | - pwd - ls -lah . pass_file=$(mktemp) printf "%s" "$ENCRYPTION_PASSPHRASE" > "$pass_file" gpg --decrypt --batch --passphrase-file "$pass_file" --out tfplan.json tfplan.json.gpg + gpg --decrypt --batch --passphrase-file "$pass_file" --out tfplan tfplan.gpg + + - name: Display Terraform Plan + working-directory: ${{ steps.download.outputs.download-path }} + env: + ENCRYPTION_PASSPHRASE: ${{ secrets.TF_PLAN_ENCRYPTION_PASSPHRASE }} + run: | + terraform show -no-color -json tfplan - name: Comment plan on PR uses: actions/github-script@v7 @@ -198,7 +204,10 @@ jobs: if (summary.replace.length > 0) { summaryText += `🟣 **Resources to be replaced:**\n${summary.replace.map(addr => `- ${addr}`).join("\n")}\n\n`; } - + if (summary.summary.update.length == 0 && summary.update.length == 0 && summary.create.length == 0 && summary.replace.length == 0) { + summaryText += `👌 **No resources will be changed**\n\n`; + } + // Append the comment identifier so that subsequent runs can update the correct comment. summaryText += commentIdentifier; From 775e82274614ab8c5a074273dd6431aef7ec32e3 Mon Sep 17 00:00:00 2001 From: Sam Ainsworth Date: Wed, 5 Feb 2025 12:12:19 +0000 Subject: [PATCH 10/17] remove superfluous --- .github/workflows/terraform-plan.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml index 94953e4..3e0181d 100644 --- a/.github/workflows/terraform-plan.yml +++ b/.github/workflows/terraform-plan.yml @@ -129,14 +129,6 @@ jobs: pass_file=$(mktemp) printf "%s" "$ENCRYPTION_PASSPHRASE" > "$pass_file" gpg --decrypt --batch --passphrase-file "$pass_file" --out tfplan.json tfplan.json.gpg - gpg --decrypt --batch --passphrase-file "$pass_file" --out tfplan tfplan.gpg - - - name: Display Terraform Plan - working-directory: ${{ steps.download.outputs.download-path }} - env: - ENCRYPTION_PASSPHRASE: ${{ secrets.TF_PLAN_ENCRYPTION_PASSPHRASE }} - run: | - terraform show -no-color -json tfplan - name: Comment plan on PR uses: actions/github-script@v7 From 0312b641511d0a7e6dc5a06373344277683216d3 Mon Sep 17 00:00:00 2001 From: Sam Ainsworth Date: Wed, 5 Feb 2025 12:24:54 +0000 Subject: [PATCH 11/17] correction --- .github/workflows/terraform-plan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml index 3e0181d..3ab5f67 100644 --- a/.github/workflows/terraform-plan.yml +++ b/.github/workflows/terraform-plan.yml @@ -196,7 +196,7 @@ jobs: if (summary.replace.length > 0) { summaryText += `🟣 **Resources to be replaced:**\n${summary.replace.map(addr => `- ${addr}`).join("\n")}\n\n`; } - if (summary.summary.update.length == 0 && summary.update.length == 0 && summary.create.length == 0 && summary.replace.length == 0) { + if (summary.update.length == 0 && summary.delete.length == 0 && summary.create.length == 0 && summary.replace.length == 0) { summaryText += `👌 **No resources will be changed**\n\n`; } From df922ef03b524172a1e7f2a001a6e0f857b540f9 Mon Sep 17 00:00:00 2001 From: Sam Ainsworth Date: Wed, 5 Feb 2025 13:38:47 +0000 Subject: [PATCH 12/17] Fix tests --- .github/workflows/terraform-plan-apply.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/terraform-plan-apply.yml b/.github/workflows/terraform-plan-apply.yml index 08fe797..1c077cf 100644 --- a/.github/workflows/terraform-plan-apply.yml +++ b/.github/workflows/terraform-plan-apply.yml @@ -37,11 +37,6 @@ on: type: string default: ${{ github.ref }} description: "Specify the branch of the Terraform code. Normally left blank to use calling ref." - artefact_path: - required: false - type: string - default: "" - description: "If there are artefacts created from data sources, specify the path here so they are downloaded before applying" secrets: AWS_ROLE_NAME: @@ -153,7 +148,6 @@ jobs: upload_plan: true download_existing_plan: false python_version: ${{ inputs.python_version }} - artefact_path: ${{ inputs.artefact_path }} secrets: inherit approve: @@ -237,7 +231,6 @@ jobs: upload_plan: false download_existing_plan: true python_version: ${{ inputs.python_version }} - artefact_path: ${{ inputs.artefact_path }} secrets: inherit post-deployment-qa-checks: From 140b3e259509665be817c238d40b80d906209bfd Mon Sep 17 00:00:00 2001 From: Sam Ainsworth Date: Wed, 5 Feb 2025 14:08:48 +0000 Subject: [PATCH 13/17] Remove extra hyphen --- .github/workflows/terraform-core.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/terraform-core.yml b/.github/workflows/terraform-core.yml index 6b71947..3b70668 100644 --- a/.github/workflows/terraform-core.yml +++ b/.github/workflows/terraform-core.yml @@ -322,7 +322,7 @@ jobs: id: download_plan if: ( inputs.download_existing_plan == true && steps.state_empty.outputs.state_empty == 'false' ) with: - name: "${{ env.state_name }}--${{ inputs.environment_name }}-artefacts" + name: "${{ env.state_name }}-${{ inputs.environment_name }}-artefacts" path: ${{ matrix.stack.directory }} - name: Decrypt Terraform plan From 9c980e66170616b785ec631c72b76ae1947b157e Mon Sep 17 00:00:00 2001 From: Sam Ainsworth Date: Wed, 5 Feb 2025 14:18:38 +0000 Subject: [PATCH 14/17] environment name --- .github/workflows/terraform-post-deployment-qa.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/terraform-post-deployment-qa.yml b/.github/workflows/terraform-post-deployment-qa.yml index 51ea018..4337c68 100644 --- a/.github/workflows/terraform-post-deployment-qa.yml +++ b/.github/workflows/terraform-post-deployment-qa.yml @@ -80,7 +80,7 @@ jobs: - uses: actions/download-artifact@v4 id: download_plan with: - name: "${{ env.state_name }}-artefacts" + name: "${{ env.state_name }}-${{ inputs.environment_name}}-artefacts" path: ${{ matrix.stack.directory }} - name: Deep SAST Scan Terraform code From af394e4b5055baee2dc5dbae48a86ca396aa3976 Mon Sep 17 00:00:00 2001 From: sweavers-ukhsa <135218414+sweavers-ukhsa@users.noreply.github.com> Date: Wed, 5 Feb 2025 14:37:31 +0000 Subject: [PATCH 15/17] Added default artefact that won't exist and removed unencrypted plan files prior to applying (#19) --- .github/workflows/terraform-core.yml | 9 +++++++++ .github/workflows/terraform-plan-apply.yml | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/.github/workflows/terraform-core.yml b/.github/workflows/terraform-core.yml index 3b70668..140da8e 100644 --- a/.github/workflows/terraform-core.yml +++ b/.github/workflows/terraform-core.yml @@ -58,6 +58,11 @@ on: type: string default: "3.12" description: "The version of python required when building packages via Terraform" + artefact_path: + required: false + type: string + default: "nonexistentfile.txt" + description: "If there are artefacts created from data sources, specify the path from the TF stack dir here so they are uploaded before applying" secrets: AWS_ROLE_NAME: @@ -440,6 +445,9 @@ jobs: gpg --batch --symmetric --passphrase-file "$pass_file" tfplan gpg --batch --symmetric --passphrase-file "$pass_file" tfplan.json + # Delete unecrypted plan files incase of accidental upload. + rm tfplan tfplan.json + - name: Upload Terraform Plan and matrix uses: actions/upload-artifact@v4 if: ${{ inputs.upload_plan }} @@ -449,6 +457,7 @@ jobs: ${{ matrix.stack.directory }}/tfplan.gpg ${{ matrix.stack.directory }}/tfplan.json.gpg ${{ matrix.stack.directory }}/updated_matrix.json + ${{ matrix.stack.directory }}/${{ inputs.artefact_path }} if-no-files-found: warn compression-level: 1 retention-days: 1 diff --git a/.github/workflows/terraform-plan-apply.yml b/.github/workflows/terraform-plan-apply.yml index 1c077cf..3ef8aeb 100644 --- a/.github/workflows/terraform-plan-apply.yml +++ b/.github/workflows/terraform-plan-apply.yml @@ -37,6 +37,11 @@ on: type: string default: ${{ github.ref }} description: "Specify the branch of the Terraform code. Normally left blank to use calling ref." + artefact_path: + required: false + type: string + default: "nonexistentfile.txt" + description: "If there are artefacts created from data sources, specify the path here so they are downloaded before" secrets: AWS_ROLE_NAME: @@ -148,6 +153,7 @@ jobs: upload_plan: true download_existing_plan: false python_version: ${{ inputs.python_version }} + artefact_path: ${{ inputs.artefact_path }} secrets: inherit approve: @@ -231,6 +237,7 @@ jobs: upload_plan: false download_existing_plan: true python_version: ${{ inputs.python_version }} + artefact_path: ${{ inputs.artefact_path }} secrets: inherit post-deployment-qa-checks: From 1ae6b4dceac97d757723ba9ae69576a70ba8d42a Mon Sep 17 00:00:00 2001 From: sweavers-ukhsa <135218414+sweavers-ukhsa@users.noreply.github.com> Date: Wed, 5 Feb 2025 14:45:37 +0000 Subject: [PATCH 16/17] Fixed typo --- .github/workflows/terraform-core.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/terraform-core.yml b/.github/workflows/terraform-core.yml index 140da8e..6314520 100644 --- a/.github/workflows/terraform-core.yml +++ b/.github/workflows/terraform-core.yml @@ -445,7 +445,7 @@ jobs: gpg --batch --symmetric --passphrase-file "$pass_file" tfplan gpg --batch --symmetric --passphrase-file "$pass_file" tfplan.json - # Delete unecrypted plan files incase of accidental upload. + # Delete unencrypted plan files incase of accidental upload. rm tfplan tfplan.json - name: Upload Terraform Plan and matrix From 154e4b72860580c2a502ff986c48b85fd8a967e2 Mon Sep 17 00:00:00 2001 From: sweavers-ukhsa <135218414+sweavers-ukhsa@users.noreply.github.com> Date: Wed, 5 Feb 2025 14:46:40 +0000 Subject: [PATCH 17/17] Fixed typo --- .github/workflows/terraform-plan-apply.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/terraform-plan-apply.yml b/.github/workflows/terraform-plan-apply.yml index 3ef8aeb..df78373 100644 --- a/.github/workflows/terraform-plan-apply.yml +++ b/.github/workflows/terraform-plan-apply.yml @@ -41,7 +41,7 @@ on: required: false type: string default: "nonexistentfile.txt" - description: "If there are artefacts created from data sources, specify the path here so they are downloaded before" + description: "If there are artefacts created from data sources, specify the path here so they are downloaded before applying" secrets: AWS_ROLE_NAME: