Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .github/workflows/terraform-parallel-install-stress-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: "Stress test parallel installs - Terraform"
on:
pull_request:
paths:
- 'src/terraform/**'
workflow_dispatch:

jobs:
test:
strategy:
matrix:
test-pass: [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250 ]
fail-fast: false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- name: "Install latest devcontainer CLI"
run: npm install -g @devcontainers/cli

- name: "Stress test 'terraform' install with default settings (pass ${{ matrix.test-pass }})"
run: devcontainer features test -f terraform --skip-scenarios .
78 changes: 54 additions & 24 deletions src/terraform/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ INSTALL_SENTINEL=${INSTALLSENTINEL:-false}
INSTALL_TFSEC=${INSTALLTFSEC:-false}
INSTALL_TERRAFORM_DOCS=${INSTALLTERRAFORMDOCS:-false}
CUSTOM_DOWNLOAD_SERVER="${CUSTOMDOWNLOADSERVER:-""}"
# This is because ubuntu noble, ubuntu resolute and debian trixie don't support the old format of GPG keys and validation
NEW_GPG_CODENAMES="trixie noble resolute"
# This is because ubuntu noble and debian trixie don't support the old format of GPG keys and validation
NEW_GPG_CODENAMES="trixie noble"

TERRAFORM_SHA256="${TERRAFORM_SHA256:-"automatic"}"
TFLINT_SHA256="${TFLINT_SHA256:-"automatic"}"
Expand Down Expand Up @@ -52,7 +52,7 @@ if [ "$(id -u)" -ne 0 ]; then
exit 1
fi

# Detect Ubuntu Noble, Ubuntu Resolute or Debian Trixie and use new repo setup, else use legacy GPG logic
# Detect Ubuntu Noble or Debian Trixie and use new repo setup, else use legacy GPG logic
IS_GPG_NEW=0
. /etc/os-release
if [[ "${NEW_GPG_CODENAMES}" == *"${VERSION_CODENAME}"* ]]; then
Expand Down Expand Up @@ -249,7 +249,7 @@ find_sentinel_version_from_url() {
if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then
local prefix='sentinel_'
local regex="${prefix}\d.\d{2}.\d(?:-\w*)?"
local version_list="$(wget -q $2 -O - | grep -oP ${regex} | sed "s/^${prefix}//" | sort -rV)"
local version_list="$(wget -q $2 -O - | grep -oP ${regex} | tr -d ${prefix} | sort -rV)"
if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then
declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)"
else
Expand Down Expand Up @@ -460,6 +460,23 @@ install_tflint() {
curl -sSL -o /tmp/tf-downloads/${TFLINT_FILENAME} https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/${TFLINT_FILENAME}
}

verify_tflint_attestations() {
local checksums=$1
local checksums_sha256=$(sha256sum "$checksums" | cut -d " " -f 1)

check_packages jq

curl -L -f "https://api.github.com/repos/terraform-linters/tflint/attestations/sha256:${checksums_sha256}" > attestation.json
curl_exit_code=$?
if [ $curl_exit_code -ne 0 ]; then
echo "(*) Failed to fetch GitHub Attestations for tflint checksums"
return 1
fi

jq ".attestations[].bundle" attestation.json > bundle.jsonl
gh at verify "$checksums" -R terraform-linters/tflint -b bundle.jsonl
}

if [ "${TFLINT_VERSION}" != "none" ]; then
echo "Downloading tflint..."
TFLINT_FILENAME="tflint_linux_${architecture}.zip"
Expand All @@ -475,31 +492,44 @@ if [ "${TFLINT_VERSION}" != "none" ]; then
else
curl -sSL -o tflint_checksums.txt https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt

# Attempt GitHub Attestation verification (0.51.1+)
set +e
curl -sSL -o checksums.txt.keyless.sig https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.keyless.sig
verify_tflint_attestations tflint_checksums.txt
verify_result=$?
set -e

# Check that checksums.txt.keyless.sig exists and is not empty
if [ -s checksums.txt.keyless.sig ]; then
# Validate checksums with cosign
curl -sSL -o checksums.txt.pem https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.pem
ensure_cosign
cosign verify-blob \
--certificate=/tmp/tf-downloads/checksums.txt.pem \
--signature=/tmp/tf-downloads/checksums.txt.keyless.sig \
--certificate-identity-regexp="^https://github.com/terraform-linters/tflint" \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
/tmp/tf-downloads/tflint_checksums.txt
# Ensure that checksums.txt has $TFLINT_FILENAME
grep ${TFLINT_FILENAME} /tmp/tf-downloads/tflint_checksums.txt
# Validate downloaded file
if [ $verify_result -eq 0 ]; then
sha256sum --ignore-missing -c tflint_checksums.txt
echo "(*) tflint_checksums.txt verified successfully using GitHub Attestation."
else
# Fallback to older, GPG-based verification (pre-0.47.0 of tflint)
curl -sSL -o tflint_checksums.txt.sig https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.sig
curl -sSL -o tflint_key "${TFLINT_GPG_KEY_URI}"
gpg -q --import tflint_key
gpg --verify tflint_checksums.txt.sig tflint_checksums.txt
# Fallback to cosign verification
echo "(*) GitHub Attestation verification failed or not supported for this version, falling back to Cosign verification..."
set +e
curl -sSL -o checksums.txt.keyless.sig https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.keyless.sig
set -e

# Check that checksums.txt.keyless.sig exists and is not empty
if [ -s checksums.txt.keyless.sig ]; then
# Validate checksums with cosign
curl -sSL -o checksums.txt.pem https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.pem
ensure_cosign
cosign verify-blob \
--certificate=/tmp/tf-downloads/checksums.txt.pem \
--signature=/tmp/tf-downloads/checksums.txt.keyless.sig \
--certificate-identity-regexp="^https://github.com/terraform-linters/tflint" \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
/tmp/tf-downloads/tflint_checksums.txt
# Ensure that checksums.txt has $TFLINT_FILENAME
grep ${TFLINT_FILENAME} /tmp/tf-downloads/tflint_checksums.txt
# Validate downloaded file
sha256sum --ignore-missing -c tflint_checksums.txt
else
# Fallback to older, GPG-based verification (pre-0.47.0 of tflint)
curl -sSL -o tflint_checksums.txt.sig https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.sig
curl -sSL -o tflint_key "${TFLINT_GPG_KEY_URI}"
gpg -q --import tflint_key
gpg --verify tflint_checksums.txt.sig tflint_checksums.txt
fi
fi
fi
fi
Expand Down
85 changes: 56 additions & 29 deletions test/terraform/tflint_fallback_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ keyserver hkps://keys.openpgp.org
keyserver hkps://keyserver.pgp.com"

check "tflint version as installed by feature" tflint --version
check "cosign version as installed by feature" cosign version

architecture="$(uname -m)"
case ${architecture} in
Expand Down Expand Up @@ -221,14 +220,31 @@ install_tflint() {
curl -sSL -o /tmp/tf-downloads/${TFLINT_FILENAME} https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/${TFLINT_FILENAME}
}

verify_tflint_attestations() {
local checksums=$1
local checksums_sha256=$(sha256sum "$checksums" | cut -d " " -f 1)

try_install_dummy_tflint_cosign_version() {
check_packages jq

curl -L -f "https://api.github.com/repos/terraform-linters/tflint/attestations/sha256:${checksums_sha256}" > attestation.json
curl_exit_code=$?
if [ $curl_exit_code -ne 0 ]; then
echo "(*) Failed to fetch GitHub Attestations for tflint checksums"
return 1
fi

jq ".attestations[].bundle" attestation.json > bundle.jsonl
gh at verify "$checksums" -R terraform-linters/tflint -b bundle.jsonl
}


try_install_dummy_tflint_version() {
mode=$1
tflint_url='https://github.com/terraform-linters/tflint'
mkdir -p /tmp/tf-downloads
cd /tmp/tf-downloads
echo -e "\nTrying to install dummy tflint version..."
TFLINT_VERSION="0.50.XYZ"
TFLINT_VERSION="0.60.XYZ"
echo "Downloading tflint...v${TFLINT_VERSION}"
TFLINT_FILENAME="tflint_linux_${architecture}.zip"
install_tflint "$TFLINT_VERSION"
Expand All @@ -237,37 +253,50 @@ try_install_dummy_tflint_cosign_version() {
fi
if [ "${TFLINT_SHA256}" != "dev-mode" ]; then

if [ "${TFLINT_SHA256}" != "automatic" ]; then
if [ "${TFLINT_SHA256}" != "automatic" ]; then
echo "${TFLINT_SHA256} *${TFLINT_FILENAME}" > tflint_checksums.txt
sha256sum --ignore-missing -c tflint_checksums.txt
else
curl -sSL -o tflint_checksums.txt https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt

# Attempt GitHub Attestation verification (0.51.1+)
set +e
curl -sSL -o checksums.txt.keyless.sig https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.keyless.sig
verify_tflint_attestations tflint_checksums.txt
verify_result=$?
set -e

# Check that checksums.txt.keyless.sig exists and is not empty
if [ -s checksums.txt.keyless.sig ]; then
# Validate checksums with cosign
curl -sSL -o checksums.txt.pem https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.pem
ensure_cosign $mode
cosign verify-blob \
--certificate=/tmp/tf-downloads/checksums.txt.pem \
--signature=/tmp/tf-downloads/checksums.txt.keyless.sig \
--certificate-identity-regexp="^https://github.com/terraform-linters/tflint" \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
/tmp/tf-downloads/tflint_checksums.txt
# Ensure that checksums.txt has $TFLINT_FILENAME
grep ${TFLINT_FILENAME} /tmp/tf-downloads/tflint_checksums.txt
# Validate downloaded file

if [ $verify_result -eq 0 ]; then
sha256sum --ignore-missing -c tflint_checksums.txt
echo "(*) tflint_checksums.txt verified successfully using GitHub Attestation."
else
# Fallback to older, GPG-based verification (pre-0.47.0 of tflint)
curl -sSL -o tflint_checksums.txt.sig https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.sig
curl -sSL -o tflint_key "${TFLINT_GPG_KEY_URI}"
gpg -q --import tflint_key
gpg --verify tflint_checksums.txt.sig tflint_checksums.txt
# Fallback to cosign verification
echo "(*) GitHub Attestation verification failed or not supported for this version, falling back to Cosign verification..."
set +e
curl -sSL -o checksums.txt.keyless.sig https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.keyless.sig
set -e

# Check that checksums.txt.keyless.sig exists and is not empty
if [ -s checksums.txt.keyless.sig ]; then
# Validate checksums with cosign
curl -sSL -o checksums.txt.pem https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.pem
ensure_cosign $mode
cosign verify-blob \
--certificate=/tmp/tf-downloads/checksums.txt.pem \
--signature=/tmp/tf-downloads/checksums.txt.keyless.sig \
--certificate-identity-regexp="^https://github.com/terraform-linters/tflint" \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
/tmp/tf-downloads/tflint_checksums.txt
# Ensure that checksums.txt has $TFLINT_FILENAME
grep ${TFLINT_FILENAME} /tmp/tf-downloads/tflint_checksums.txt
# Validate downloaded file
sha256sum --ignore-missing -c tflint_checksums.txt
else
# Fallback to older, GPG-based verification (pre-0.47.0 of tflint)
curl -sSL -o tflint_checksums.txt.sig https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.sig
curl -sSL -o tflint_key "${TFLINT_GPG_KEY_URI}"
gpg -q --import tflint_key
gpg --verify tflint_checksums.txt.sig tflint_checksums.txt
fi
fi
fi
fi
Expand All @@ -276,12 +305,10 @@ try_install_dummy_tflint_cosign_version() {
sudo mv -f tflint /usr/local/bin/
}

try_install_dummy_tflint_cosign_version "mode1"
try_install_dummy_tflint_version "mode1"

check "tflint version as installed when mode=1" tflint --version
check "cosign version as installed when mode=1" cosign version

try_install_dummy_tflint_cosign_version "mode2"
try_install_dummy_tflint_version "mode2"

check "tflint version as installed when mode=2" tflint --version
check "cosign version as installed when mode=2" cosign version
Loading