From b63790a9615d860c7bbf090b76a8bf8104447e99 Mon Sep 17 00:00:00 2001 From: Daniel Flook Date: Wed, 19 Mar 2025 13:21:59 +0000 Subject: [PATCH 1/6] Add dockerfile and actions security linting --- .github/workflows/test.yaml | 26 +++++++++++++++++++------- image/Dockerfile | 3 ++- image/Dockerfile-base | 3 +++ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 3681cf36..ad3702c0 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -97,6 +97,14 @@ jobs: ./actionlint ./actionlint example_workflows/*.yaml + - name: Install the latest version of uv + uses: astral-sh/setup-uv@f94ec6bedd8674c4426838e6b50417d36b6ab231 # v5 + - name: Actions Security Check + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + uvx zizmor --format plain . + - name: Lint CHANGELOG uses: DavidAnson/markdownlint-cli2-action@05f32210e84442804257b2a6f20b273450ec8265 # v19 with: @@ -111,15 +119,19 @@ jobs: docs/*.md **/README.md - ensure-pinned-actions: - runs-on: ubuntu-24.04 - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Ensure SHA pinned actions + - name: ensure-sha-pinned-actions uses: zgosalvez/github-actions-ensure-sha-pinned-actions@25ed13d0628a1601b4b44048e63cc4328ed03633 # v3 with: allowlist: | actions/ dflook/ + + - name: Lint Dockerfile + uses: hadolint/hadolint-action@v3.1.0 + with: + dockerfile: ./image/Dockerfile + + - name: Lint Dockerfile + uses: hadolint/hadolint-action@v3.1.0 + with: + dockerfile: ./image/Dockerfile-base diff --git a/image/Dockerfile b/image/Dockerfile index 39ae0857..5ee246f8 100644 --- a/image/Dockerfile +++ b/image/Dockerfile @@ -1,3 +1,4 @@ +# hadolint ignore=DL3007 FROM danielflook/terraform-github-actions-base:latest ARG TARGETARCH @@ -8,7 +9,7 @@ ARG VERSION=99.0.0 COPY src/ /tmp/src/ COPY setup.py /tmp RUN sed -i "s|version='.*'|version=\'${VERSION}\'|" /tmp/setup.py \ - && pip install /tmp \ + && pip install --no-cache-dir /tmp \ && rm -rf /tmp/src /tmp/setup.py RUN if [ "$FETCH_CHECKSUMS" = "yes" ]; then \ diff --git a/image/Dockerfile-base b/image/Dockerfile-base index f4265a98..2214ca93 100644 --- a/image/Dockerfile-base +++ b/image/Dockerfile-base @@ -1,5 +1,6 @@ FROM golang:1.12.6 AS tfmask +# hadolint ignore=DL3003 RUN git clone https://github.com/cloudposse/tfmask.git \ && cd tfmask \ && git checkout 9a15f421210397f2c321a57b5ed3d108a012a86d \ @@ -14,6 +15,8 @@ ENV TF_IN_AUTOMATION=true ENV TF_INPUT=false ENV TF_PLUGIN_CACHE_DIR=/usr/local/share/terraform/plugin-cache +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +# hadolint ignore=DL3008 RUN < Date: Wed, 19 Mar 2025 13:28:36 +0000 Subject: [PATCH 2/6] pin actions --- .github/workflows/test.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index ad3702c0..706e853b 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -98,7 +98,7 @@ jobs: ./actionlint example_workflows/*.yaml - name: Install the latest version of uv - uses: astral-sh/setup-uv@f94ec6bedd8674c4426838e6b50417d36b6ab231 # v5 + uses: astral-sh/setup-uv@f94ec6bedd8674c4426838e6b50417d36b6ab231 # v5.3.1 - name: Actions Security Check env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -127,11 +127,11 @@ jobs: dflook/ - name: Lint Dockerfile - uses: hadolint/hadolint-action@v3.1.0 + uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf # v3.1.0 with: dockerfile: ./image/Dockerfile - name: Lint Dockerfile - uses: hadolint/hadolint-action@v3.1.0 + uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf # v3.1.0 with: dockerfile: ./image/Dockerfile-base From 8af96b930fa6c2661df556d70e34b808c79006db Mon Sep 17 00:00:00 2001 From: Daniel Flook Date: Wed, 19 Mar 2025 16:50:30 +0000 Subject: [PATCH 3/6] Add shellcheck --- .github/workflows/test.yaml | 7 ++++++- image/actions.sh | 29 ++++++++++++++++------------- image/entrypoints/test.sh | 2 +- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 706e853b..d9999915 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -131,7 +131,12 @@ jobs: with: dockerfile: ./image/Dockerfile - - name: Lint Dockerfile + - name: Lint Dockerfile-base uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf # v3.1.0 with: dockerfile: ./image/Dockerfile-base + + - name: Run ShellCheck + run: | + cd image/entrypoints + shellcheck ../actions.sh ../workflow_commands.sh *.sh --enable add-default-case,avoid-nullary-conditional,require-double-brackets,deprecate-which diff --git a/image/actions.sh b/image/actions.sh index f13170eb..46734a34 100644 --- a/image/actions.sh +++ b/image/actions.sh @@ -18,7 +18,7 @@ function repair_environment() { # HOME doesn't exist... is it near GITHUB_EVENT_PATH? local ACTUAL_HOME - ACTUAL_HOME=$(realpath "$(dirname $GITHUB_EVENT_PATH)/../_github_home") + ACTUAL_HOME=$(realpath "$(dirname "$GITHUB_EVENT_PATH")/../_github_home") if [[ -d "$ACTUAL_HOME" ]]; then HOME="$ACTUAL_HOME" @@ -42,7 +42,7 @@ function debug() { function detect-terraform-version() { TERRAFORM_BIN_CACHE_DIR="/var/terraform:$JOB_TMP_DIR/terraform-bin-dir" TERRAFORM_BIN_CHECKSUM_DIR="/var/terraform" terraform-version - debug_cmd ls -la "$(which terraform)" + debug_cmd ls -la "$(command -v terraform)" local TF_VERSION TF_VERSION=$(terraform version -json | jq -r '.terraform_version' 2>/dev/null || terraform version | grep 'Terraform v' | sed 's/Terraform v//') @@ -140,7 +140,8 @@ function setup() { detect-terraform-version - readonly TERRAFORM_BACKEND_TYPE=$(terraform-backend) + TERRAFORM_BACKEND_TYPE=$(terraform-backend) + readonly TERRAFORM_BACKEND_TYPE if [[ "$TERRAFORM_BACKEND_TYPE" != "" ]]; then echo "Detected $TERRAFORM_BACKEND_TYPE backend" fi @@ -170,7 +171,7 @@ function init() { start_group "Initializing $TOOL_PRODUCT_NAME" rm -rf "$TF_DATA_DIR" - debug_log $TOOL_COMMAND_NAME init -input=false -backend=false + debug_log "$TOOL_COMMAND_NAME" init -input=false -backend=false (cd "$INPUT_PATH" && $TOOL_COMMAND_NAME init -input=false -backend=false) end_group @@ -186,10 +187,10 @@ function init-test() { rm -rf "$TF_DATA_DIR" if [[ -n "$INPUT_TEST_DIRECTORY" ]]; then - debug_log $TOOL_COMMAND_NAME init -input=false -backend=false -test-directory "$INPUT_TEST_DIRECTORY" - (cd "$INPUT_PATH" && $TOOL_COMMAND_NAME init -input=false -backend=false -test-directory $INPUT_TEST_DIRECTORY) + debug_log "$TOOL_COMMAND_NAME" init -input=false -backend=false -test-directory "$INPUT_TEST_DIRECTORY" + (cd "$INPUT_PATH" && $TOOL_COMMAND_NAME init -input=false -backend=false -test-directory "$INPUT_TEST_DIRECTORY") else - debug_log $TOOL_COMMAND_NAME init -input=false -backend=false + debug_log "$TOOL_COMMAND_NAME" init -input=false -backend=false (cd "$INPUT_PATH" && $TOOL_COMMAND_NAME init -input=false -backend=false) fi @@ -231,7 +232,8 @@ function init-backend-workspace() { rm -rf "$TF_DATA_DIR" - debug_log TF_WORKSPACE=$INPUT_WORKSPACE $TOOL_COMMAND_NAME init -input=false '$INIT_ARGS' # don't expand INIT_ARGS + # shellcheck disable=SC2016 + debug_log TF_WORKSPACE="$INPUT_WORKSPACE" "$TOOL_COMMAND_NAME" init -input=false '$INIT_ARGS' # don't expand INIT_ARGS set +e # shellcheck disable=SC2086 @@ -271,7 +273,8 @@ function init-backend-default-workspace() { rm -rf "$TF_DATA_DIR" - debug_log $TOOL_COMMAND_NAME init -input=false '$INIT_ARGS' # don't expand INIT_ARGS + # shellcheck disable=SC2016 + debug_log "$TOOL_COMMAND_NAME" init -input=false '$INIT_ARGS' # don't expand INIT_ARGS set +e # shellcheck disable=SC2086 (cd "$INPUT_PATH" && $TOOL_COMMAND_NAME init -input=false $INIT_ARGS \ @@ -299,7 +302,7 @@ function init-backend-default-workspace() { function select-workspace() { local WORKSPACE_EXIT - debug_log $TOOL_COMMAND_NAME workspace select "$INPUT_WORKSPACE" + debug_log "$TOOL_COMMAND_NAME" workspace select "$INPUT_WORKSPACE" set +e (cd "$INPUT_PATH" && $TOOL_COMMAND_NAME workspace select "$INPUT_WORKSPACE") >"$STEP_TMP_DIR/workspace_select" 2>&1 WORKSPACE_EXIT=$? @@ -429,7 +432,7 @@ function set-remote-plan-args() { } function output() { - debug_log $TOOL_COMMAND_NAME output -json + debug_log "$TOOL_COMMAND_NAME" output -json (cd "$INPUT_PATH" && $TOOL_COMMAND_NAME output -json | tee "$STEP_TMP_DIR/terraform_output.json" | convert_output) } @@ -526,8 +529,8 @@ function destroy() { function force_unlock() { echo "Unlocking state with ID: $INPUT_LOCK_ID" - debug_log $TOOL_COMMAND_NAME force-unlock -force $INPUT_LOCK_ID - (cd "$INPUT_PATH" && $TOOL_COMMAND_NAME force-unlock -force $INPUT_LOCK_ID) + debug_log "$TOOL_COMMAND_NAME" force-unlock -force "$INPUT_LOCK_ID" + (cd "$INPUT_PATH" && $TOOL_COMMAND_NAME force-unlock -force "$INPUT_LOCK_ID") } # Every file written to disk should use one of these directories diff --git a/image/entrypoints/test.sh b/image/entrypoints/test.sh index 2fba424e..badd1c4f 100755 --- a/image/entrypoints/test.sh +++ b/image/entrypoints/test.sh @@ -34,7 +34,7 @@ function set-test-args() { function test() { - debug_log $TOOL_COMMAND_NAME test -no-color $TEST_ARGS $VARIABLE_ARGS + debug_log $TOOL_COMMAND_NAME test -no-color "$TEST_ARGS" "$VARIABLE_ARGS" set +e # shellcheck disable=SC2086 From 4b4663525bb3ed340308bffd84fa1a4d03bdaa60 Mon Sep 17 00:00:00 2001 From: Daniel Flook Date: Thu, 20 Mar 2025 18:37:40 +0000 Subject: [PATCH 4/6] Lint yaml files --- .config/.markdownlint.yaml | 1 - .config/yamllint.yaml | 14 +++++++++++++ .github/ISSUE_TEMPLATE/problem.yml | 4 ++-- .github/workflows/release.yaml | 10 +++++----- .github/workflows/test-apply.yaml | 4 ++-- .github/workflows/test-binary-plan.yaml | 2 +- .github/workflows/test-changes-only.yaml | 1 - .github/workflows/test-cloud.yaml | 24 +++++++++++------------ .github/workflows/test-http.yaml | 2 +- .github/workflows/test-new-workspace.yaml | 2 +- .github/workflows/test-plan.yaml | 14 ++++++------- .github/workflows/test-registry.yaml | 2 +- .github/workflows/test-test.yaml | 8 ++++---- .github/workflows/test-unlock-state.yaml | 16 +++++++-------- .github/workflows/test-version.yaml | 16 +++++++-------- .github/workflows/test.yaml | 13 ++++++++---- 16 files changed, 75 insertions(+), 58 deletions(-) create mode 100644 .config/yamllint.yaml diff --git a/.config/.markdownlint.yaml b/.config/.markdownlint.yaml index 58249f90..0314e288 100644 --- a/.config/.markdownlint.yaml +++ b/.config/.markdownlint.yaml @@ -5,4 +5,3 @@ no-inline-html: allowed_elements: ['p', 'img'] ul-style: style: sublist - diff --git a/.config/yamllint.yaml b/.config/yamllint.yaml new file mode 100644 index 00000000..247d3f7c --- /dev/null +++ b/.config/yamllint.yaml @@ -0,0 +1,14 @@ +--- +extends: default + +rules: + document-start: disable + line-length: + max: 255 + truthy: + check-keys: false + comments: + min-spaces-from-content: 1 + octal-values: + forbid-implicit-octal: true + forbid-explicit-octal: true diff --git a/.github/ISSUE_TEMPLATE/problem.yml b/.github/ISSUE_TEMPLATE/problem.yml index ae78365c..7b9c040c 100644 --- a/.github/ISSUE_TEMPLATE/problem.yml +++ b/.github/ISSUE_TEMPLATE/problem.yml @@ -49,6 +49,6 @@ body: id: debugging-enabled attributes: label: Has debug logging been enabled? - options: - - label: Yes, the `ACTIONS_STEP_DEBUG` secret was set to `true` when capturing the workflow log above. I understand that if I have not done this, I may not recieve a response. + options: + - label: Yes, the `ACTIONS_STEP_DEBUG` secret was set to `true` when capturing the workflow log above. I understand that if I have not done this, I may not receive a response. required: true diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0d13d8d2..f33758b2 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -52,11 +52,11 @@ jobs: run: | BASE_TAG=$(docker buildx imagetools inspect danielflook/terraform-github-actions-base:latest --format '{{json .}}' | jq -r '.manifest.annotations."ref.tag"') BASE_DIGEST=$(docker buildx imagetools inspect "danielflook/terraform-github-actions-base:$BASE_TAG" --format '{{json .}}' | jq -r '.manifest.digest') - + gh attestation verify --repo dflook/terraform-github-actions "oci://index.docker.io/danielflook/terraform-github-actions-base@$BASE_DIGEST" - + sed -i "s|FROM danielflook/terraform-github-actions-base:latest|FROM danielflook/terraform-github-actions-base@$BASE_DIGEST|" "image/Dockerfile" - + docker buildx build \ --build-arg FETCH_CHECKSUMS=yes \ --build-arg VERSION="${RELEASE_TAG:1}" \ @@ -156,12 +156,12 @@ jobs: git -C "$HOME/$action" tag --force -a -m"$RELEASE_TAG" "$major.$minor-dockerhub" git -C "$HOME/$action" push --force git -C "$HOME/$action" push --force --tags - + # git tags that use GitHub Container Registry for the image git -C "$HOME/$action" checkout ghcr || git -C "$HOME/$action" checkout -b ghcr prepare_release sed -i "s| image:.*| image: docker://ghcr.io/dflook/terraform-github-actions@$IMAGE_DIGEST|" "$HOME/$action/action.yaml" - + git -C "$HOME/$action" add -A git -C "$HOME/$action" commit -m "$RELEASE_TAG-ghcr" git -C "$HOME/$action" tag --force -a -m"$RELEASE_TAG" "$RELEASE_TAG-ghcr" diff --git a/.github/workflows/test-apply.yaml b/.github/workflows/test-apply.yaml index 8bf87300..0e253e54 100644 --- a/.github/workflows/test-apply.yaml +++ b/.github/workflows/test-apply.yaml @@ -878,7 +878,7 @@ jobs: contents: read pull-requests: write env: - GITHUB_TOKEN: No + GITHUB_TOKEN: "No" TERRAFORM_ACTIONS_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout @@ -1029,7 +1029,7 @@ jobs: echo "::error:: output changes not set correctly" exit 1 fi - + if [[ "$TO_ADD" -ne 1 ]]; then echo "::error:: to_add not set correctly" exit 1 diff --git a/.github/workflows/test-binary-plan.yaml b/.github/workflows/test-binary-plan.yaml index a84dc62e..bf920a1d 100644 --- a/.github/workflows/test-binary-plan.yaml +++ b/.github/workflows/test-binary-plan.yaml @@ -137,4 +137,4 @@ jobs: if [[ "$FAILURE_REASON" != "plan-changed" ]]; then echo "::error:: failure-reason not set correctly" exit 1 - fi \ No newline at end of file + fi diff --git a/.github/workflows/test-changes-only.yaml b/.github/workflows/test-changes-only.yaml index f804dfc8..b5e26a33 100644 --- a/.github/workflows/test-changes-only.yaml +++ b/.github/workflows/test-changes-only.yaml @@ -229,4 +229,3 @@ jobs: echo "::error:: failure-reason not set correctly" exit 1 fi - diff --git a/.github/workflows/test-cloud.yaml b/.github/workflows/test-cloud.yaml index a6a94092..7c44d600 100644 --- a/.github/workflows/test-cloud.yaml +++ b/.github/workflows/test-cloud.yaml @@ -265,7 +265,7 @@ jobs: echo "::error:: Variables not set correctly" exit 1 fi - + if ! grep -q "Terraform will perform the following actions" "$TEXT_PLAN_PATH"; then echo "::error:: text_plan_path not set correctly" exit 1 @@ -275,7 +275,7 @@ jobs: echo "::error:: json_plan_path should not be set" exit 1 fi - + if [[ "$RUN_ID" != "run-"* ]]; then echo "::error:: output run_id not set correctly" exit 1 @@ -358,7 +358,7 @@ jobs: echo "::error:: output not set correctly" exit 1 fi - + if ! grep -q "Terraform will perform the following actions" "$TEXT_PLAN_PATH"; then echo "::error:: text_plan_path not set correctly" exit 1 @@ -448,7 +448,7 @@ jobs: echo "::error:: output changes not set correctly" exit 1 fi - + if ! grep -q "Terraform will perform the following actions" "$TEXT_PLAN_PATH"; then echo "::error:: text_plan_path not set correctly" exit 1 @@ -458,7 +458,7 @@ jobs: echo "::error:: json_plan_path should be set" exit 1 fi - + if [[ "$RUN_ID" != "run-"* ]]; then echo "::error:: output run_id not set correctly" exit 1 @@ -485,12 +485,12 @@ jobs: echo "::error:: Variables not set correctly" exit 1 fi - + if ! grep -q "Terraform will perform the following actions" "$TEXT_PLAN_PATH"; then echo "::error:: text_plan_path not set correctly" exit 1 fi - + if [[ ! -f "$JSON_PLAN_PATH" ]]; then echo "::error:: json_plan_path should be set" exit 1 @@ -536,7 +536,7 @@ jobs: echo "::error:: changes output not set correctly" exit 1 fi - + if [[ "$APPLY_OUTPUT_LEN" != "5" ]]; then echo "::error:: Variables not set correctly" exit 1 @@ -610,7 +610,7 @@ jobs: echo "::error:: changes output not set correctly" exit 1 fi - + if [[ "$SAVED_APPLY_OUTPUT_LEN" != "8" ]]; then echo "::error:: Variables not set correctly" exit 1 @@ -620,7 +620,7 @@ jobs: echo "::error:: text_plan_path not set correctly" exit 1 fi - + if [[ ! -f "$SAVED_PLAN_JSON_PLAN_PATH" ]]; then echo "::error:: json_plan_path should be set" exit 1 @@ -630,7 +630,7 @@ jobs: echo "::error:: output run_id not set correctly" exit 1 fi - + if [[ "$SAVED_APPLY_RUN_ID" != "run-"* ]]; then echo "::error:: output run_id not set correctly" exit 1 @@ -674,7 +674,7 @@ jobs: echo "::error:: changes output not set correctly" exit 1 fi - + if [[ "$SAVED_APPLY_OUTPUT_LEN" != "8" ]]; then echo "::error:: Variables not set correctly" exit 1 diff --git a/.github/workflows/test-http.yaml b/.github/workflows/test-http.yaml index 37b8254a..2b0e4e04 100644 --- a/.github/workflows/test-http.yaml +++ b/.github/workflows/test-http.yaml @@ -162,7 +162,7 @@ jobs: echo "::error:: output not set correctly" exit 1 fi - + # Check the credential file is as before diff tests/workflows/test-http/http-module/netrc "$RUNNER_TEMP_D/_github_home/.netrc" diff --git a/.github/workflows/test-new-workspace.yaml b/.github/workflows/test-new-workspace.yaml index 6d73e629..0e85e1dd 100644 --- a/.github/workflows/test-new-workspace.yaml +++ b/.github/workflows/test-new-workspace.yaml @@ -32,7 +32,7 @@ jobs: key = "terraform-new-workspace-${{ matrix.tf_version }}" region = "eu-west-2" } - + required_version = "${{ matrix.tf_version }}" } EOF diff --git a/.github/workflows/test-plan.yaml b/.github/workflows/test-plan.yaml index febeab82..171b49b3 100644 --- a/.github/workflows/test-plan.yaml +++ b/.github/workflows/test-plan.yaml @@ -52,7 +52,7 @@ jobs: echo "::error:: text_plan_path not set correctly" exit 1 fi - + if ! [[ -f "$PLAN_PATH" ]]; then echo "::error:: plan_path not set correctly" exit 1 @@ -232,7 +232,7 @@ jobs: echo "::error:: text_plan_path not set correctly" exit 1 fi - + if [[ "$TO_ADD" -ne 1 ]]; then echo "::error:: to_add not set correctly" exit 1 @@ -864,7 +864,7 @@ jobs: path: tests/workflows/test-plan/single_sensitive_variable variables: | my_sensitive_string = "password123" - + plan_sensitive_variables: runs-on: ubuntu-24.04 @@ -904,7 +904,7 @@ jobs: protocol = "udp" fruits = ["apple", "banana"] } - ] + ] plan_sensitive_var: runs-on: ubuntu-24.04 @@ -999,7 +999,7 @@ jobs: with: path: tests/workflows/test-plan/plan var_file: | - var_file/doesnt/exist.tfvars + var_file/doesnt/exist.tfvars var_file/doesnt/exist2.tfvars add_github_comment: false @@ -1027,11 +1027,11 @@ jobs: echo "Non existant var_file did not fail correctly" exit 1 fi - + if [[ "$BACKEND_CONFIG_FILE_OUTCOME" != "failure" ]]; then echo "Non existant backend_config_file did not fail correctly" exit 1 - fi + fi test_plan_1_4: runs-on: ubuntu-24.04 diff --git a/.github/workflows/test-registry.yaml b/.github/workflows/test-registry.yaml index adc19c79..4f585360 100644 --- a/.github/workflows/test-registry.yaml +++ b/.github/workflows/test-registry.yaml @@ -56,7 +56,7 @@ jobs: echo "::error:: output not set correctly" exit 1 fi - + # Check that terraformrc is as before diff tests/workflows/test-registry/terraformrc "$RUNNER_TEMP_D/_github_home/.terraformrc" diff --git a/.github/workflows/test-test.yaml b/.github/workflows/test-test.yaml index 52570509..35796418 100644 --- a/.github/workflows/test-test.yaml +++ b/.github/workflows/test-test.yaml @@ -33,7 +33,7 @@ jobs: echo "::error:: failure-reason not set correctly" exit 1 fi - + if [[ "$JUNIT_XML_PATH" != "" ]]; then echo "::error:: junit-xml-path should not be set" exit 1 @@ -65,7 +65,7 @@ jobs: echo "::error:: failure-reason not set correctly" exit 1 fi - + if [[ "$JUNIT_XML_PATH" == "" ]]; then echo "::error:: junit-xml-path should be set" exit 1 @@ -76,7 +76,7 @@ jobs: echo "::error:: junit-xml-path does not point to a file" exit 1 fi - + if [[ "$(grep -c ' Date: Thu, 20 Mar 2025 22:46:47 +0000 Subject: [PATCH 5/6] Validate yaml schemas --- .config/.v8rrc.yaml | 15 +++++++++++++++ .config/{yamllint.yaml => .yamllint.yaml} | 0 .github/workflows/test.yaml | 7 +++++-- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 .config/.v8rrc.yaml rename .config/{yamllint.yaml => .yamllint.yaml} (100%) diff --git a/.config/.v8rrc.yaml b/.config/.v8rrc.yaml new file mode 100644 index 00000000..bbc7dbef --- /dev/null +++ b/.config/.v8rrc.yaml @@ -0,0 +1,15 @@ +customCatalog: + schemas: + - name: Example Workflow + fileMatch: ["example_workflows/*.yaml"] + location: https://json.schemastore.org/github-workflow.json + + - name: Markdown Lint + fileMatch: ["changelog.markdownlint.yaml"] + location: "https://raw.githubusercontent.com/DavidAnson/markdownlint/main/schema/markdownlint-config-schema.json" + + - name: GitHub Issue Template configuration + fileMatch: [".github/ISSUE_TEMPLATE/config.yml"] + location: "https://json.schemastore.org/github-issue-config.json" + +patterns: ['**/*.yaml', '**/*.yml'] diff --git a/.config/yamllint.yaml b/.config/.yamllint.yaml similarity index 100% rename from .config/yamllint.yaml rename to .config/.yamllint.yaml diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 54503c39..ac04029c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -132,6 +132,7 @@ jobs: dockerfile: ./image/Dockerfile - name: Lint Dockerfile-base + uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf # v3.1.0 with: dockerfile: ./image/Dockerfile-base @@ -139,9 +140,11 @@ jobs: - name: Run ShellCheck run: | cd image/entrypoints - shellcheck ../actions.sh ../workflow_commands.sh *.sh --enable add-default-case,avoid-nullary-conditional,require-double-brackets,deprecate-which + shellcheck ../actions.sh ../workflow_commands.sh ./*.sh --enable add-default-case,avoid-nullary-conditional,require-double-brackets,deprecate-which - name: Lint YAML files run: | pip install yamllint - yamllint -c .config/yamllint.yaml . + yamllint -c .config/.yamllint.yaml . + + V8R_CONFIG_FILE=.config/.v8rrc.yaml npx v8r --ignore-errors From d9811db21159800357c4ca87c8ee52a8a0e15adf Mon Sep 17 00:00:00 2001 From: Daniel Flook Date: Fri, 21 Mar 2025 22:19:28 +0000 Subject: [PATCH 6/6] Lint Python files using ruff --- .config/ruff.toml | 29 +++++++++++++++++++ .github/workflows/test.yaml | 4 +++ .gitignore | 5 ++++ docs-gen/action.py | 13 +++++---- docs-gen/actions/new_workspace.py | 1 - docs-gen/actions/remote_state.py | 1 - image/src/github_pr_comment/__main__.py | 6 ++-- image/src/plan_renderer/variables.py | 3 +- image/src/terraform/hcl.py | 6 ++-- image/src/terraform/module.py | 16 +++++----- image/src/terraform_cloud_state/__main__.py | 1 - image/src/terraform_version/__main__.py | 6 ++-- .../src/terraform_version/required_version.py | 2 +- 13 files changed, 65 insertions(+), 28 deletions(-) create mode 100644 .config/ruff.toml diff --git a/.config/ruff.toml b/.config/ruff.toml new file mode 100644 index 00000000..a59f34bc --- /dev/null +++ b/.config/ruff.toml @@ -0,0 +1,29 @@ +line-length = 120 + +target-version = "py39" + +src = ["docs-gen", "image/src"] + +include = [ + "docs-gen/*.py", + "image/src/*.py", + "image/src/setup.py", + "tools/*.py", +] + +[lint] +# Allow fix for all enabled rules (when `--fix`) is provided. +fixable = ["ALL"] +unfixable = [] + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +[lint.flake8-quotes] +inline-quotes = "single" +multiline-quotes = "single" +docstring-quotes = "double" + +[format] +quote-style = "single" +docstring-code-format = true diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index ac04029c..9d2b1e23 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -148,3 +148,7 @@ jobs: yamllint -c .config/.yamllint.yaml . V8R_CONFIG_FILE=.config/.v8rrc.yaml npx v8r --ignore-errors + + - uses: astral-sh/ruff-action@9828f49eb4cadf267b40eaa330295c412c68c1f9 # v3 + with: + args: --config=.config/ruff.toml check diff --git a/.gitignore b/.gitignore index 38965798..1d6ae894 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,8 @@ /venv/ .terraform.lock.hcl .terraform-bin-dir/ +.gpg/ +build/ +__pycache__/ +.DS_Store +*.egg-info/ diff --git a/docs-gen/action.py b/docs-gen/action.py index daae7a04..186a54ac 100644 --- a/docs-gen/action.py +++ b/docs-gen/action.py @@ -1,5 +1,6 @@ import textwrap -from dataclasses import dataclass, field +import dataclasses +from dataclasses import dataclass from textwrap import indent from typing import Callable, Type @@ -93,9 +94,9 @@ class Output: description: str meta_description: str = None type: str = None - aliases: list[str] = field(default_factory=list) + aliases: list[str] = dataclasses.field(default_factory=list) meta_output: bool = False - available_in: list[Type[Terraform] | Type[OpenTofu]] = field(default_factory=lambda: [Terraform, OpenTofu]) + available_in: list[Type[Terraform] | Type[OpenTofu]] = dataclasses.field(default_factory=lambda: [Terraform, OpenTofu]) def markdown(self, tool: Tool) -> str: if self.meta_output: @@ -135,11 +136,11 @@ class Action: name: str description: str | Callable[[Tool], str] meta_description: str = None - inputs: list[Input] = field(default_factory=list) + inputs: list[Input] = dataclasses.field(default_factory=list) inputs_intro: str = None environment_variables: list[EnvVar] = None environment_variables_intro: str = None - outputs: list[Output] = field(default_factory=list) + outputs: list[Output] = dataclasses.field(default_factory=list) outputs_intro: str = None extra: str | Callable[[bool], str] = None @@ -318,4 +319,4 @@ def action_yaml(self, tool: Tool) -> str: color: purple ''', trailing_blank_line=False) - return productize(s, tool) \ No newline at end of file + return productize(s, tool) diff --git a/docs-gen/actions/new_workspace.py b/docs-gen/actions/new_workspace.py index 901977cf..b917a82c 100644 --- a/docs-gen/actions/new_workspace.py +++ b/docs-gen/actions/new_workspace.py @@ -2,7 +2,6 @@ from action import Action from environment_variables.GITHUB_DOT_COM_TOKEN import GITHUB_DOT_COM_TOKEN -from environment_variables.TERRAFORM_ACTIONS_GITHUB_TOKEN import TERRAFORM_ACTIONS_GITHUB_TOKEN from environment_variables.TERRAFORM_CLOUD_TOKENS import TERRAFORM_CLOUD_TOKENS from environment_variables.TERRAFORM_HTTP_CREDENTIALS import TERRAFORM_HTTP_CREDENTIALS from environment_variables.TERRAFORM_PRE_RUN import TERRAFORM_PRE_RUN diff --git a/docs-gen/actions/remote_state.py b/docs-gen/actions/remote_state.py index 8162ad0f..1fc27b05 100644 --- a/docs-gen/actions/remote_state.py +++ b/docs-gen/actions/remote_state.py @@ -6,7 +6,6 @@ from inputs.backend_config import backend_config from inputs.backend_config_file import backend_config_file from inputs.backend_type import backend_type -from inputs.path import path from inputs.workspace import workspace from outputs.terraform_outputs import terraform_outputs diff --git a/image/src/github_pr_comment/__main__.py b/image/src/github_pr_comment/__main__.py index 90fb0d2b..10648a0e 100644 --- a/image/src/github_pr_comment/__main__.py +++ b/image/src/github_pr_comment/__main__.py @@ -151,9 +151,9 @@ def format_description(action_inputs: PlanPrInputs, sensitive_variables: List[st label += f'\nWith backend config files: `{action_inputs["INPUT_BACKEND_CONFIG_FILE"]}`' if action_inputs["INPUT_VAR"]: - label += f'\n:warning: Using deprecated var input. Use the variables input instead.' + label += '\n:warning: Using deprecated var input. Use the variables input instead.' if any(var_name in action_inputs["INPUT_VAR"] for var_name in sensitive_variables): - label += f'\nWith vars: (sensitive values)' + label += '\nWith vars: (sensitive values)' else: label += f'\nWith vars: `{action_inputs["INPUT_VAR"]}`' @@ -226,7 +226,7 @@ def graphql() -> Optional[str]: if response.ok: try: return response.json()['data']['viewer']['login'] - except Exception as e: + except Exception: pass debug('Failed to get current user from graphql') diff --git a/image/src/plan_renderer/variables.py b/image/src/plan_renderer/variables.py index bea84690..44fed1b0 100644 --- a/image/src/plan_renderer/variables.py +++ b/image/src/plan_renderer/variables.py @@ -2,7 +2,8 @@ from textwrap import indent -class Sensitive: pass +class Sensitive: + pass def render_argument_list(argument_list: dict[str, Any]) -> str: diff --git a/image/src/terraform/hcl.py b/image/src/terraform/hcl.py index 85f51ee0..ef25cf1b 100644 --- a/image/src/terraform/hcl.py +++ b/image/src/terraform/hcl.py @@ -31,7 +31,7 @@ def is_loadable(path: Path) -> bool: debug('TimeoutExpired') # We found a file that won't parse :( return False - except: + except Exception: # If we get an exception, we can still try and load it. return True @@ -55,8 +55,8 @@ def loads(hcl: str) -> dict: if is_loadable(tmp_path): return hcl2.loads(hcl) - debug(f'Unable to load hcl') - raise ValueError(f'Unable to load hcl') + debug('Unable to load hcl') + raise ValueError('Unable to load hcl') if __name__ == '__main__': diff --git a/image/src/terraform/module.py b/image/src/terraform/module.py index d3988ce8..00766159 100644 --- a/image/src/terraform/module.py +++ b/image/src/terraform/module.py @@ -152,8 +152,8 @@ def get_remote_backend_config( 'workspaces': {} }) - for terraform in module.get('terraform', []): - for backend in terraform.get('backend', []): + for terraform_block in module.get('terraform', []): + for backend in terraform_block.get('backend', []): if 'remote' not in backend: return None @@ -209,8 +209,8 @@ def get_cloud_config(module: TerraformModule, cli_config_path: Path) -> Optional 'workspaces': {} }) - for terraform in module.get('terraform', []): - for cloud in terraform.get('cloud', []): + for terraform_block in module.get('terraform', []): + for cloud in terraform_block.get('cloud', []): found = True @@ -245,13 +245,13 @@ def get_backend_type(module: TerraformModule) -> Optional[str]: :return: The name of the backend used by the module """ - for terraform in module.get('terraform', []): - for backend in terraform.get('backend', []): + for terraform_block in module.get('terraform', []): + for backend in terraform_block.get('backend', []): for backend_type in backend: return str(backend_type) - for terraform in module.get('terraform', []): - if 'cloud' in terraform: + for terraform_block in module.get('terraform', []): + if 'cloud' in terraform_block: return 'cloud' return 'local' diff --git a/image/src/terraform_cloud_state/__main__.py b/image/src/terraform_cloud_state/__main__.py index 202aaed5..f852d88d 100644 --- a/image/src/terraform_cloud_state/__main__.py +++ b/image/src/terraform_cloud_state/__main__.py @@ -4,7 +4,6 @@ from pathlib import Path from typing import Optional -from github_actions.commands import output from terraform.cloud import TerraformCloudApi from terraform.module import BackendConfig from terraform.module import load_module, get_remote_backend_config, get_cloud_config diff --git a/image/src/terraform_version/__main__.py b/image/src/terraform_version/__main__.py index a0021cbf..69a4776e 100644 --- a/image/src/terraform_version/__main__.py +++ b/image/src/terraform_version/__main__.py @@ -96,7 +96,7 @@ def determine_version(inputs: InitInputs, cli_config_path: Path, actions_env: Ac sys.stdout.write(f'Using the same {version.product} version that wrote the existing remote state file\n') return version - sys.stdout.write(f'Version not specified, using the latest release version\n') + sys.stdout.write('Version not specified, using the latest release version\n') return latest_non_prerelease_version(versions) @@ -151,8 +151,8 @@ def main() -> None: sys.exit(1) if 'OPENTOFU' in os.environ and version.product == 'Terraform': - sys.stdout.write(f'OpenTofu is preferred, but only a version of Terraform matched the version constraints.\n') - sys.stdout.write(f'Try specifying a version of OpenTofu. Pre-release versions must be explicit, e.g. OPENTOFU_VERSION=1.6.0-alpha3\n') + sys.stdout.write('OpenTofu is preferred, but only a version of Terraform matched the version constraints.\n') + sys.stdout.write('Try specifying a version of OpenTofu. Pre-release versions must be explicit, e.g. OPENTOFU_VERSION=1.6.0-alpha3\n') switch(version) diff --git a/image/src/terraform_version/required_version.py b/image/src/terraform_version/required_version.py index 6aecba4e..960b632a 100644 --- a/image/src/terraform_version/required_version.py +++ b/image/src/terraform_version/required_version.py @@ -20,7 +20,7 @@ def get_required_version(module: TerraformModule, versions: Iterable[Version]) - def try_get_required_version(module: TerraformModule, versions: Iterable[Version]) -> Optional[Version]: try: return get_required_version(module, versions) - except Exception as e: + except Exception: debug('Failed to get terraform version from required_version constraint') return None