-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
70 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,10 +2,11 @@ | |
GitHub Action to check whether the plan generated by terraform plan complies with governance rules on aiven terraform provider resources. | ||
|
||
# How it works | ||
When a pull request is opened, the action will generate the plan using `terraform plan` and analyze the output to see | ||
whether the user requesting the change is is a member of the owner group and whether the pull request has been approved by a member of the owner group. | ||
This action checks the generated plan whether the external user requesting the change is owner of the resource and whether the change has been approved by one of the resource owners and outputs a report in JSON format regadring any compliance errors that it finds. | ||
|
||
For example: | ||
The program only considers resources with explicitly set owners. Right now, the only resource that supports having owner is the `aiven_kafka_topic` resource by using the optional `owner_user_group_id` configuration. | ||
|
||
Example output: | ||
```json | ||
{ | ||
"ok": false, | ||
|
@@ -25,17 +26,20 @@ For example: | |
|
||
# Setup | ||
Here is how to set it up for your repository: | ||
1. For the action to understand who is who, you'll need to map the github login username to aiven internal user using the `aiven_external_identity` data resource. For example: | ||
1. Map the external user to aiven internal user by adding `aiven_external_identity` data resource in your terraform configuration. In this case, we are using service `github`, which refers to the github login name. For example: | ||
``` | ||
data "aiven_external_identity" "foo" { | ||
organization_id = data.aiven_organization_user.organization_id, | ||
internal_user_id = data.aiven_organization_user.user_id, | ||
external_user_id = "github-username", | ||
internal_user_id = data.aiven_organization_user.alice.user_id, | ||
external_user_id = "github-login-name", | ||
external_service_name = "github" | ||
} | ||
``` | ||
|
||
2. The action only considers topics with owner, which you can define using `aiven_kafka_topic.owner_user_group_id`. For example: | ||
**Note:** | ||
`aiven_external_identity` is currently in Beta. To use it in your configuration, you'll need have `PROVIDER_AIVEN_ENABLE_BETA: 1` set when running terraform commands. | ||
|
||
2. The action only considers topics with explicitly set owner which you can define using `aiven_kafka_topic.owner_user_group_id`. For example: | ||
``` | ||
resource "aiven_kafka_topic" "foo" { | ||
topic_name = "foo" | ||
|
@@ -44,9 +48,11 @@ resource "aiven_kafka_topic" "foo" { | |
} | ||
``` | ||
|
||
3. Finally, use the github action in your `.github/workflows`. For example: | ||
3. Finally, create customized workflow around the action in your `.github/workflows` that suits your environment. | ||
|
||
For example, this workflow gets the pull request requester and approvers from the pull request and uses this action to check the plan compliance during pull request reviews: | ||
```yaml | ||
name: 'Aiven Terraform Governance Compliance Check' | ||
name: 'Check plan' | ||
|
||
on: | ||
pull_request: | ||
|
@@ -59,25 +65,64 @@ on: | |
|
||
pull_request_review: | ||
types: [submitted, dismissed, edited] | ||
|
||
jobs: | ||
aiven_terraform_governance_compliance_check: | ||
check: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: "Aiven Terraform Governance Compliance Check Test" | ||
id: "compliance-check" | ||
uses: aiven/aiven_terraform_governance_compliance_check | ||
with: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
AIVEN_API_TOKEN: ${{ secrets.AIVEN_API_TOKEN }} | ||
- run: | | ||
if [ $(echo ${{ steps.compliance-check.outputs.result }} | jq '.ok') == "true" ] | ||
then | ||
echo "OK" | ||
else | ||
echo $RESULT | jq | ||
exit 1 | ||
fi | ||
- name: "Checkout branch" | ||
uses: actions/checkout@v4 | ||
|
||
- name: "Pull request reviewers" | ||
id: pull_request_reviewers | ||
uses: octokit/[email protected] | ||
with: | ||
route: GET /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
- name: "Pull request approvers" | ||
id: "pull_request_approvers" | ||
run: | | ||
APPROVERS=$( | ||
echo '${{ steps.pull_request_reviewers.outputs.data }}' | jq '[.[] | select(.state == "APPROVED") | .user.login] | unique | @csv' | ||
) | ||
echo "approvers=$APPROVERS" >> "$GITHUB_OUTPUT" | ||
shell: bash | ||
|
||
- name: "Setup terraform" | ||
uses: hashicorp/setup-terraform@v3 | ||
|
||
- name: "Terraform plan" | ||
env: | ||
AIVEN_WEB_URL: ${{ secrets.AIVEN_WEB_URL }} | ||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }} | ||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY }} | ||
PROVIDER_AIVEN_ENABLE_BETA: 1 | ||
run: | | ||
terraform init | ||
terraform state pull | ||
terraform plan -out=./plan -var="aiven_api_token=${{ secrets.AIVEN_API_TOKEN }}" | ||
terraform show -json ./plan > ./plan.json | ||
shell: bash | ||
|
||
- name: "Run compliance check" | ||
id: "governance" | ||
uses: aiven/aiven-terraform-governance-compliance-checker@b9a4c2a80e2a9b4dc6809f6214909a27d8a8b5a5 | ||
with: | ||
requester: ${{ github.event.pull_request.user.login }} | ||
approvers: ${{ steps.pull_request_approvers.outputs.approvers }} | ||
plan: "./plan.json" | ||
|
||
- name: "Handle results" | ||
run: | | ||
if [ $(echo '${{ steps.governance.outputs.result }}' | jq '.ok') == "true" ] | ||
then | ||
echo "✅" | ||
else | ||
echo '${{ steps.governance.outputs.result }}' | jq | ||
exit 1 | ||
fi | ||
``` | ||