Browse Source

FIX: Replace compromised tj-actions/changed-files (#33481)

# FIX: Replace compromised tj-actions/changed-files

See https://www.stepsecurity.io/blog/harden-runner-detection-tj-actions-changed-files-action-is-compromised .

(Backport from develop)
MDW 2 months ago
parent
commit
324f9631d7
2 changed files with 93 additions and 7 deletions
  1. 86 0
      .github/scripts/get_changed_php.sh
  2. 7 7
      .github/workflows/pre-commit.yml

+ 86 - 0
.github/scripts/get_changed_php.sh

@@ -0,0 +1,86 @@
+#!/bin/bash
+# Copyright (C) 2025		MDW	<mdeweerd@users.noreply.github.com>
+
+set -euo pipefail
+
+# This script retrieves the list of changed PHP files for a pull request
+# using the GitHub API and sets two outputs:
+#   - any_changed: "true" if at least one PHP file changed, "false" otherwise
+#   - all_changed_files: space-separated list of changed PHP file paths
+#
+# Required environment variables:
+#   GITHUB_TOKEN      - GitHub token with repo access
+#   GITHUB_REPOSITORY - "owner/repo"
+#   GITHUB_EVENT_PATH - Path to the event JSON payload
+
+# Verify required environment variables are set
+if [[ -z "${GITHUB_TOKEN:-}" ]]; then
+	echo "GITHUB_TOKEN is not set" >&2
+	exit 1
+fi
+if [[ -z "${GITHUB_REPOSITORY:-}" ]]; then
+	echo "GITHUB_REPOSITORY is not set" >&2
+	exit 1
+fi
+if [[ -z "${GITHUB_EVENT_PATH:-}" ]]; then
+	echo "GITHUB_EVENT_PATH is not set" >&2
+	exit 1
+fi
+
+# Extract the pull request number from the event payload
+pr_number=$(jq --raw-output '.pull_request.number' "$GITHUB_EVENT_PATH")
+if [[ "$pr_number" == "null" ]]; then
+	echo "Not a pull request event"
+	exit 0
+fi
+
+# Split repository into owner and repo name
+# Split repository into owner and repo name using Bash parameter expansion
+owner="${GITHUB_REPOSITORY%%/*}"  # Extract text before the first '/'
+repo="${GITHUB_REPOSITORY##*/}"   # Extract text after the last '/'
+
+page=1
+per_page=100
+changed_php_files=()
+
+# Loop through all pages to gather changed files
+while true; do
+	response=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \
+		"https://api.github.com/repos/${owner}/${repo}/pulls/${pr_number}/files?per_page=${per_page}&page=${page}")
+
+	# Filter for files ending with .php and add them to the list
+	mapfile -t files < <(echo "$response" | jq -r '.[] | select(.filename | test("\\.php$")) | .filename')
+	changed_php_files+=("${files[@]}")
+
+	# Check if we have reached the last page (less than per_page results)
+	count=$(echo "$response" | jq 'length')
+	if (( count < per_page )); then
+		break
+	fi
+	((page++))
+done
+
+
+# Build a space-separated string of changed PHP files
+# This does not cope with files that have spaces.
+# But such files do not exist in the project (at least not for the
+# files we are filtering).
+all_changed_files=$(IFS=" " ; echo "${changed_php_files[*]}")
+
+
+# Determine changed files flag
+if [ -z "$all_changed_files" ]; then
+	any_changed="false"
+else
+	any_changed="true"
+fi
+
+# Set outputs for GitHub Actions if GITHUB_OUTPUT is available
+if [ -n "${GITHUB_OUTPUT:-}" ]; then
+	echo "any_changed=${any_changed}" >> "$GITHUB_OUTPUT"
+	echo "all_changed_files=${all_changed_files}" >> "$GITHUB_OUTPUT"
+else
+	# Otherwise, print the outputs
+	echo "any_changed=${any_changed}"
+	echo "all_changed_files=${all_changed_files}"
+fi

+ 7 - 7
.github/workflows/pre-commit.yml

@@ -14,18 +14,18 @@ jobs:
         run: sudo apt-get update && sudo apt-get install cppcheck
         if: false
 
+      # Checkout git sources to analyze
+      - uses: actions/checkout@v4
+
       # The next uses the git API because there is no clone yet.
       # This is faster for a big repo.
       - name: Get all changed php files (if PR)
         id: changed-php
-        uses: tj-actions/changed-files@v42
-        if: github.event_name == 'pull_request'
-        with:
-          files: |
-            **.php
+        if: env.gh_event == 'pull_request'
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: ./.github/scripts/get_changed_php.sh
 
-      # Checkout git sources to analyze
-      - uses: actions/checkout@v4
       # Action setup-python needs a requirements.txt or pyproject.toml
       # This ensures one of them exists.
       - name: Create requirements.txt if no requirements.txt or pyproject.toml