From ec9b46099e2069d0abe42ecc2cbd69b705452928 Mon Sep 17 00:00:00 2001
From: Suhong Qin <51539171+sqin2019@users.noreply.github.com>
Date: Tue, 29 Aug 2023 17:04:59 -0700
Subject: [PATCH] feat: added iam cleanup in workflow (#111)
---
.github/workflows/cleanup.yml | 284 +++++++++++++++++++++++++++++
.github/workflows/tool_cleanup.yml | 178 ------------------
2 files changed, 284 insertions(+), 178 deletions(-)
create mode 100644 .github/workflows/cleanup.yml
delete mode 100644 .github/workflows/tool_cleanup.yml
diff --git a/.github/workflows/cleanup.yml b/.github/workflows/cleanup.yml
new file mode 100644
index 0000000..f0fab39
--- /dev/null
+++ b/.github/workflows/cleanup.yml
@@ -0,0 +1,284 @@
+# Copyright 2023 The Authors (see AUTHORS file)
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Reusable workflow that handles AOD request cleanup.
+name: 'aod-cleanup'
+
+on:
+ workflow_call:
+ inputs:
+ workload_identity_provider:
+ description: 'The full identifier of the Workload Identity Provider, including the project number, pool name, and provider name.'
+ type: 'string'
+ required: true
+ service_account:
+ description: 'Email address or unique identifier of the Google Cloud service account for which to generate credentials.'
+ type: 'string'
+ required: true
+ aod_cli_version:
+ description: 'The version of AOD CLI.'
+ type: 'string'
+ default: 'latest'
+ required: false
+ go_version:
+ description: 'The version of Golang.'
+ type: 'string'
+ default: '1.21'
+ required: false
+
+env:
+ IAM_ERROR_FILENAME: 'iam_error.txt'
+ IAM_OUT_FILENAME: 'iam_output.txt'
+ TOOL_ERROR_FILENAME: 'tool_error.txt'
+ TOOL_OUT_FILENAME: 'tool_output.txt'
+
+jobs:
+ # Check the current status of this pull request with respect to code review.
+ review_status:
+ runs-on: 'ubuntu-latest'
+ permissions:
+ pull-requests: 'read'
+ outputs:
+ REVIEW_DECISION: '${{ steps.get_review_decision.outputs.REVIEW_DECISION }}'
+ steps:
+ - id: 'get_review_decision'
+ env:
+ # Set the GH_TOKEN environment variable to use GitHub CLI in a GitHub Actions workflow.
+ # See ref: https://docs.github.com/en/actions/using-workflows/using-github-cli-in-workflows
+ GH_TOKEN: '${{ github.token }}'
+ run: |
+ repo=${{ github.repository }}
+ reviewDecision="$(gh api graphql -F owner=${{ github.repository_owner }} -F name=${repo##*/} -F pr_number=${{ github.event.pull_request.number }} -f query='
+ query($name: String!, $owner: String!, $pr_number: Int!) {
+ repository(owner: $owner, name: $name) {
+ pullRequest(number: $pr_number) {
+ reviewDecision
+ }
+ }
+ }
+ ' --jq '.data.repository.pullRequest.reviewDecision')"
+
+ echo REVIEW_DECISION=$reviewDecision >> $GITHUB_OUTPUT
+
+ # Only run Tool request cleanup when the pull request is approved.
+ cleanup:
+ needs: 'review_status'
+ if: '${{ needs.review_status.outputs.REVIEW_DECISION == ''APPROVED'' }}'
+ runs-on: 'ubuntu-latest'
+ permissions:
+ contents: 'read'
+ id-token: 'write'
+ pull-requests: 'write'
+ name: 'Handle AOD Request Cleanup'
+ steps:
+ - name: 'Checkout Triggering Branch'
+ uses: 'actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab' # ratchet:actions/checkout@v3
+ with:
+ ref: '${{ github.event.pull_request.head.ref }}'
+ - name: 'Setup Go'
+ uses: 'actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568' # ratchet:actions/setup-go@v3
+ with:
+ go-version: '${{ inputs.go_version }}'
+ - name: 'Authenticate to Google Cloud'
+ uses: 'google-github-actions/auth@35b0e87d162680511bf346c299f71c9c5c379033' # ratchet:google-github-actions/auth@v1
+ with:
+ workload_identity_provider: '${{ inputs.workload_identity_provider }}'
+ service_account: '${{ inputs.service_account }}'
+ token_format: 'access_token'
+ # Install gcloud, `setup-gcloud` automatically picks up authentication from `auth`.
+ - name: 'Set up Cloud SDK for tool request'
+ if: '${{ hashFiles(''tool.yaml'') != '''' }}'
+ uses: 'google-github-actions/setup-gcloud@e30db14379863a8c79331b04a9969f4c1e225e0b' # ratchet:google-github-actions/setup-gcloud@v1
+ - name: 'Install AOD CLI'
+ run: 'go install github.com/abcxyz/access-on-demand/cmd/aod@${{ inputs.aod_cli_version }}'
+ - name: 'Handle tool cleanup'
+ if: '${{ hashFiles(''tool.yaml'') != '''' }}'
+ id: 'cleanup_tool'
+ env:
+ TOOL_FILE_PATH: '${{ github.workspace }}/tool.yaml'
+ run: |
+ touch ${{ runner.temp }}/${{ env.TOOL_ERROR_FILENAME }}
+ touch ${{ runner.temp }}/${{ env.TOOL_OUT_FILENAME }}
+ aod tool cleanup -path ${{ env.TOOL_FILE_PATH }} \
+ 2> ${{ runner.temp }}/${{ env.TOOL_ERROR_FILENAME }} \
+ > ${{ runner.temp }}/${{ env.TOOL_OUT_FILENAME }}
+ - name: 'Handle IAM cleanup'
+ if: '${{ hashFiles(''iam.yaml'') != '''' }}'
+ id: 'cleanup_iam'
+ env:
+ IAM_FILE_PATH: '${{ github.workspace }}/iam.yaml'
+ run: |
+ touch ${{ runner.temp }}/${{ env.IAM_ERROR_FILENAME }}
+ touch ${{ runner.temp }}/${{ env.IAM_OUT_FILENAME }}
+ aod iam cleanup -path ${{ env.IAM_FILE_PATH }} \
+ 2> ${{ runner.temp }}/${{ env.IAM_ERROR_FILENAME }} \
+ > ${{ runner.temp }}/${{ env.IAM_OUT_FILENAME }}
+ - name: 'Tool Request Success Cleanup Comment'
+ if: '${{ always() && steps.cleanup_tool.outcome == ''success'' }}'
+ uses: 'actions/github-script@98814c53be79b1d30f795b907e553d8679345975' # ratchet:actions/github-script@v6
+ with:
+ github-token: '${{ github.token }}'
+ retries: '3'
+ script: |+
+ const fs = require("fs");
+
+ const toolOutFilename = "${{ runner.temp }}/${{ env.TOOL_OUT_FILENAME }}";
+ const req = fs.readFileSync(toolOutFilename, { encoding: "utf8" });
+
+ const body = `**\`Access on Demand\`** - 🟩 **\`Tool\`** request cleanup succeeded.
+
+
+ Details
+ Executed "cleanup" commands in the request below, or skipped if commands not found.
+
+ \`\`\`
+ ${req}
+ \`\`\`
+ `;
+
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: "${{ github.event.pull_request.number }}",
+ body: body,
+ });
+ - name: 'Tool Request Failure Cleanup Comment'
+ if: '${{ always() && steps.cleanup_tool.outcome == ''failure'' }}'
+ uses: 'actions/github-script@98814c53be79b1d30f795b907e553d8679345975' # ratchet:actions/github-script@v6
+ with:
+ github-token: '${{ github.token }}'
+ retries: '3'
+ script: |+
+ const fs = require("fs");
+
+ const toolOutFilename = "${{ runner.temp }}/${{ env.TOOL_OUT_FILENAME }}";
+ const toolErrFilename = "${{ runner.temp }}/${{ env.TOOL_ERROR_FILENAME }}";
+
+ const req = fs.readFileSync(toolOutFilename, { encoding: "utf8" });
+ const error = fs.readFileSync(toolErrFilename, { encoding: "utf8" });
+
+ const body = `**\`Access on Demand\`** - 🟥 **\`Tool\`** request cleanup failed.
+
+
+ Details
+ Failed to execute "cleanup" commands in the request below.
+
+ \`\`\`
+ ${req}
+ \`\`\`
+
+ Error:
+ \`\`\`
+ ${error}
+ \`\`\`
+ `;
+
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: "${{ github.event.pull_request.number }}",
+ body: body,
+ });
+ - name: 'Tool Request Not Found Comment'
+ if: '${{ always() && hashFiles(''tool.yaml'') == '''' }}'
+ uses: 'actions/github-script@98814c53be79b1d30f795b907e553d8679345975' # ratchet:actions/github-script@v6
+ with:
+ github-token: '${{ github.token }}'
+ retries: '3'
+ script: |+
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: ${{ github.event.pull_request.number }},
+ body: `**\`Access on Demand\`** - 🟦 **\`Tool\`** request not found, skip cleanup.`,
+ });
+ - name: 'IAM Request Success Cleanup Comment'
+ if: '${{ always() && steps.cleanup_iam.outcome == ''success'' }}'
+ uses: 'actions/github-script@98814c53be79b1d30f795b907e553d8679345975' # ratchet:actions/github-script@v6
+ with:
+ github-token: '${{ github.token }}'
+ retries: '3'
+ script: |+
+ const fs = require("fs");
+
+ const iamOutFilename = "${{ runner.temp }}/${{ env.IAM_OUT_FILENAME }}";
+ const req = fs.readFileSync(iamOutFilename, { encoding: "utf8" });
+
+ const body = `**\`Access on Demand\`** - 🟩 **\`IAM\`** request cleanup succeeded.
+
+
+ Details
+ Removed bindings in the request below.
+
+ \`\`\`
+ ${req}
+ \`\`\`
+ `;
+
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: "${{ github.event.pull_request.number }}",
+ body: body,
+ });
+ - name: 'IAM Request Failure Cleanup Comment'
+ if: '${{ always() && steps.cleanup_iam.outcome == ''failure'' }}'
+ uses: 'actions/github-script@98814c53be79b1d30f795b907e553d8679345975' # ratchet:actions/github-script@v6
+ with:
+ github-token: '${{ github.token }}'
+ retries: '3'
+ script: |+
+ const fs = require("fs");
+
+ const iamOutFilename = "${{ runner.temp }}/${{ env.IAM_OUT_FILENAME }}";
+ const iamErrFilename = "${{ runner.temp }}/${{ env.IAM_ERROR_FILENAME }}";
+
+ const req = fs.readFileSync(iamOutFilename, { encoding: "utf8" });
+ const error = fs.readFileSync(iamErrFilename, { encoding: "utf8" });
+
+ const body = `**\`Access on Demand\`** - 🟥 **\`IAM\`** request cleanup failed.
+
+
+ Details
+ Failed to cleanup IAM polices of the resources in the request below.
+
+ \`\`\`
+ ${req}
+ \`\`\`
+
+ Error:
+ \`\`\`
+ ${error}
+ \`\`\`
+ `;
+
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: "${{ github.event.pull_request.number }}",
+ body: body,
+ });
+ - name: 'IAM Request Not Found Comment'
+ if: '${{ always() && hashFiles(''iam.yaml'') == '''' }}'
+ uses: 'actions/github-script@98814c53be79b1d30f795b907e553d8679345975' # ratchet:actions/github-script@v6
+ with:
+ github-token: '${{ github.token }}'
+ retries: '3'
+ script: |+
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: ${{ github.event.pull_request.number }},
+ body: `**\`Access on Demand\`** - 🟦 **\`IAM\`** request not found, skip cleanup.`,
+ });
diff --git a/.github/workflows/tool_cleanup.yml b/.github/workflows/tool_cleanup.yml
deleted file mode 100644
index 0c2597f..0000000
--- a/.github/workflows/tool_cleanup.yml
+++ /dev/null
@@ -1,178 +0,0 @@
-# Copyright 2023 The Authors (see AUTHORS file)
-
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-
-# http://www.apache.org/licenses/LICENSE-2.0
-
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Reusable workflow that handles tool request cleanup.
-name: 'aod-tool-cleanup'
-
-on:
- workflow_call:
- inputs:
- workload_identity_provider:
- description: 'The full identifier of the Workload Identity Provider, including the project number, pool name, and provider name.'
- type: 'string'
- required: true
- service_account:
- description: 'Email address or unique identifier of the Google Cloud service account for which to generate credentials.'
- type: 'string'
- required: true
- aod_cli_version:
- description: 'The version of AOD CLI.'
- type: 'string'
- default: 'latest'
- required: false
- go_version:
- description: 'The version of Golang.'
- type: 'string'
- default: '1.21'
- required: false
-
-env:
- TOOL_ERROR_FILENAME: '/tmp/tool_error.txt'
- TOOL_OUT_FILENAME: '/tmp/tool_output.txt'
-
-jobs:
- # Check the current status of this pull request with respect to code review.
- review_status:
- runs-on: 'ubuntu-latest'
- permissions:
- pull-requests: 'read'
- outputs:
- REVIEW_DECISION: '${{ steps.get_review_decision.outputs.REVIEW_DECISION }}'
- steps:
- - id: 'get_review_decision'
- env:
- # Set the GH_TOKEN environment variable to use GitHub CLI in a GitHub Actions workflow.
- # See ref: https://docs.github.com/en/actions/using-workflows/using-github-cli-in-workflows
- GH_TOKEN: '${{ github.token }}'
- run: |
- repo=${{ github.repository }}
- reviewDecision="$(gh api graphql -F owner=${{ github.repository_owner }} -F name=${repo##*/} -F pr_number=${{ github.event.pull_request.number }} -f query='
- query($name: String!, $owner: String!, $pr_number: Int!) {
- repository(owner: $owner, name: $name) {
- pullRequest(number: $pr_number) {
- reviewDecision
- }
- }
- }
- ' --jq '.data.repository.pullRequest.reviewDecision')"
-
- echo REVIEW_DECISION=$reviewDecision >> $GITHUB_OUTPUT
-
- # Only run Tool request cleanup when the pull request is approved.
- cleanup:
- needs: 'review_status'
- if: '${{ needs.review_status.outputs.REVIEW_DECISION == ''APPROVED'' }}'
- runs-on: 'ubuntu-latest'
- permissions:
- contents: 'read'
- id-token: 'write'
- pull-requests: 'write'
- name: 'Handle Tool Request Cleanup'
- steps:
- - name: 'Checkout Triggering Branch'
- uses: 'actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab' # ratchet:actions/checkout@v3
- with:
- ref: '${{ github.event.pull_request.head.ref }}'
- - name: 'Setup Go'
- uses: 'actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568' # ratchet:actions/setup-go@v3
- with:
- go-version: '${{ inputs.go_version }}'
- - name: 'Authenticate to Google Cloud'
- uses: 'google-github-actions/auth@35b0e87d162680511bf346c299f71c9c5c379033' # ratchet:google-github-actions/auth@v1
- with:
- workload_identity_provider: '${{ inputs.workload_identity_provider }}'
- service_account: '${{ inputs.service_account }}'
- token_format: 'access_token'
- # Install gcloud, `setup-gcloud` automatically picks up authentication from `auth`.
- - name: 'Set up Cloud SDK'
- uses: 'google-github-actions/setup-gcloud@e30db14379863a8c79331b04a9969f4c1e225e0b' # ratchet:google-github-actions/setup-gcloud@v1
- - name: 'Install AOD CLI'
- run: 'go install github.com/abcxyz/access-on-demand/cmd/aod@${{ inputs.aod_cli_version }}'
- - name: 'Handle cleanup'
- id: 'cleanup_tool'
- env:
- FILE_PATH: '${{ github.workspace }}/tool.yaml'
- run: |
- touch ${{ env.TOOL_ERROR_FILENAME }} ${{ env.TOOL_OUT_FILENAME }}
- aod tool cleanup -path ${{ env.FILE_PATH }} \
- 2> ${{ env.TOOL_ERROR_FILENAME }} \
- > ${{ env.TOOL_OUT_FILENAME }}
- # TODO (#79): Output only executed commands.
- - name: 'Tool Request Cleanup Comment'
- if: '${{ always() }}'
- uses: 'actions/github-script@98814c53be79b1d30f795b907e553d8679345975' # ratchet:actions/github-script@v6
- with:
- github-token: '${{ github.token }}'
- retries: '3'
- script: |+
- var body, req;
- const fs = require("fs");
- const outcome = '${{ steps.cleanup_tool.outcome }}';
- switch (outcome) {
- case 'success':
- req = fs.readFileSync(
- `${{ env.TOOL_OUT_FILENAME }}`,
- { encoding: "utf8" }
- );
-
- body = `**\`Access on Demand\`** - 🟩 **\`Tool\`** request succeeded.
-
-
- Details
- Executed "cleanup" commands in the request below, or skipped if "cleanup" commands not found.
-
- \`\`\`
- ${req}
- \`\`\`
- `;
- break;
- case 'failure':
- req = fs.readFileSync(
- `${{ env.TOOL_OUT_FILENAME }}`,
- { encoding: "utf8" }
- );
- const error = fs.readFileSync(
- `${{ env.TOOL_ERROR_FILENAME }}`,
- { encoding: "utf8" }
- );
- body = `**\`Access on Demand\`** - 🟥 **\`Tool\`** request failed.
-
-
- Details
- Failed to execute "cleanup" commands in the request below.
-
- \`\`\`
- ${req}
- \`\`\`
-
- Error:
- \`\`\`
- ${error}
- \`\`\`
- `;
- break;
- // step cancelled/skipped, should not happen if the triggering event is correct.
- default:
- // Do nothing.
- break;
- }
-
- if (typeof body !== "undefined") {
- await github.rest.issues.createComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: ${{ github.event.pull_request.number }},
- body: body,
- });
- }