mirror of
https://github.com/ivuorinen/actions.git
synced 2026-01-26 03:23:59 +00:00
322 lines
9.6 KiB
YAML
322 lines
9.6 KiB
YAML
# 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
with:
|
|
token: ${{ inputs.token || github.token }}
|
|
|
|
- name: Validate Inputs
|
|
id: validate
|
|
uses: ivuorinen/actions/validate-inputs@7061aafd35a2f21b57653e34f2b634b2a19334a9
|
|
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: bash
|
|
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 -euo pipefail
|
|
# 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: bash
|
|
run: |
|
|
set -euo pipefail
|
|
# 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."
|
|
echo "found=false" >> $GITHUB_OUTPUT
|
|
exit 0
|
|
fi
|
|
|
|
echo "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: bash
|
|
run: |
|
|
set -euo pipefail
|
|
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: Install TFLint
|
|
if: steps.check-files.outputs.found == 'true'
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
# Use validated environment variable
|
|
MAX_RETRIES="$VALIDATED_RETRIES"
|
|
|
|
# Function to install TFLint with retries
|
|
install_tflint() {
|
|
local attempt=1
|
|
local max_attempts="$MAX_RETRIES"
|
|
|
|
while [ $attempt -le $max_attempts ]; do
|
|
echo "Installing TFLint (Attempt $attempt of $max_attempts)"
|
|
|
|
if curl -sSL "https://raw.githubusercontent.com/terraform-linters/tflint/master/install_linux.sh" | bash; then
|
|
echo "TFLint installed successfully"
|
|
return 0
|
|
fi
|
|
|
|
attempt=$((attempt + 1))
|
|
if [ $attempt -le $max_attempts ]; then
|
|
echo "Installation failed, waiting 10 seconds before retry..."
|
|
sleep 10
|
|
fi
|
|
done
|
|
|
|
echo "::error::Failed to install TFLint after $max_attempts attempts"
|
|
return 1
|
|
}
|
|
|
|
install_tflint
|
|
|
|
# Initialize TFLint plugins
|
|
tflint --init
|
|
|
|
- name: Configure TFLint
|
|
if: steps.check-files.outputs.found == 'true'
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
# Use validated environment variable
|
|
CONFIG_FILE="$VALIDATED_CONFIG"
|
|
|
|
# Create default config if none exists
|
|
if [ ! -f "$CONFIG_FILE" ]; then
|
|
cat > "$CONFIG_FILE" <<EOF
|
|
plugin "aws" {
|
|
enabled = true
|
|
version = "latest"
|
|
source = "github.com/terraform-linters/tflint-ruleset-aws"
|
|
}
|
|
|
|
config {
|
|
module = true
|
|
force = false
|
|
disabled_by_default = false
|
|
}
|
|
EOF
|
|
fi
|
|
|
|
# Validate config
|
|
tflint --config "$CONFIG_FILE" --validate
|
|
|
|
- name: Run TFLint
|
|
if: steps.check-files.outputs.found == 'true'
|
|
id: lint
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
# Use validated environment variables
|
|
WORKING_DIRECTORY="$VALIDATED_WORKING_DIR"
|
|
CONFIG_FILE="$VALIDATED_CONFIG"
|
|
FORMAT="$VALIDATED_FORMAT"
|
|
FAIL_ON_ERROR="$VALIDATED_FAIL"
|
|
|
|
cd "$WORKING_DIRECTORY"
|
|
|
|
# Create reports directory
|
|
mkdir -p reports
|
|
|
|
# Run TFLint with configured format
|
|
tflint_output="reports/tflint.$FORMAT"
|
|
if ! tflint --config "$CONFIG_FILE" \
|
|
--format "$FORMAT" \
|
|
--no-color \
|
|
. > "$tflint_output"; then
|
|
error_count=$(grep -c "level\": \"error\"" "$tflint_output" || echo 0)
|
|
echo "error_count=$error_count" >> $GITHUB_OUTPUT
|
|
|
|
if [[ "$FAIL_ON_ERROR" == "true" ]]; then
|
|
echo "::error::Found $error_count linting errors"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
echo "sarif_file=$tflint_output" >> $GITHUB_OUTPUT
|
|
|
|
- name: Run Terraform Format
|
|
if: steps.check-files.outputs.found == 'true' && inputs.auto-fix == 'true'
|
|
id: fix
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
# 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
|
|
|
|
echo "fixed_count=$fixed_count" >> $GITHUB_OUTPUT
|
|
|
|
- name: Set Git Config for Fixes
|
|
if: ${{ fromJSON(steps.fix.outputs.fixed_count) > 0 }}
|
|
uses: ivuorinen/actions/set-git-config@7061aafd35a2f21b57653e34f2b634b2a19334a9
|
|
with:
|
|
token: ${{ inputs.token || github.token }}
|
|
username: ${{ inputs.username }}
|
|
email: ${{ inputs.email }}
|
|
|
|
- name: Commit Fixes
|
|
if: ${{ fromJSON(steps.fix.outputs.fixed_count) > 0 }}
|
|
shell: bash
|
|
env:
|
|
FIXED_COUNT: ${{ steps.fix.outputs.fixed_count }}
|
|
run: |
|
|
set -euo pipefail
|
|
# Use validated environment variable and output
|
|
WORKING_DIRECTORY="$VALIDATED_WORKING_DIR"
|
|
|
|
cd "$WORKING_DIRECTORY"
|
|
|
|
if git diff --quiet; then
|
|
echo "No changes to commit."
|
|
else
|
|
git add .
|
|
git commit -m "fix: applied terraform formatting fixes to $FIXED_COUNT files"
|
|
git push || {
|
|
echo "Push failed, pulling latest changes..."
|
|
git pull --rebase
|
|
git push
|
|
}
|
|
fi
|
|
|
|
- name: Upload SARIF Report
|
|
if: steps.check-files.outputs.found == 'true' && inputs.format == 'sarif'
|
|
uses: github/codeql-action/upload-sarif@16140ae1a102900babc80a33c44059580f687047 # v4.30.9
|
|
with:
|
|
sarif_file: ${{ env.VALIDATED_WORKING_DIR }}/reports/tflint.sarif
|
|
category: terraform-lint
|
|
|
|
- name: Cleanup
|
|
if: always()
|
|
shell: bash
|
|
run: |-
|
|
set -euo pipefail
|
|
|
|
# Remove temporary files
|
|
rm -rf .terraform/
|
|
rm -rf reports/
|
|
|
|
# Clean up TFLint cache
|
|
rm -rf ~/.tflint.d/
|