diff --git a/.github/labels.yaml b/.github/labels.yaml new file mode 100644 index 0000000..e961fe2 --- /dev/null +++ b/.github/labels.yaml @@ -0,0 +1,28 @@ +--- +- name: breaking + color: "b60205" + description: This change is not backwards compatible +- name: bug + color: "d93f0b" + description: Something isn't working +- name: documentation + color: "0075ca" + description: Improvements or additions to documentation +- name: enhancement + color: "0e8a16" + description: New feature or request +- name: feature + color: "0e8a16" + description: New feature or request +- name: fix + color: "d93f0b" + description: Something isn't working +- name: misc + color: "#6B93D3" + description: Miscellaneous task not covered by something else +- name: no-changelog + color: "cccccc" + description: No entry should be added to the release notes and changelog +- name: security + color: "5319e7" + description: Solving a security issue diff --git a/.github/release-drafter-config.yaml b/.github/release-drafter-config.yaml new file mode 100644 index 0000000..3d4047a --- /dev/null +++ b/.github/release-drafter-config.yaml @@ -0,0 +1,86 @@ +name-template: 'v$RESOLVED_VERSION' +tag-template: 'v$RESOLVED_VERSION' +version-template: '$MAJOR.$MINOR.$PATCH' +change-title-escapes: '\<*_&' + +categories: + - title: '๐Ÿš€ Features' + labels: + - 'breaking' + - 'enhancement' + - 'feature' + - title: '๐Ÿ› Bug Fixes' + labels: + - 'bug' + - 'fix' + - 'security' + - title: '๐Ÿ“– Documentation' + labels: + - 'documentation' + - title: '๐Ÿงบ Miscellaneous' + labels: + - 'misc' + +version-resolver: + major: + labels: + - 'breaking' + minor: + labels: + - 'enhancement' + - 'feature' + patch: + labels: + - 'bug' + - 'documentation' + - 'fix' + - 'security' + default: 'minor' + +autolabeler: + - label: 'documentation' + body: + - '/documentation/' + branch: + - '/docs\/.+/' + title: + - '/documentation/i' + - '/docs/i' + - label: 'bug' + body: + - '/bug/' + branch: + - '/bug\/.+/' + - '/fix\/.+/' + title: + - '/bug/i' + - '/fix/i' + - label: 'feature' + branch: + - '/feature\/.+/' + - '/enhancement\/.+/' + title: + - '/feature/i' + - '/feat/i' + - '/enhancement/i' + - label: 'breaking' + body: + - '/breaking/' + branch: + - '/breaking\/.+/' + title: + - '/breaking/i' + - '/major/i' + +exclude-contributors: + - 'github-actions[bot]' + +exclude-labels: + - 'no-changelog' + +template: | + # What's Changed + + $CHANGES + + **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION diff --git a/.github/workflows/label-synchronization.yaml b/.github/workflows/label-synchronization.yaml new file mode 100644 index 0000000..0c241b8 --- /dev/null +++ b/.github/workflows/label-synchronization.yaml @@ -0,0 +1,29 @@ +name: label-synchronization +on: + workflow_dispatch: + push: + branches: + - main + - master + paths: + - .github/labels.yaml + - .github/workflows/label-sync.yaml + +permissions: + # write permission is required to edit issue labels + issues: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Synchronize labels + uses: crazy-max/ghaction-github-labeler@v5 + with: + dry-run: false + github-token: ${{ secrets.GITHUB_TOKEN }} + skip-delete: false + yaml-file: .github/labels.yaml diff --git a/.github/workflows/pr-validation.yaml b/.github/workflows/pr-validation.yaml new file mode 100644 index 0000000..dbbdeae --- /dev/null +++ b/.github/workflows/pr-validation.yaml @@ -0,0 +1,104 @@ +name: "pr-validation" + +on: + pull_request: + +permissions: + checks: write + contents: read + pull-requests: write + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + autolabeler: + runs-on: ubuntu-latest + steps: + - uses: release-drafter/release-drafter@v6 + with: + config-name: release-drafter-config.yaml + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + title-checker: + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5 + id: lint_pr_title + with: + types: | + breaking + bug + docs + documentation + enhancement + feat + feature + fix + misc + security + requireScope: false + ignoreLabels: | + skip-changelog + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - uses: marocchino/sticky-pull-request-comment@v2 + # When the previous steps fails, the workflow would stop. By adding this + # condition you can continue the execution with the populated error message. + if: always() && (steps.lint_pr_title.outputs.error_message != null) + with: + header: pr-title-lint-error + message: | + Hey there and thank you for opening this pull request! ๐Ÿ‘‹๐Ÿผ + + We require pull request titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/) and it looks like your proposed title needs to be adjusted. + + Examples for valid PR titles: + feat(ui): Add button component. + fix: Correct typo. + _type(scope): subject._ + + Adding a scope is optional + + Details: + ``` + ${{ steps.lint_pr_title.outputs.error_message }} + ``` + + # Delete a previous comment when the issue has been resolved + - if: ${{ steps.lint_pr_title.outputs.error_message == null }} + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: pr-title-lint-error + delete: true + + label-checker: + needs: autolabeler + runs-on: ubuntu-latest + steps: + - uses: danielchabr/pr-labels-checker@v3.3 + id: lint_pr_labels + with: + hasSome: breaking,bug,documentation,enhancement,feature,fix,misc,security + githubToken: ${{ secrets.GITHUB_TOKEN }} + + - uses: marocchino/sticky-pull-request-comment@v2 + # When the previous steps fails, the workflow would stop. By adding this + # condition you can continue the execution with the populated error message. + if: always() && (steps.lint_pr_labels.outputs.passed == false) + with: + header: pr-labels-lint-error + message: | + Hey there and thank you for opening this pull request! ๐Ÿ‘‹๐Ÿผ + + The PR needs to have at least one of the following labels: breaking, bug, documentation, enhancement, feature, fix, misc, security. + + # Delete a previous comment when the issue has been resolved + - if: ${{ steps.lint_pr_labels.outputs.passed != false }} + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: pr-labels-lint-error + delete: true diff --git a/.github/workflows/release-drafter.yaml b/.github/workflows/release-drafter.yaml new file mode 100644 index 0000000..b5e0cc3 --- /dev/null +++ b/.github/workflows/release-drafter.yaml @@ -0,0 +1,29 @@ +name: "release-drafter" + +on: + push: + branches: + - main + - master + paths-ignore: + - .github/** + - .pre-commit-config.yaml + - CHANGELOG.md + - CONTRIBUTING.md + - LICENSE + +permissions: + # write permission is required to create a github release + contents: write + +jobs: + draft: + runs-on: ubuntu-latest + steps: + - uses: release-drafter/release-drafter@v6 + with: + publish: false + prerelease: false + config-name: release-drafter-config.yaml + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/terraform-validation.yaml b/.github/workflows/terraform-validation.yaml new file mode 100644 index 0000000..9a26a9c --- /dev/null +++ b/.github/workflows/terraform-validation.yaml @@ -0,0 +1,170 @@ +name: "terraform" + +on: + pull_request: + +permissions: + contents: write + pull-requests: write + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TF_IN_AUTOMATION: 1 + +jobs: + fmt-lint-validate: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 + + - name: Setup Terraform Linters + uses: terraform-linters/setup-tflint@v4 + with: + github_token: ${{ github.token }} + + - name: Terraform Format + id: fmt + run: terraform fmt -check -recursive + + - name: Terraform Lint + id: lint + run: | + echo "Checking ." + tflint --format compact + + for d in examples/*/; do + echo "Checking ${d} ..." + tflint --chdir=$d --format compact + done + + - name: Terraform Validate + id: validate + if: ${{ !vars.SKIP_TERRAFORM_VALIDATE }} + run: | + for d in examples/*/; do + echo "Checking ${d} ..." + terraform -chdir=$d init + terraform -chdir=$d validate -no-color + done + env: + AWS_DEFAULT_REGION: eu-west-1 + + - name: Terraform Test + id: test + if: ${{ !vars.SKIP_TERRAFORM_TESTS }} + run: | + terraform init + terraform test + + - uses: actions/github-script@v6 + if: github.event_name == 'pull_request' || always() + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + // 1. Retrieve existing bot comments for the PR + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }) + const botComment = comments.find(comment => { + return comment.user.type === 'Bot' && comment.body.includes('Terraform Format and Style') + }) + + // 2. Prepare format of the comment + const output = `#### Terraform Format and Style ๐Ÿ–Œ\`${{ steps.fmt.outcome }}\` + #### Terraform Initialization โš™๏ธ\`${{ steps.init.outcome }}\` + #### Terraform Lint ๐Ÿ“–\`${{ steps.lint.outcome }}\` + #### Terraform Validation ๐Ÿค–\`${{ steps.validate.outcome }}\` +
Validation Output + + \`\`\`\n + ${{ steps.validate.outputs.stdout }} + \`\`\` + +
`; + + // 3. If we have a comment, update it, otherwise create a new one + if (botComment) { + github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + body: output + }) + } else { + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: output + }) + } + + docs: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + + - name: Render terraform docs inside the README.md and push changes back to PR branch + uses: terraform-docs/gh-actions@v1.1.0 + with: + args: --sort-by required + git-commit-message: "docs(readme): update module usage" + git-push: true + output-file: README.md + output-method: inject + working-dir: . + continue-on-error: true # added this to prevent a PR from a remote fork failing the workflow + + tfsec: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Terraform security scan + uses: aquasecurity/tfsec-action@v1.0.3 + with: + github_token: ${{ github.token }} + soft_fail: false + tfsec_args: --concise-output --force-all-dirs + + - name: Terraform pr commenter + uses: aquasecurity/tfsec-pr-commenter-action@v1.3.1 + with: + github_token: ${{ github.token }} + tfsec_args: --concise-output --force-all-dirs + + checkov: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Run Checkov + uses: bridgecrewio/checkov-action@v12 + with: + container_user: 1000 + directory: "/" + download_external_modules: false + framework: terraform + output_format: sarif + quiet: true + skip_check: "CKV_GIT_5,CKV_GLB_1,CKV_TF_1" + soft_fail: false + skip_path: "examples/" + +### SKIP REASON ### +# Check | Description | Reason + +# CKV_GIT_5 | Ensure GitHub pull requests have at least 2 approvals | We strive for at least 1 approval +# CKV_GLB_1 | Ensure at least two approving reviews are required to merge a GitLab MR | We strive for at least 1 approval +# CKV_TF_1 | Ensure Terraform module sources use a commit hash | We think this check is too restrictive and that versioning should be preferred over commit hash diff --git a/.github/workflows/update-changelog.yaml b/.github/workflows/update-changelog.yaml new file mode 100644 index 0000000..82f347d --- /dev/null +++ b/.github/workflows/update-changelog.yaml @@ -0,0 +1,31 @@ +name: "update-changelog" + +on: + release: + types: + - published + +permissions: + contents: write + +jobs: + update: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.MCAF_GITHUB_TOKEN }} + + - name: Update Changelog + uses: stefanzweifel/changelog-updater-action@v1 + with: + latest-version: ${{ github.event.release.tag_name }} + release-notes: ${{ github.event.release.body }} + + - name: Commit updated Changelog + uses: stefanzweifel/git-auto-commit-action@v5 + with: + branch: ${{ github.event.repository.default_branch }} + commit_message: "docs(changelog): update changelog" + file_pattern: CHANGELOG.md diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..1aa6827 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,40 @@ +# .pre-commit-config.yaml +default_stages: [commit] +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-json + - id: check-merge-conflict + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - id: pretty-format-json + args: + - --autofix + - id: detect-aws-credentials + args: + - --allow-missing-credentials + - id: detect-private-key + - repo: https://github.com/antonbabenko/pre-commit-terraform + rev: v1.88.4 + hooks: + - id: terraform_fmt + - id: terraform_tflint + - id: terraform_docs + - id: terraform_validate + - repo: https://github.com/bridgecrewio/checkov.git + rev: 3.2.60 + hooks: + - id: checkov + verbose: false + args: + - --download-external-modules + - "true" + - --quiet + - --compact + - --skip-check + - CKV_GIT_5,CKV_GLB_1,CKV_TF_1 + - --skip-path + - examples/* diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a139bae --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,39 @@ +# Contributing + +## Coding Guidelines + +- The terraform language has some [style conventions](https://developer.hashicorp.com/terraform/language/syntax/style) which must be followed for consistency between files and modules written by different teams. + +## Opening a pull request + +- We require pull request titles to follow the [conventional commits specification](https://www.conventionalcommits.org/en/v1.0.0/) + +- Labels are automatically added to your PR based on certain keywords in the `title`, `body`, and `branch` . You are able to manually add or remove labels from your PR, the following labels are allowed: `breaking`, `enhancement`, `feature`, `bug`, `fix`, `security`, `documentation`. + +## Release flow + +1. Every time a PR is merged, a draft release note is created or updated to add an entry for this PR. The release version is automatically incremented based on the labels specified. + +2. When you are ready to publish the release, you can use the drafted release note to do so. `MCAF Contributors` are able to publish releases. If you are an `MCAF Contributor` and want to publish a drafted release: + - Browse to the release page + - Edit the release you want to publish (click on the pencil) + - Click `Update release` (the green button at the bottom of the page) + +If a PR should not be added to the release notes and changelog, add the label `no-changelog` to your PR. + +## Local Development + +To ease local development, [pre-commit](https://pre-commit.com/) configuration has been added to the repository. Pre-commit is useful for identifying simple issues before creating a PR: + +To use it, follow these steps: + +1. Installation: + - Using Brew: `brew install tflint` + - Using Python: `pip3 install pre-commit --upgrade` + - Using Conda: `conda install -c conda-forge pre-commit` + +2. Run the pre-commit hooks against all the files (the first time run might take a few minutes): +`pre-commit run -a` + +3. (optional) Install the pre-commit hooks to run before each commit: +`pre-commit install`