Skip to content

fix(lambda): prevent recurring deployment plans (#489) #216

fix(lambda): prevent recurring deployment plans (#489)

fix(lambda): prevent recurring deployment plans (#489) #216

Workflow file for this run

---
# yamllint disable rule:comments
# yamllint disable rule:truthy
name: IaC Policy
on:
pull_request:
branches:
- main
- renovatebot
paths:
- modules/**/*.tf
- modules/**/*.tftest.hcl
- modules/**/*.tofutest.hcl
- examples/**/*.tf
- policy/**
- tests/iac/**
- tests/tofu/**
- scripts/ci_summary.py
- pyproject.toml
- uv.lock
- .github/workflows/iac-policy.yml
push:
branches:
- main
paths:
- modules/**/*.tf
- modules/**/*.tftest.hcl
- modules/**/*.tofutest.hcl
- examples/**/*.tf
- policy/**
- tests/iac/**
- tests/tofu/**
- scripts/ci_summary.py
- pyproject.toml
- uv.lock
- .github/workflows/iac-policy.yml
permissions: {} # Default deny; jobs declare only the permissions they need.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
offline-iac-contracts:
name: Offline IaC contract tests
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read # Required to checkout repository content.
issues: write # Required to create or update sticky PR summary comments.
pull-requests: write # Required to publish summaries back to pull requests.
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
with:
egress-policy: audit
- name: Checkout Repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: '3.12'
- name: Set up uv
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
with:
version: 0.11.29
- name: Run offline IaC contract tests
working-directory: tests
run: |
uv run --project .. --locked --only-group lambda-tests \
pytest -q iac --junitxml=iac-results.xml
- name: Write offline IaC contract summary
if: always()
working-directory: tests
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
python ../scripts/ci_summary.py \
--title "Offline IaC contract tests" \
--junit "Offline IaC contracts=iac-results.xml" \
--coverage coverage.xml \
--output iac-contract-summary.md \
--comment-marker forge-ci-summary:offline-iac-contracts
opentofu-tests:
name: OpenTofu module tests (${{ matrix.opentofu.name }})
runs-on: ubuntu-latest
timeout-minutes: 45
permissions:
contents: read # Required to checkout repository content.
issues: write # Required to create or update sticky PR summary comments.
pull-requests: write # Required to publish summaries back to pull requests.
strategy:
fail-fast: false
matrix:
opentofu:
- name: minimum-supported
version: 1.11.0
- name: latest-stable
version: latest
steps:
- name: Checkout Repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install OpenTofu
uses: opentofu/setup-opentofu@a1320f892987e89d278cc92dc5adc984fb93aca4 # v2.0.2
with:
tofu_version: ${{ matrix.opentofu.version }}
tofu_wrapper: false
cache: true
github_token: ${{ github.token }}
- name: Record OpenTofu version
id: tofu-version
shell: bash
run: |
set -euo pipefail
version="$(
tofu version -json \
| jq -r '.terraform_version // .tofu_version // .opentofu_version // empty'
)"
if [[ ! "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid OpenTofu version: ${version}" >&2
exit 1
fi
echo "version=${version}" >> "${GITHUB_OUTPUT}"
- name: Prepare OpenTofu plugin cache
shell: bash
run: |
set -euo pipefail
cache_dir="${RUNNER_TEMP}/tofu-plugin-cache"
mkdir -p "${cache_dir}"
echo "TF_PLUGIN_CACHE_DIR=${cache_dir}" >> "${GITHUB_ENV}"
- name: Cache OpenTofu providers
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ${{ runner.temp }}/tofu-plugin-cache
key: tofu-${{ steps.tofu-version.outputs.version }}-providers-${{ hashFiles('modules/**/*.tf') }}
restore-keys: |
tofu-${{ steps.tofu-version.outputs.version }}-providers-
tofu-providers-
- name: Install TFLint
env:
TFLINT_VERSION: 0.55.1
shell: bash
run: |
set -euo pipefail
install_dir="${HOME}/.local/bin"
mkdir -p "${install_dir}"
curl -fsSL -o /tmp/tflint.zip \
"https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/tflint_linux_amd64.zip"
unzip -oq /tmp/tflint.zip -d "${install_dir}"
chmod +x "${install_dir}/tflint"
- name: Show IaC tool versions
shell: bash
run: |
tofu version
tflint --version
- name: Discover OpenTofu test modules
shell: bash
run: |
set -euo pipefail
find modules -path '*/tests/*.tftest.hcl' -exec dirname {} \; \
| sed 's#/tests$##' \
| sort -u > .opentofu-test-modules
test -s .opentofu-test-modules
wc -l .opentofu-test-modules
- name: Check OpenTofu formatting
shell: bash
run: tofu fmt -check -recursive
- name: Initialize and validate modules
shell: bash
run: |
set -euo pipefail
while IFS= read -r module; do
echo "::group::${module}"
tofu -chdir="${module}" init -backend=false -input=false
tofu -chdir="${module}" validate -no-color
echo "::endgroup::"
done < .opentofu-test-modules
- name: Run TFLint
shell: bash
run: |
set -euo pipefail
while IFS= read -r module; do
echo "::group::${module}"
# Static .tftest.hcl contracts already enforce required_providers.
# TFLint 0.55 does not understand OpenTofu provider for_each
# references used by modules/helpers/forge_subscription.
tflint --chdir="${module}" --disable-rule=terraform_required_providers --no-color
echo "::endgroup::"
done < .opentofu-test-modules
- name: Run native OpenTofu tests
shell: bash
env:
GITHUB_TOKEN: ${{ github.token }}
OPENTOFU_NAME: ${{ matrix.opentofu.name }}
OPENTOFU_VERSION: ${{ steps.tofu-version.outputs.version }}
run: |
set -euo pipefail
summary_table="$(mktemp)"
failures=0
total=0
while IFS= read -r module; do
echo "::group::${module}"
total=$((total + 1))
log_file="${RUNNER_TEMP}/tofu-test-${total}.log"
if tofu -chdir="${module}" test -no-color > "${log_file}" 2>&1; then
result="passed"
else
result="failed"
failures=$((failures + 1))
fi
cat "${log_file}"
printf '| `%s` | %s |\n' "${module}" "${result}" >> "${summary_table}"
echo "::endgroup::"
done < .opentofu-test-modules
if (( failures == 0 )); then
result="passed"
else
result="failed"
fi
summary_file="opentofu-${OPENTOFU_NAME}-summary.md"
{
printf '## OpenTofu module tests (%s)\n\n' "${OPENTOFU_NAME}"
printf '**Result:** %s\n\n' "${result}"
printf '**OpenTofu version:** `%s`\n\n' "${OPENTOFU_VERSION}"
printf '| Metric | Count |\n'
printf '| --- | ---: |\n'
printf '| Passed modules | %s |\n' "$((total - failures))"
printf '| Failed modules | %s |\n' "${failures}"
printf '| Total modules | %s |\n\n' "${total}"
printf '| Module | Result |\n'
printf '| --- | --- |\n'
cat "${summary_table}"
printf '\n'
} > "${summary_file}"
python scripts/ci_summary.py \
--title "OpenTofu module tests (${OPENTOFU_NAME})" \
--input-markdown "${summary_file}" \
--output "${summary_file}" \
--comment-marker "forge-ci-summary:opentofu-${OPENTOFU_NAME}"
(( failures == 0 ))
opa-policy:
name: OPA/conftest tenant-isolation gate
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read # Required to checkout repository content.
issues: write # Required to create or update sticky PR summary comments.
pull-requests: write # Required to publish summaries back to pull requests.
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
with:
egress-policy: audit
- name: Checkout Repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install conftest
env:
CONFTEST_VERSION: 0.56.0
run: |
curl -fsSL -o conftest.tar.gz \
"https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz"
tar xzf conftest.tar.gz conftest
sudo install conftest /usr/local/bin/conftest
conftest --version
- name: Verify policy logic (hard gate)
id: conftest-verify
run: conftest verify --policy policy/opa
- name: Write OPA policy summary
if: always()
env:
GITHUB_TOKEN: ${{ github.token }}
VERIFY_OUTCOME: ${{ steps.conftest-verify.outcome }}
run: |
set -euo pipefail
if [[ "${VERIFY_OUTCOME}" == "success" ]]; then
result="passed"
else
result="failed"
fi
{
printf '## OPA/conftest tenant-isolation gate\n\n'
printf '**Result:** %s\n\n' "${result}"
printf '| Gate | Result |\n'
printf '| --- | --- |\n'
printf '| `conftest verify --policy policy/opa` | %s |\n\n' "${result}"
} > opa-policy-summary.md
python scripts/ci_summary.py \
--title "OPA/conftest tenant-isolation gate" \
--input-markdown opa-policy-summary.md \
--output opa-policy-summary.md \
--comment-marker forge-ci-summary:opa-policy
checkov:
name: Checkov IaC scan (informational)
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read # Required to checkout repository content.
security-events: write # Required to upload Checkov SARIF to code scanning.
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
with:
egress-policy: audit
- name: Checkout Repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: '3.12'
- name: Run Checkov (soft-fail, informational)
# Installed via pip + pinned (Renovate-managed) rather than a 3rd-party
# action SHA. Informational: never blocks the PR (continue-on-error +
# --soft-fail); findings surface in the Security tab. Flip --soft-fail
# off after triage (register follow-up).
# NOTE: --output-file-path takes the SARIF FILENAME (not a dir) in this
# checkov version; writing to '.' raises IsADirectoryError.
continue-on-error: true
run: |
pip install "checkov==3.2.334"
checkov --directory modules/ --framework terraform \
--skip-path '.*/\.terraform/.*' \
--skip-download \
--soft-fail \
--output cli --output sarif --output-file-path console,results.sarif
- name: Upload Checkov SARIF
if: always()
continue-on-error: true
uses: github/codeql-action/upload-sarif@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
with:
sarif_file: results.sarif