# yaml-language-server: $schema=https://json.schemastore.org/github-action.json # permissions: # - contents: write # Required for committing fixes # - security-events: write # Required for uploading SARIF reports --- name: Terraform Lint and Fix description: 'Lints and fixes Terraform files with advanced validation and security checks.' author: 'Ismo Vuorinen' branding: icon: server color: green inputs: terraform-version: description: 'Terraform version to use' required: false default: 'latest' tflint-version: description: 'TFLint version to use' required: false default: 'latest' working-directory: description: 'Directory containing Terraform files' required: false default: '.' config-file: description: 'Path to TFLint config file' required: false default: '.tflint.hcl' fail-on-error: description: 'Fail workflow if issues are found' required: false default: 'true' auto-fix: description: 'Automatically fix issues when possible' required: false default: 'true' max-retries: description: 'Maximum number of retry attempts' required: false default: '3' format: description: 'Output format (compact, json, checkstyle, junit, sarif)' required: false default: 'sarif' token: description: 'GitHub token for authentication' required: false default: '' username: description: 'GitHub username for commits' required: false default: 'github-actions' email: description: 'GitHub email for commits' required: false default: 'github-actions@github.com' outputs: error-count: description: 'Number of errors found' value: ${{ steps.lint.outputs.error_count }} fixed-count: description: 'Number of issues fixed' value: ${{ steps.fix.outputs.fixed_count }} sarif-file: description: 'Path to SARIF report file' value: ${{ steps.lint.outputs.sarif_file }} runs: using: composite steps: - name: Checkout Repository uses: actions/checkout@71cf2267d89c5cb81562390fa70a37fa40b1305e # v6-beta with: token: ${{ inputs.token || github.token }} - name: Validate Inputs id: validate uses: ivuorinen/actions/validate-inputs@5cc7373a22402ee8985376bc713f00e09b5b2edb with: action-type: 'terraform-lint-fix' token: ${{ inputs.token || github.token }} email: ${{ inputs.email }} username: ${{ inputs.username }} terraform-version: ${{ inputs.terraform-version }} tflint-version: ${{ inputs.tflint-version }} max-retries: ${{ inputs.max-retries }} - name: Write Validated Inputs to Environment shell: sh env: INPUT_WORKING_DIR: ${{ inputs.working-directory }} INPUT_CONFIG: ${{ inputs.config-file }} INPUT_FORMAT: ${{ inputs.format }} INPUT_FAIL: ${{ inputs.fail-on-error }} INPUT_RETRIES: ${{ inputs.max-retries }} run: | set -eu # Write validated inputs to GITHUB_ENV for safe use in shell contexts { echo "VALIDATED_WORKING_DIR=$INPUT_WORKING_DIR" echo "VALIDATED_CONFIG=$INPUT_CONFIG" echo "VALIDATED_FORMAT=$INPUT_FORMAT" echo "VALIDATED_FAIL=$INPUT_FAIL" echo "VALIDATED_RETRIES=$INPUT_RETRIES" } >> "$GITHUB_ENV" - name: Check for Terraform Files id: check-files shell: sh run: | set -eu # Use validated environment variable WORKING_DIRECTORY="$VALIDATED_WORKING_DIR" cd "$WORKING_DIRECTORY" # Check for Terraform files if ! find . -name "*.tf" -o -name "*.tfvars" | grep -q .; then echo "No Terraform files found. Skipping lint and fix." printf '%s\n' "found=false" >> "$GITHUB_OUTPUT" exit 0 fi printf '%s\n' "found=true" >> "$GITHUB_OUTPUT" - name: Setup Terraform if: steps.check-files.outputs.found == 'true' uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2 with: terraform_version: ${{ inputs.terraform-version }} terraform_wrapper: false - name: Validate Terraform Syntax if: steps.check-files.outputs.found == 'true' shell: sh run: | set -eu echo "Validating Terraform file syntax..." for file in $(find . -name "*.tf" -o -name "*.tfvars"); do if ! terraform fmt -check=true "$file" >/dev/null 2>&1; then echo "::warning::Invalid Terraform syntax in $file" fi done - name: Setup TFLint if: steps.check-files.outputs.found == 'true' uses: terraform-linters/setup-tflint@4cb9feea73331a35b422df102992a03a44a3bb33 # v6.2.1 with: tflint_version: ${{ inputs.tflint-version }} - name: Initialize TFLint if: steps.check-files.outputs.found == 'true' shell: sh run: | set -eu # Initialize TFLint plugins tflint --init - name: Configure TFLint if: steps.check-files.outputs.found == 'true' shell: sh run: | set -eu # Use validated environment variable CONFIG_FILE="$VALIDATED_CONFIG" # Create default config if none exists if [ ! -f "$CONFIG_FILE" ]; then cat > "$CONFIG_FILE" < "$tflint_output"; then error_count=$(grep -c "level\": \"error\"" "$tflint_output" || echo 0) printf '%s\n' "error_count=$error_count" >> "$GITHUB_OUTPUT" if [ "$FAIL_ON_ERROR" = "true" ]; then echo "::error::Found $error_count linting errors" exit 1 fi fi printf '%s\n' "sarif_file=$tflint_output" >> "$GITHUB_OUTPUT" - name: Run Terraform Format if: steps.check-files.outputs.found == 'true' && inputs.auto-fix == 'true' id: fix shell: sh run: | set -eu # Use validated environment variable WORKING_DIRECTORY="$VALIDATED_WORKING_DIR" cd "$WORKING_DIRECTORY" # Track fixed files fixed_count=0 # Format Terraform files for file in $(find . -name "*.tf" -o -name "*.tfvars"); do if ! terraform fmt -check "$file" >/dev/null 2>&1; then terraform fmt "$file" fixed_count=$((fixed_count + 1)) fi done printf '%s\n' "fixed_count=$fixed_count" >> "$GITHUB_OUTPUT" - name: Commit Fixes if: steps.check-files.outputs.found == 'true' && inputs.auto-fix == 'true' && fromJSON(steps.fix.outputs.fixed_count) > 0 uses: stefanzweifel/git-auto-commit-action@28e16e81777b558cc906c8750092100bbb34c5e3 # v7.0.0 with: commit_message: 'style: apply terraform formatting fixes' commit_user_name: ${{ inputs.username }} commit_user_email: ${{ inputs.email }} file_pattern: '*.tf *.tfvars' - name: Upload SARIF Report if: steps.check-files.outputs.found == 'true' && inputs.format == 'sarif' uses: github/codeql-action/upload-sarif@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7 with: sarif_file: ${{ env.VALIDATED_WORKING_DIR }}/reports/tflint.sarif category: terraform-lint - name: Cleanup if: always() shell: sh run: |- set -eu # Remove temporary files rm -rf .terraform/ rm -rf reports/ # Clean up TFLint cache rm -rf ~/.tflint.d/