diff --git a/.github/labels.json b/.github/labels.json new file mode 100644 index 0000000..b422557 --- /dev/null +++ b/.github/labels.json @@ -0,0 +1,42 @@ +[ + { + "name": "kind/bug", + "color": "c7def8", + "description": "Categorizes issue or PR as related to a bug" + }, + { + "name": "kind/cleanup", + "color": "c7def8", + "description": "Categorizes issue or PR as related to cleaning up code, process, or technical debt" + }, + { + "name": "kind/documentation", + "color": "c7def8", + "description": "Categorizes issue or PR as related to documentation" + }, + { + "name": "kind/feature", + "color": "c7def8", + "description": "Categorizes issue or PR as related to a new feature" + }, + { + "name": "bump:major", + "color": "ef6bb4", + "description": "Attach to PR to automatically bump major version on merge" + }, + { + "name": "bump:minor", + "color": "ef6bb4", + "description": "Attach to PR to automatically bump minor version on merge" + }, + { + "name": "bump:patch", + "color": "ef6bb4", + "description": "Attach to PR to automatically bump patch version on merge" + }, + { + "name": "do-not-merge/hold", + "color": "e11d21", + "description": "Indicated that a PR is not to be merged" + } +] diff --git a/.github/renovate.json b/.github/renovate.json index f45d8f1..1cdbc81 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,5 +1,8 @@ { "extends": [ "config:base" + ], + "labels": [ + "bump:patch" ] } diff --git a/.github/workflows/depup.yml b/.github/workflows/depup.yml new file mode 100644 index 0000000..1677903 --- /dev/null +++ b/.github/workflows/depup.yml @@ -0,0 +1,36 @@ +name: depup + +on: + schedule: + - cron: '14 14 * * *' # Runs at 14:14 UTC every day + repository_dispatch: + types: [depup] + +jobs: + reviewdog: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: haya14busa/action-depup@v1 + id: depup + with: + file: Dockerfile + version_name: REVIEWDOG_VERSION + repo: reviewdog/reviewdog + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + title: "chore(deps): update reviewdog to ${{ steps.depup.outputs.latest }}" + commit-message: "chore(deps): update reviewdog to ${{ steps.depup.outputs.latest }}" + body: | + Update reviewdog to [v${{ steps.depup.outputs.latest }}](https://github.com/reviewdog/reviewdog/releases/tag/v${{ steps.depup.outputs.latest }}) + Compare [v${{ steps.depup.outputs.current }}...v${{ steps.depup.outputs.latest }}](https://github.com/reviewdog/reviewdog/compare/v${{ steps.depup.outputs.current }}...v${{ steps.depup.outputs.latest }}) + + This PR is auto generated by [depup workflow](https://github.com/${{ github.repository }}/actions?query=workflow%3Adepup). + branch: depup/reviewdog + base: master + labels: "bump:minor" \ No newline at end of file diff --git a/.github/workflows/dockerimage.yml b/.github/workflows/dockerimage.yml index 9108733..e70018a 100644 --- a/.github/workflows/dockerimage.yml +++ b/.github/workflows/dockerimage.yml @@ -1,6 +1,10 @@ name: Docker Image CI -on: [push] +on: + push: + branches: + - master + pull_request: jobs: @@ -11,8 +15,6 @@ jobs: steps: - name: Clone repo uses: actions/checkout@master - with: - fetch-depth: 1 - name: Build the Docker image - run: docker build . --file Dockerfile --tag tfsec:$(date +%s) + run: docker build . --file Dockerfile --tag $( echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]' ):$(date +%s) diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml new file mode 100644 index 0000000..cd7a182 --- /dev/null +++ b/.github/workflows/labels.yml @@ -0,0 +1,23 @@ +name: Labels + +on: + push: + paths: + - .github/labels.json + - .github/workflows/labels.yml + branches: + - master + +jobs: + Manage: + name: Manage GitHub labels + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@master + + - name: Manage labels + uses: lannonbr/issue-label-manager-action@2.0.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..187dddb --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,49 @@ +name: release + +on: + push: + branches: + - master + tags: + - 'v*.*.*' + +jobs: + release: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + # Bump version on merging Pull Requests with specific labels. + # (bump:major,bump:minor,bump:patch) + - id: bumpr + if: "!startsWith(github.ref, 'refs/tags/')" + uses: haya14busa/action-bumpr@v1 + + # Update corresponding major and minor tag. + # e.g. Update v1 and v1.2 when releasing v1.2.3 + - uses: haya14busa/action-update-semver@v1 + if: "!steps.bumpr.outputs.skip" + with: + tag: ${{ steps.bumpr.outputs.next_version }} + + # Get tag name. + - id: tag + uses: haya14busa/action-cond@v1 + with: + cond: "${{ startsWith(github.ref, 'refs/tags/') }}" + if_true: ${{ github.ref }} + if_false: ${{ steps.bumpr.outputs.next_version }} + + # Create release. + - uses: actions/create-release@v1 + if: "steps.tag.outputs.value != ''" + env: + # This token is provided by Actions, you do not need to create your own token + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.tag.outputs.value }} + release_name: Release ${{ steps.tag.outputs.value }} + body: ${{ steps.bumpr.outputs.message }} + draft: false + prerelease: false diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml new file mode 100644 index 0000000..84e523f --- /dev/null +++ b/.github/workflows/reviewdog.yml @@ -0,0 +1,62 @@ +name: reviewdog + +on: + push: + branches: + - master + pull_request: + +jobs: + shellcheck: + name: runner / shellcheck + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: haya14busa/action-cond@v1 + id: reporter + with: + cond: ${{ github.event_name == 'pull_request' }} + if_true: "github-pr-review" + if_false: "github-check" + + - uses: reviewdog/action-shellcheck@v1 + with: + github_token: ${{ secrets.github_token }} + reporter: ${{ steps.reporter.outputs.value }} + level: warning + + hadolint: + name: runner / hadolint + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: haya14busa/action-cond@v1 + id: reporter + with: + cond: ${{ github.event_name == 'pull_request' }} + if_true: "github-pr-review" + if_false: "github-check" + + - uses: reviewdog/action-hadolint@v1 + with: + github_token: ${{ secrets.github_token }} + reporter: ${{ steps.reporter.outputs.value }} + level: warning + + misspell: + name: runner / misspell + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: reviewdog/action-misspell@v1 + with: + github_token: ${{ secrets.github_token }} + reporter: github-check + level: warning + locale: "US" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..9151147 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,123 @@ +name: Test + +on: + push: + branches: + - master + pull_request: + +jobs: + test-check: + name: runner / tfsec (github-check) + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: ./ + continue-on-error: true + id: test + with: + github_token: ${{ secrets.github_token }} + reporter: github-check + level: info + working_directory: testdata + + # The check is expected to fail on the test data + - name: Check return codes + if: success() || failure () + run: | + tfsec_return="${{ steps.test.outputs.tfsec-return-code }}" + reviewdog_return="${{ steps.test.outputs.reviewdog-return-code }}" + + if [ "$tfsec_return" -eq 1 ]; then + echo "tfsec correctly returned failure ${tfsec_return}" + else + echo "tfsec returned ${tfsec_return}, expected '1'. Failing..." + exit 1 + fi + + if [ "$reviewdog_return" -eq 0 ]; then + echo "reviewdog correctly returned success: ${reviewdog_return}" + else + echo "reviewdog returned ${reviewdog_return}, expected '0'. Failing..." + exit 1 + fi + + test-pr-check: + if: github.event_name == 'pull_request' + name: runner / tfsec (github-pr-check) + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: ./ + continue-on-error: true + id: test + with: + github_token: ${{ secrets.github_token }} + reporter: github-pr-check + level: info + working_directory: testdata + + # The check is expected to fail on the test data + - name: Check return codes + if: success() || failure () + run: | + tfsec_return="${{ steps.test.outputs.tfsec-return-code }}" + reviewdog_return="${{ steps.test.outputs.reviewdog-return-code }}" + + if [ "$tfsec_return" -eq 1 ]; then + echo "tfsec correctly returned failure ${tfsec_return}" + else + echo "tfsec returned ${tfsec_return}, expected '1'. Failing..." + exit 1 + fi + + if [ "$reviewdog_return" -eq 0 ]; then + echo "reviewdog correctly returned success: ${reviewdog_return}" + else + echo "reviewdog returned ${reviewdog_return}, expected '0'. Failing..." + exit 1 + fi + + test-pr-review: + if: github.event_name == 'pull_request' + name: runner / tfsec (github-pr-review) + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: ./ + continue-on-error: true + id: test + with: + github_token: ${{ secrets.github_token }} + reporter: github-pr-review + level: info + working_directory: testdata + + # The check is expected to fail on the test data + # but for forked PRs reviewdog will just output + # on the PR and report success + - name: Check return codes + if: success() || failure () + run: | + tfsec_return="${{ steps.test.outputs.tfsec-return-code }}" + reviewdog_return="${{ steps.test.outputs.reviewdog-return-code }}" + + if [ "$tfsec_return" -eq 1 ]; then + echo "tfsec correctly returned failure ${tfsec_return}" + else + echo "tfsec returned ${tfsec_return}, expected '1'. Failing..." + exit 1 + fi + + if [ "$reviewdog_return" -eq 0 ]; then + echo "reviewdog correctly returned failure: ${reviewdog_return}" + else + echo "reviewdog returned ${reviewdog_return}, expected '0'. Failing..." + exit 1 + fi diff --git a/Dockerfile b/Dockerfile index eb1e381..9bd68e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,16 @@ FROM alpine:3.11 -RUN apk --no-cache --update add git curl \ +ENV REVIEWDOG_VERSION=v0.9.17 + +# hadolint ignore=DL3018 +RUN apk --no-cache --update add bash git \ && rm -rf /var/cache/apk/* +SHELL ["/bin/bash", "-eo", "pipefail", "-c"] + RUN wget -O - -q https://raw.githubusercontent.com/reviewdog/reviewdog/master/install.sh | sh -s -- -b /usr/local/bin/ -RUN curl -L "$(curl -s https://api.github.com/repos/liamg/tfsec/releases/latest | grep -o -E "https://.+?-linux-amd64")" > tfsec \ +RUN wget -O - -q "$(wget -q https://api.github.com/repos/liamg/tfsec/releases/latest -O - | grep -o -E "https://.+?-linux-amd64")" > tfsec \ && install tfsec /usr/local/bin/ COPY entrypoint.sh /entrypoint.sh diff --git a/README.md b/README.md index d0b69ad..3040902 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,12 @@ # GitHub Action: Run tfsec with reviewdog +[![Test](https://github.com/reviewdog/action-tfsec/workflows/Test/badge.svg)](https://github.com/reviewdog/action-tfsec/actions?query=workflow%3ATest) +[![reviewdog](https://github.com/reviewdog/action-tfsec/workflows/reviewdog/badge.svg)](https://github.com/reviewdog/action-tfsec/actions?query=workflow%3Areviewdog) +[![depup](https://github.com/reviewdog/action-tfsec/workflows/depup/badge.svg)](https://github.com/reviewdog/action-tfsec/actions?query=workflow%3Adepup) +[![release](https://github.com/reviewdog/action-tfsec/workflows/release/badge.svg)](https://github.com/reviewdog/action-tfsec/actions?query=workflow%3Arelease) +[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/reviewdog/action-tfsec?logo=github&sort=semver)](https://github.com/reviewdog/action-tfsec/releases) +[![action-bumpr supported](https://img.shields.io/badge/bumpr-supported-ff69b4?logo=github&link=https://github.com/haya14busa/action-bumpr)](https://github.com/haya14busa/action-bumpr) + This action runs [tfsec](https://github.com/liamg/tfsec) with [reviewdog](https://github.com/reviewdog/reviewdog) on pull requests to enforce best practices. @@ -37,12 +44,27 @@ The default is `error`. Optional. Reporter of reviewdog command [`github-pr-check`,`github-pr-review`]. The default is `github-pr-check`. +### `working_directory` + +Optional. Directory to run the action on, from the repo root. +The default is `.` ( root of the repository). + ### `flags` Optional. List of arguments to send to tfsec. For the output to be parsable by reviewdog [`--format=checkstyle` is enforced](./entrypoint.sh). The default is ``. +## Outputs + +## `tfsec-return-code` + +The `tfsec` command return code. + +## `reviewdog-return-code` + +The `reviewdog` command return code. + ## Example usage ```yml @@ -61,6 +83,35 @@ jobs: uses: reviewdog/action-tfsec@master with: github_token: ${{ secrets.github_token }} + working_directory: "testdata" # Change working directory reporter: github-pr-review # Change reporter flags: "" # Optional ``` + +## Development + +### Release + +#### [haya14busa/action-bumpr](https://github.com/haya14busa/action-bumpr) +You can bump version on merging Pull Requests with specific labels (bump:major,bump:minor,bump:patch). +Pushing tag manually by yourself also work. + +#### [haya14busa/action-update-semver](https://github.com/haya14busa/action-update-semver) + +This action updates major/minor release tags on a tag push. e.g. Update v1 and v1.2 tag when released v1.2.3. +ref: https://help.github.com/en/articles/about-actions#versioning-your-action + +### Lint - reviewdog integration + +This reviewdog action template itself is integrated with reviewdog to run lints +which is useful for Docker container based actions. + +Supported linters: + +- [reviewdog/action-shellcheck](https://github.com/reviewdog/action-shellcheck) +- [reviewdog/action-hadolint](https://github.com/reviewdog/action-hadolint) +- [reviewdog/action-misspell](https://github.com/reviewdog/action-misspell) + +### Dependencies Update Automation +This repository uses [haya14busa/action-depup](https://github.com/haya14busa/action-depup) to update +reviewdog version. diff --git a/action.yml b/action.yml index e13c8b2..1242db5 100644 --- a/action.yml +++ b/action.yml @@ -14,12 +14,24 @@ inputs: Reporter of reviewdog command [github-pr-check,github-pr-review]. Default is github-pr-check. default: 'github-pr-check' + working_directory: + description: | + Directory to run the action on, from the repo root. + Default is . ( root of the repository) + default: '.' flags: description: | List of arguments to send to tfsec For the output to be parsable by reviewdog --format=checkstyle is enforced Default is blank. default: '' + +outputs: + tfsec-return-code: + description: 'tfsec command return code' + reviewdog-return-code: + description: 'reviewdog command return code' + runs: using: 'docker' image: 'Dockerfile' @@ -27,6 +39,7 @@ runs: - ${{ inputs.github_token }} - ${{ inputs.level }} - ${{ inputs.reporter }} + - ${{ inputs.working_directory }} - ${{ inputs.flags }} branding: icon: 'edit' diff --git a/entrypoint.sh b/entrypoint.sh index af79db6..2124a24 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,8 +1,17 @@ -#!/bin/sh +#!/bin/bash -cd "$GITHUB_WORKSPACE" +if [ -n "${GITHUB_WORKSPACE}" ]; then + cd "${GITHUB_WORKSPACE}" || exit +fi export REVIEWDOG_GITHUB_API_TOKEN="${INPUT_GITHUB_TOKEN}" -tfsec --format=checkstyle ${INPUT_FLAGS} \ +tfsec --format=checkstyle ${INPUT_FLAGS} "${INPUT_WORKING_DIRECTORY}" \ | reviewdog -f=checkstyle -name="tfsec" -reporter="${INPUT_REPORTER}" -level="${INPUT_LEVEL}" + +tfsec_return="${PIPESTATUS[0]}" reviewdog_return="${PIPESTATUS[1]}" exit_code=$? + +echo ::set-output name=tfsec-return-code::"${tfsec_return}" +echo ::set-output name=reviewdog-return-code::"${reviewdog_return}" + +exit $exit_code diff --git a/testdata/example.tf b/testdata/example.tf new file mode 100644 index 0000000..b1cef17 --- /dev/null +++ b/testdata/example.tf @@ -0,0 +1,19 @@ +resource "aws_security_group_rule" "my-rule" { + type = "ingress" + cidr_blocks = ["0.0.0.0/0"] +} + +resource "aws_alb_listener" "my-alb-listener"{ + port = "80" + protocol = "HTTP" +} + +resource "aws_db_security_group" "my-group" { + +} + +resource "azurerm_managed_disk" "source" { + encryption_settings { + enabled = false + } +}