Skip to content

fix(ci): repair Integration Tests, Lint, and Security Scanning on main #1794

fix(ci): repair Integration Tests, Lint, and Security Scanning on main

fix(ci): repair Integration Tests, Lint, and Security Scanning on main #1794

Workflow file for this run

name: pre-commit
on:
pull_request:
branches: [main]
push:
branches: [main]
permissions:
contents: read
jobs:
pre-commit:
name: Run pre-commit hooks
runs-on: ubuntu-latest
# 35 minutes accommodates the 3-attempt retry wrapper on the
# `Run pre-commit` step below (3 attempts * 10 min per-attempt
# timeout + 2 * 90 s retry waits = 33 min worst case) plus a
# small margin for setup/install steps. Without the bump, the
# job-level cap killed any retry attempt before it could start,
# making the retry policy ineffective (CR finding on #697).
timeout-minutes: 35
steps:
- name: Checkout code
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.13"
- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: "1.25.4"
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "24"
# Cache the npm download cache keyed on the frontend lockfile.
# Saves ~30-40s per run vs an uncached `npm ci`. Same pattern
# already used in frontend-build-sentinel.yml.
cache: "npm"
cache-dependency-path: frontend/package-lock.json
- name: Set up Terraform
# Required by the terraform_fmt + terraform_validate pre-commit hooks.
# terraform_validate calls `terraform init` per module, which the
# action wraps with HTTP-cached provider downloads.
#
# Pin must satisfy `required_version = ">= 1.10.0"` declared by every
# `terraform/environments/*/main.tf` — pinning to a sub-1.10 version
# makes init abort before validate even runs. Action major matches
# `.github/workflows/ci.yml` so both workflows resolve to the same
# Terraform binary; otherwise a behavioural drift between the two
# could pass one and fail the other.
uses: hashicorp/setup-terraform@dfe3c3f87815947d99a8997f908cb6525fc44e9e # v4.0.1
with:
terraform_version: "1.10.5"
terraform_wrapper: false
- name: Install tflint
# Pinned to a release tag (not master) so a malicious or accidental
# change to install_linux.sh on master can't silently land on this
# CI runner. `curl -fsSL` makes transport errors fail loudly
# instead of writing an HTML error page to stdin and feeding it
# to bash.
env:
TFLINT_VERSION: v0.55.0
run: |
set -euo pipefail
curl -fsSL -o /tmp/tflint-install.sh \
"https://raw.githubusercontent.com/terraform-linters/tflint/${TFLINT_VERSION}/install_linux.sh"
bash /tmp/tflint-install.sh
# Cache the installed tool binaries (gosec, gocyclo). Keyed on the
# pinned version strings so a tool-version bump still triggers a
# fresh install. Both binaries land in ~/go/bin which setup-go@v6
# already adds to PATH. Restored BEFORE the install steps so the
# `if: cache-hit != 'true'` guards below can short-circuit them on
# cache-hit runs (the `go install` invocations cost ~3-5s each
# even when the module cache is warm; skipping them on cache-hit
# is worth the extra `if`).
- name: Cache Go-installed tools (gosec, gocyclo)
id: cache-go-tools
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ~/go/bin
key: go-tools-${{ runner.os }}-gosec-v2.22.4-gocyclo-v0.6.0
- name: Install gosec
if: steps.cache-go-tools.outputs.cache-hit != 'true'
# Pinned to the same version ci.yml's `securego/gosec` Action uses,
# so an upstream gosec release with rule changes can't silently
# downgrade the gate between the two workflows.
run: go install github.com/securego/gosec/v2/cmd/gosec@v2.22.4
- name: Install gocyclo
if: steps.cache-go-tools.outputs.cache-hit != 'true'
# Pinned to match ci.yml — security tool installs must not use
# @latest; that's exactly the supply-chain weakness this PR is
# closing for Dockerfile FROMs.
run: go install github.com/fzipp/gocyclo/cmd/gocyclo@v0.6.0
- name: Install Trivy
# Pinned to v0.69.3 (the latest release with published GitHub-release
# tarballs as of writing). Tags exist for v0.58 onwards but several
# mid-range releases skipped publishing assets to the Releases page;
# the install.sh script fetches via GitHub Releases, so picking one
# of those tags makes install bail silently after detecting the
# version. v0.69.3 ships the standard `trivy_<ver>_Linux-64bit.tar.gz`
# asset.
run: |
set -eo pipefail
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh \
| sh -s -- -b /usr/local/bin v0.69.3
- name: Install git-secrets
# Pinned to a release tag rather than master HEAD. After install
# we register the AWS pattern set and ASSERT at least one pattern
# was registered — without the assert, a registration failure
# produces a patternless scanner that exits 0 unconditionally,
# leaving the gate silently downgraded.
run: |
set -euo pipefail
git clone --depth 1 --branch 1.3.0 https://github.com/awslabs/git-secrets.git /tmp/git-secrets
sudo make -C /tmp/git-secrets install
git secrets --register-aws --global
git secrets --list --global | grep -q '.' || {
echo "git-secrets registration produced no patterns — gate would be silently disabled"
exit 1
}
# Note: the hadolint-docker pre-commit hook
# (.pre-commit-config.yaml:80) runs the official
# hadolint/hadolint:v2.14.0 Docker image. We do NOT install a host
# binary here — it would be dead code (never invoked by the hook)
# AND a supply-chain hole (latest tag, no checksum). If a future
# change switches the hook from hadolint-docker to plain hadolint,
# install a pinned + sha256-verified binary here.
- name: Install pre-commit
run: pip install 'pre-commit==4.0.1'
# Cache pre-commit's per-hook environments (Go, Python, Node, etc.
# virtualenvs it builds on first run). Keyed on the hook config
# because pre-commit will rebuild any env whose pinned rev changes.
# Saves ~30-60s per cache-hit run; safe because pre-commit verifies
# env integrity on use.
- name: Cache pre-commit environments
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }}
restore-keys: |
pre-commit-${{ runner.os }}-
# Cache the Go build cache so `go vet`, `gosec`, and any other
# Go-compiling hooks reuse compiled object files instead of
# rebuilding from source. setup-go@v6 caches ~/go/pkg/mod
# (modules) but NOT ~/.cache/go-build (compiled output) — this
# step covers the latter. Keyed on go.sum so a dep upgrade still
# invalidates the cache and gets clean builds.
- name: Cache Go build cache
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ~/.cache/go-build
key: go-build-${{ runner.os }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
go-build-${{ runner.os }}-
- name: Install frontend deps
run: |
if [ -f frontend/package-lock.json ]; then
cd frontend && npm ci
fi
- name: Run pre-commit
# SKIP=terraform_validate: that hook calls `terraform init` per
# module, which creates `.terraform.lock.hcl` files. Those are
# gitignored, so on a fresh CI checkout they don't exist and the
# init step "modifies files", which pre-commit reports as a
# failure. Local pre-commit runs work because lock files persist
# between invocations. terraform_fmt and terraform_tflint still
# run and catch the syntax/style issues that terraform_validate
# would catch; the deeper schema validation runs in
# `terraform plan` during deploy workflows.
#
# GITHUB_TOKEN is passed so terraform_tflint's `tflint --init`
# step authenticates against the GitHub API (5000/hr per-token)
# when it downloads ruleset plugin releases. Without the token,
# tflint goes anonymous and hits the 60/hr per-IP limit shared
# across every workflow on the runner's NAT IP, which trips
# intermittently when PRs land in the same hour (issue #564).
#
# nick-fields/retry wraps the run with up to 3 attempts and a
# 90-second wait so transient flakes (GitHub Releases blips,
# tflint plugin download timeouts, etc.) do not require a
# manual rerun. The GITHUB_TOKEN fix above is the primary fix;
# the retry wrapper is the cheap defense-in-depth for the
# residual flakes that token alone cannot eliminate.
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
env:
SKIP: terraform_validate
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
timeout_minutes: 10
max_attempts: 3
retry_wait_seconds: 90
command: pre-commit run --all-files