From 52e77ec03811ec8b3cbc22ec290d3c9e2b104667 Mon Sep 17 00:00:00 2001 From: stranske Date: Thu, 1 Jan 2026 21:25:24 +0000 Subject: [PATCH 1/6] feat: add automated action version sync to templates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add workflow and script to keep templates in sync with action versions after Dependabot merges updates to .github/workflows/. New files: - .github/workflows/maint-sync-action-versions.yml: Automated workflow - scripts/sync_action_versions.sh: Manual sync script Also updates templates to current versions: - actions/checkout: v4 → v6 - actions/download-artifact: v4 → v7 - actions/upload-artifact: v4 → v6 - actions/cache: v4 → v5 This prevents the recurring issue where consumer repo syncs would downgrade action versions that were updated by their own Dependabot. --- .../workflows/maint-sync-action-versions.yml | 150 ++++++++++++++++++ scripts/sync_action_versions.sh | 60 +++++++ templates/ci-basic.yml | 6 +- templates/ci-full.yml | 8 +- .../.github/workflows/agents-autofix-loop.yml | 4 +- .../.github/workflows/agents-guard.yml | 4 +- .../workflows/agents-keepalive-loop.yml | 10 +- .../.github/workflows/agents-pr-meta.yml | 2 +- .../.github/workflows/autofix.yml | 2 +- .../workflows/maint-coverage-guard.yml | 6 +- .../.github/workflows/pr-00-gate.yml | 2 +- templates/cosmetic-repair.yml | 2 +- templates/dependency-refresh.yml | 2 +- .../.github/workflows/notify-workflows.yml | 2 +- 14 files changed, 235 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/maint-sync-action-versions.yml create mode 100755 scripts/sync_action_versions.sh diff --git a/.github/workflows/maint-sync-action-versions.yml b/.github/workflows/maint-sync-action-versions.yml new file mode 100644 index 000000000..ccd6b9597 --- /dev/null +++ b/.github/workflows/maint-sync-action-versions.yml @@ -0,0 +1,150 @@ +name: Maint Sync Action Versions + +# Sync GitHub Action versions from .github/workflows to templates +# after Dependabot merges action version updates. +# +# This ensures templates stay in sync with the latest action versions +# that Dependabot updates in the main workflows. + +on: + push: + branches: [main] + paths: + - '.github/workflows/*.yml' + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + sync-versions: + name: Sync action versions to templates + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Extract action versions from workflows + id: extract + run: | + set -euo pipefail + + # Extract unique action versions from .github/workflows/ + declare -A versions + + for file in .github/workflows/*.yml; do + while IFS= read -r line; do + # Match 'uses: owner/action@version' + if [[ "$line" =~ uses:[[:space:]]*([^[:space:]]+)@(v[0-9]+) ]]; then + action="${BASH_REMATCH[1]}" + version="${BASH_REMATCH[2]}" + # Store highest version for each action + if [[ -z "${versions[$action]:-}" ]] || [[ "$version" > "${versions[$action]}" ]]; then + versions["$action"]="$version" + fi + fi + done < "$file" + done + + # Output versions for key actions + echo "checkout=${versions[actions/checkout]:-v4}" >> "$GITHUB_OUTPUT" + echo "github_script=${versions[actions/github-script]:-v7}" >> "$GITHUB_OUTPUT" + echo "upload_artifact=${versions[actions/upload-artifact]:-v4}" >> "$GITHUB_OUTPUT" + echo "download_artifact=${versions[actions/download-artifact]:-v4}" >> "$GITHUB_OUTPUT" + echo "cache=${versions[actions/cache]:-v4}" >> "$GITHUB_OUTPUT" + + echo "Detected versions:" + for action in "${!versions[@]}"; do + echo " $action: ${versions[$action]}" + done + + - name: Update templates with synced versions + id: update + run: | + set -euo pipefail + + checkout="${{ steps.extract.outputs.checkout }}" + github_script="${{ steps.extract.outputs.github_script }}" + upload_artifact="${{ steps.extract.outputs.upload_artifact }}" + download_artifact="${{ steps.extract.outputs.download_artifact }}" + cache="${{ steps.extract.outputs.cache }}" + + changed=0 + + # Update all YAML files in templates/ + find templates/ -name "*.yml" -type f | while read -r file; do + orig_hash=$(md5sum "$file" | cut -d' ' -f1) + + sed -i \ + -e "s|actions/checkout@v[0-9]\+|actions/checkout@${checkout}|g" \ + -e "s|actions/github-script@v[0-9]\+|actions/github-script@${github_script}|g" \ + -e "s|actions/upload-artifact@v[0-9]\+|actions/upload-artifact@${upload_artifact}|g" \ + -e "s|actions/download-artifact@v[0-9]\+|actions/download-artifact@${download_artifact}|g" \ + -e "s|actions/cache@v[0-9]\+|actions/cache@${cache}|g" \ + "$file" + + new_hash=$(md5sum "$file" | cut -d' ' -f1) + if [[ "$orig_hash" != "$new_hash" ]]; then + echo "Updated: $file" + changed=1 + fi + done + + echo "changed=$changed" >> "$GITHUB_OUTPUT" + + - name: Check for changes + id: check + run: | + if git diff --quiet templates/; then + echo "has_changes=false" >> "$GITHUB_OUTPUT" + echo "No changes to templates" + else + echo "has_changes=true" >> "$GITHUB_OUTPUT" + echo "Changes detected:" + git diff --stat templates/ + fi + + - name: Create PR if changes exist + if: steps.check.outputs.has_changes == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + + branch="auto/sync-action-versions-$(date +%Y%m%d%H%M%S)" + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + git checkout -b "$branch" + git add templates/ + git commit -m "ci(deps): sync action versions to templates + + Automated sync from .github/workflows/ to templates/ + + Updated versions: + - actions/checkout: ${{ steps.extract.outputs.checkout }} + - actions/github-script: ${{ steps.extract.outputs.github_script }} + - actions/upload-artifact: ${{ steps.extract.outputs.upload_artifact }} + - actions/download-artifact: ${{ steps.extract.outputs.download_artifact }} + - actions/cache: ${{ steps.extract.outputs.cache }}" + + git push origin "$branch" + + gh pr create \ + --title "ci(deps): sync action versions to templates" \ + --body "Automated PR to sync GitHub Action versions from \`.github/workflows/\` to \`templates/\`. + + This ensures templates stay in sync with Dependabot updates. + + **Updated versions:** + - actions/checkout: \`${{ steps.extract.outputs.checkout }}\` + - actions/github-script: \`${{ steps.extract.outputs.github_script }}\` + - actions/upload-artifact: \`${{ steps.extract.outputs.upload_artifact }}\` + - actions/download-artifact: \`${{ steps.extract.outputs.download_artifact }}\` + - actions/cache: \`${{ steps.extract.outputs.cache }}\`" \ + --label "dependencies" \ + --label "github-actions" diff --git a/scripts/sync_action_versions.sh b/scripts/sync_action_versions.sh new file mode 100755 index 000000000..59363a274 --- /dev/null +++ b/scripts/sync_action_versions.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# Sync GitHub Action versions from .github/workflows/ to templates/ +# Run this after Dependabot updates are merged to keep templates in sync. +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(dirname "$SCRIPT_DIR")" + +cd "$REPO_ROOT" + +# Extract versions from .github/workflows/ +declare -A versions + +echo "Extracting versions from .github/workflows/..." +for file in .github/workflows/*.yml; do + while IFS= read -r line; do + if [[ "$line" =~ uses:[[:space:]]*([^[:space:]]+)@(v[0-9]+) ]]; then + action="${BASH_REMATCH[1]}" + version="${BASH_REMATCH[2]}" + if [[ -z "${versions[$action]:-}" ]] || [[ "$version" > "${versions[$action]}" ]]; then + versions["$action"]="$version" + fi + fi + done < "$file" +done + +echo "" +echo "Detected versions:" +for action in "${!versions[@]}"; do + echo " $action: ${versions[$action]}" +done + +checkout="${versions[actions/checkout]:-v4}" +github_script="${versions[actions/github-script]:-v7}" +upload_artifact="${versions[actions/upload-artifact]:-v4}" +download_artifact="${versions[actions/download-artifact]:-v4}" +cache="${versions[actions/cache]:-v4}" + +echo "" +echo "Updating templates/..." + +# Update templates +find templates/ -name "*.yml" -type f | while read -r file; do + orig=$(cat "$file") + + sed -i \ + -e "s|actions/checkout@v[0-9]\+|actions/checkout@${checkout}|g" \ + -e "s|actions/github-script@v[0-9]\+|actions/github-script@${github_script}|g" \ + -e "s|actions/upload-artifact@v[0-9]\+|actions/upload-artifact@${upload_artifact}|g" \ + -e "s|actions/download-artifact@v[0-9]\+|actions/download-artifact@${download_artifact}|g" \ + -e "s|actions/cache@v[0-9]\+|actions/cache@${cache}|g" \ + "$file" + + if [[ "$(cat "$file")" != "$orig" ]]; then + echo " Updated: $file" + fi +done + +echo "" +echo "Done. Run 'git diff templates/' to see changes." diff --git a/templates/ci-basic.yml b/templates/ci-basic.yml index 56e524150..30d0e5c50 100644 --- a/templates/ci-basic.yml +++ b/templates/ci-basic.yml @@ -22,7 +22,7 @@ jobs: name: Lint & Format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup Python uses: actions/setup-python@v5 @@ -42,7 +42,7 @@ jobs: name: Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup Python uses: actions/setup-python@v5 @@ -70,7 +70,7 @@ jobs: name: Type Check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup Python uses: actions/setup-python@v5 diff --git a/templates/ci-full.yml b/templates/ci-full.yml index 05562876e..ad700be76 100644 --- a/templates/ci-full.yml +++ b/templates/ci-full.yml @@ -29,7 +29,7 @@ jobs: name: Smoke Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup Python uses: actions/setup-python@v5 @@ -55,7 +55,7 @@ jobs: name: Lint & Format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup Python uses: actions/setup-python@v5 @@ -78,7 +78,7 @@ jobs: name: Type Check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup Python uses: actions/setup-python@v5 @@ -103,7 +103,7 @@ jobs: # CUSTOMIZE: Python versions to test python-version: ['3.11', '3.12'] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup Python ${{ matrix.python-version }} uses: actions/setup-python@v5 diff --git a/templates/consumer-repo/.github/workflows/agents-autofix-loop.yml b/templates/consumer-repo/.github/workflows/agents-autofix-loop.yml index 23a343272..b06ffc45c 100644 --- a/templates/consumer-repo/.github/workflows/agents-autofix-loop.yml +++ b/templates/consumer-repo/.github/workflows/agents-autofix-loop.yml @@ -39,7 +39,7 @@ jobs: security_reason: ${{ steps.security_gate.outputs.reason }} steps: - name: Checkout (for security gate) - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: sparse-checkout: | .github/scripts/prompt_injection_guard.js @@ -492,7 +492,7 @@ jobs: PY - name: Upload metrics artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: agents-autofix-metrics path: autofix-metrics.ndjson diff --git a/templates/consumer-repo/.github/workflows/agents-guard.yml b/templates/consumer-repo/.github/workflows/agents-guard.yml index 7a3e22585..436f7d960 100644 --- a/templates/consumer-repo/.github/workflows/agents-guard.yml +++ b/templates/consumer-repo/.github/workflows/agents-guard.yml @@ -33,7 +33,7 @@ jobs: steps: - name: Checkout base ref for safety validation if: github.event_name == 'pull_request_target' - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.base.sha }} sparse-checkout: | @@ -58,7 +58,7 @@ jobs: - name: Checkout PR head for pull_request event if: github.event_name == 'pull_request' - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: sparse-checkout: | .github/scripts/agents-guard.js diff --git a/templates/consumer-repo/.github/workflows/agents-keepalive-loop.yml b/templates/consumer-repo/.github/workflows/agents-keepalive-loop.yml index 6dcebe889..9c7c27d20 100644 --- a/templates/consumer-repo/.github/workflows/agents-keepalive-loop.yml +++ b/templates/consumer-repo/.github/workflows/agents-keepalive-loop.yml @@ -72,12 +72,12 @@ jobs: steps: # Dual checkout pattern: consumer repo for context, Workflows repo for scripts - name: Checkout consumer repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: path: consumer - name: Checkout Workflows scripts - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: repository: stranske/Workflows ref: main @@ -282,7 +282,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Workflows scripts - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: repository: stranske/Workflows ref: main @@ -342,7 +342,7 @@ jobs: environment: agent-standard steps: - name: Checkout Workflows scripts - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: repository: stranske/Workflows ref: main @@ -419,7 +419,7 @@ jobs: echo "$metrics_json" >> keepalive-metrics.ndjson - name: Upload keepalive metrics artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: keepalive-metrics path: keepalive-metrics.ndjson diff --git a/templates/consumer-repo/.github/workflows/agents-pr-meta.yml b/templates/consumer-repo/.github/workflows/agents-pr-meta.yml index 58300b0c5..cb4e17c23 100644 --- a/templates/consumer-repo/.github/workflows/agents-pr-meta.yml +++ b/templates/consumer-repo/.github/workflows/agents-pr-meta.yml @@ -59,7 +59,7 @@ jobs: steps: - name: Resolve PR context id: resolve - uses: actions/github-script@v8 + uses: actions/github-script@v7 with: script: | const pr = context.payload.issue; diff --git a/templates/consumer-repo/.github/workflows/autofix.yml b/templates/consumer-repo/.github/workflows/autofix.yml index 11850fff8..eb60edd47 100644 --- a/templates/consumer-repo/.github/workflows/autofix.yml +++ b/templates/consumer-repo/.github/workflows/autofix.yml @@ -49,7 +49,7 @@ jobs: steps: - name: Resolve PR context id: context - uses: actions/github-script@v8 + uses: actions/github-script@v7 with: script: | const pr = context.payload.pull_request; diff --git a/templates/consumer-repo/.github/workflows/maint-coverage-guard.yml b/templates/consumer-repo/.github/workflows/maint-coverage-guard.yml index bb033bc03..6eef4f731 100644 --- a/templates/consumer-repo/.github/workflows/maint-coverage-guard.yml +++ b/templates/consumer-repo/.github/workflows/maint-coverage-guard.yml @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Locate latest Gate workflow run id: discover @@ -79,7 +79,7 @@ jobs: - name: Download coverage trend artifact if: ${{ steps.discover.outputs.run_id }} - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v7 continue-on-error: true with: name: gate-coverage-trend @@ -89,7 +89,7 @@ jobs: - name: Download coverage artifact if: ${{ steps.discover.outputs.run_id }} - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v7 continue-on-error: true with: pattern: gate-coverage-* diff --git a/templates/consumer-repo/.github/workflows/pr-00-gate.yml b/templates/consumer-repo/.github/workflows/pr-00-gate.yml index 5511d00b4..1eed8264e 100644 --- a/templates/consumer-repo/.github/workflows/pr-00-gate.yml +++ b/templates/consumer-repo/.github/workflows/pr-00-gate.yml @@ -65,7 +65,7 @@ jobs: description: ${{ steps.summarize.outputs.description }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: sparse-checkout: | .github/scripts diff --git a/templates/cosmetic-repair.yml b/templates/cosmetic-repair.yml index ccac27f42..c975e502e 100644 --- a/templates/cosmetic-repair.yml +++ b/templates/cosmetic-repair.yml @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 diff --git a/templates/dependency-refresh.yml b/templates/dependency-refresh.yml index e5acbdb30..df9626ac3 100644 --- a/templates/dependency-refresh.yml +++ b/templates/dependency-refresh.yml @@ -35,7 +35,7 @@ jobs: DRY_RUN: ${{ inputs.dry-run || 'false' }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 diff --git a/templates/integration-repo/.github/workflows/notify-workflows.yml b/templates/integration-repo/.github/workflows/notify-workflows.yml index 56eb42da9..c9600fe9f 100644 --- a/templates/integration-repo/.github/workflows/notify-workflows.yml +++ b/templates/integration-repo/.github/workflows/notify-workflows.yml @@ -52,7 +52,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout this repo - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: path: integration-tests From bffeddde39ee368fd83cd7b4bb73dca1dceb527e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 1 Jan 2026 21:37:43 +0000 Subject: [PATCH 2/6] chore(codex-autofix): apply updates (PR #444) --- .workflows-lib | 2 +- tests/workflows/fixtures/keepalive/harness.js | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.workflows-lib b/.workflows-lib index 5a7ab0492..19f6bd0af 160000 --- a/.workflows-lib +++ b/.workflows-lib @@ -1 +1 @@ -Subproject commit 5a7ab0492b27501f6ba46fcda452ab24207633d8 +Subproject commit 19f6bd0afb904487be5fd3b63497d1d84d14b082 diff --git a/tests/workflows/fixtures/keepalive/harness.js b/tests/workflows/fixtures/keepalive/harness.js index 076cd8a66..7b2790fc3 100755 --- a/tests/workflows/fixtures/keepalive/harness.js +++ b/tests/workflows/fixtures/keepalive/harness.js @@ -352,9 +352,20 @@ async function runScenario(scenario) { actions_bot_pat: '', ...(scenario.env || {}), }; + const tokenKeys = new Set([ + 'ACTIONS_BOT_PAT', + 'SERVICE_BOT_PAT', + 'GH_TOKEN', + 'gh_token', + 'actions_bot_pat', + ]); for (const [key, value] of Object.entries(envOverrides)) { originalEnv[key] = process.env[key]; - process.env[key] = String(value); + if (value === '' && tokenKeys.has(key)) { + delete process.env[key]; + } else { + process.env[key] = String(value); + } } const originalNow = Date.now; From da4e40e22ec8700c9a95287394f32e7d2d7074ca Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 1 Jan 2026 21:44:51 +0000 Subject: [PATCH 3/6] chore(codex-autofix): apply updates (PR #444) --- tests/workflows/fixtures/keepalive/harness.js | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/tests/workflows/fixtures/keepalive/harness.js b/tests/workflows/fixtures/keepalive/harness.js index 7b2790fc3..e11e98d11 100755 --- a/tests/workflows/fixtures/keepalive/harness.js +++ b/tests/workflows/fixtures/keepalive/harness.js @@ -343,7 +343,6 @@ async function runScenario(scenario) { }, }; - const originalEnv = {}; const envOverrides = { ACTIONS_BOT_PAT: 'dummy-token', SERVICE_BOT_PAT: 'service-token', @@ -359,13 +358,12 @@ async function runScenario(scenario) { 'gh_token', 'actions_bot_pat', ]); + const env = {}; for (const [key, value] of Object.entries(envOverrides)) { - originalEnv[key] = process.env[key]; if (value === '' && tokenKeys.has(key)) { - delete process.env[key]; - } else { - process.env[key] = String(value); + continue; } + env[key] = String(value); } const originalNow = Date.now; @@ -376,16 +374,9 @@ async function runScenario(scenario) { try { const { runKeepalive } = loadKeepaliveRunner(); - await runKeepalive({ core, github, context, env: process.env }); + await runKeepalive({ core, github, context, env }); } finally { Date.now = originalNow; - for (const [key, value] of Object.entries(originalEnv)) { - if (value === undefined) { - delete process.env[key]; - } else { - process.env[key] = value; - } - } } return { From 1c75bd0e759a2e2d8dc826462a7037e00a487bdd Mon Sep 17 00:00:00 2001 From: stranske Date: Thu, 1 Jan 2026 21:43:39 +0000 Subject: [PATCH 4/6] fix: correct action versions and comparison logic - Revert checkout from v6 to v4 (v6 is very new, staying with v4 for stability) - Keep upload-artifact@v6 and download-artifact@v7 (matching main workflows) - Fix version comparison: use numeric instead of string comparison - Fix subshell variable issue: use for loop instead of pipe to while Addresses Copilot review comments on PR #444 --- .../workflows/maint-sync-action-versions.yml | 19 ++++++++++--------- scripts/sync_action_versions.sh | 9 ++++++++- templates/ci-basic.yml | 6 +++--- templates/ci-full.yml | 8 ++++---- .../.github/workflows/agents-autofix-loop.yml | 2 +- .../.github/workflows/agents-guard.yml | 4 ++-- .../workflows/agents-keepalive-loop.yml | 8 ++++---- .../workflows/maint-coverage-guard.yml | 2 +- .../.github/workflows/pr-00-gate.yml | 2 +- templates/cosmetic-repair.yml | 2 +- templates/dependency-refresh.yml | 2 +- .../.github/workflows/notify-workflows.yml | 2 +- 12 files changed, 37 insertions(+), 29 deletions(-) diff --git a/.github/workflows/maint-sync-action-versions.yml b/.github/workflows/maint-sync-action-versions.yml index ccd6b9597..d4c091d5e 100644 --- a/.github/workflows/maint-sync-action-versions.yml +++ b/.github/workflows/maint-sync-action-versions.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -41,9 +41,15 @@ jobs: if [[ "$line" =~ uses:[[:space:]]*([^[:space:]]+)@(v[0-9]+) ]]; then action="${BASH_REMATCH[1]}" version="${BASH_REMATCH[2]}" - # Store highest version for each action - if [[ -z "${versions[$action]:-}" ]] || [[ "$version" > "${versions[$action]}" ]]; then + # Use numeric comparison for versions + if [[ -z "${versions[$action]:-}" ]]; then versions["$action"]="$version" + else + new_num="${version#v}" + current_num="${versions[$action]#v}" + if (( new_num > current_num )); then + versions["$action"]="$version" + fi fi fi done < "$file" @@ -72,10 +78,8 @@ jobs: download_artifact="${{ steps.extract.outputs.download_artifact }}" cache="${{ steps.extract.outputs.cache }}" - changed=0 - # Update all YAML files in templates/ - find templates/ -name "*.yml" -type f | while read -r file; do + for file in $(find templates/ -name "*.yml" -type f); do orig_hash=$(md5sum "$file" | cut -d' ' -f1) sed -i \ @@ -89,11 +93,8 @@ jobs: new_hash=$(md5sum "$file" | cut -d' ' -f1) if [[ "$orig_hash" != "$new_hash" ]]; then echo "Updated: $file" - changed=1 fi done - - echo "changed=$changed" >> "$GITHUB_OUTPUT" - name: Check for changes id: check diff --git a/scripts/sync_action_versions.sh b/scripts/sync_action_versions.sh index 59363a274..31663011b 100755 --- a/scripts/sync_action_versions.sh +++ b/scripts/sync_action_versions.sh @@ -17,8 +17,15 @@ for file in .github/workflows/*.yml; do if [[ "$line" =~ uses:[[:space:]]*([^[:space:]]+)@(v[0-9]+) ]]; then action="${BASH_REMATCH[1]}" version="${BASH_REMATCH[2]}" - if [[ -z "${versions[$action]:-}" ]] || [[ "$version" > "${versions[$action]}" ]]; then + # Use numeric comparison for versions + if [[ -z "${versions[$action]:-}" ]]; then versions["$action"]="$version" + else + new_num="${version#v}" + current_num="${versions[$action]#v}" + if (( new_num > current_num )); then + versions["$action"]="$version" + fi fi fi done < "$file" diff --git a/templates/ci-basic.yml b/templates/ci-basic.yml index 30d0e5c50..56e524150 100644 --- a/templates/ci-basic.yml +++ b/templates/ci-basic.yml @@ -22,7 +22,7 @@ jobs: name: Lint & Format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 @@ -42,7 +42,7 @@ jobs: name: Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 @@ -70,7 +70,7 @@ jobs: name: Type Check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 diff --git a/templates/ci-full.yml b/templates/ci-full.yml index ad700be76..05562876e 100644 --- a/templates/ci-full.yml +++ b/templates/ci-full.yml @@ -29,7 +29,7 @@ jobs: name: Smoke Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 @@ -55,7 +55,7 @@ jobs: name: Lint & Format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 @@ -78,7 +78,7 @@ jobs: name: Type Check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 @@ -103,7 +103,7 @@ jobs: # CUSTOMIZE: Python versions to test python-version: ['3.11', '3.12'] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - name: Setup Python ${{ matrix.python-version }} uses: actions/setup-python@v5 diff --git a/templates/consumer-repo/.github/workflows/agents-autofix-loop.yml b/templates/consumer-repo/.github/workflows/agents-autofix-loop.yml index b06ffc45c..e24cc312a 100644 --- a/templates/consumer-repo/.github/workflows/agents-autofix-loop.yml +++ b/templates/consumer-repo/.github/workflows/agents-autofix-loop.yml @@ -39,7 +39,7 @@ jobs: security_reason: ${{ steps.security_gate.outputs.reason }} steps: - name: Checkout (for security gate) - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: sparse-checkout: | .github/scripts/prompt_injection_guard.js diff --git a/templates/consumer-repo/.github/workflows/agents-guard.yml b/templates/consumer-repo/.github/workflows/agents-guard.yml index 436f7d960..7a3e22585 100644 --- a/templates/consumer-repo/.github/workflows/agents-guard.yml +++ b/templates/consumer-repo/.github/workflows/agents-guard.yml @@ -33,7 +33,7 @@ jobs: steps: - name: Checkout base ref for safety validation if: github.event_name == 'pull_request_target' - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.base.sha }} sparse-checkout: | @@ -58,7 +58,7 @@ jobs: - name: Checkout PR head for pull_request event if: github.event_name == 'pull_request' - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: sparse-checkout: | .github/scripts/agents-guard.js diff --git a/templates/consumer-repo/.github/workflows/agents-keepalive-loop.yml b/templates/consumer-repo/.github/workflows/agents-keepalive-loop.yml index 9c7c27d20..e63c93eac 100644 --- a/templates/consumer-repo/.github/workflows/agents-keepalive-loop.yml +++ b/templates/consumer-repo/.github/workflows/agents-keepalive-loop.yml @@ -72,12 +72,12 @@ jobs: steps: # Dual checkout pattern: consumer repo for context, Workflows repo for scripts - name: Checkout consumer repository - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: path: consumer - name: Checkout Workflows scripts - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: repository: stranske/Workflows ref: main @@ -282,7 +282,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Workflows scripts - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: repository: stranske/Workflows ref: main @@ -342,7 +342,7 @@ jobs: environment: agent-standard steps: - name: Checkout Workflows scripts - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: repository: stranske/Workflows ref: main diff --git a/templates/consumer-repo/.github/workflows/maint-coverage-guard.yml b/templates/consumer-repo/.github/workflows/maint-coverage-guard.yml index 6eef4f731..a993ec038 100644 --- a/templates/consumer-repo/.github/workflows/maint-coverage-guard.yml +++ b/templates/consumer-repo/.github/workflows/maint-coverage-guard.yml @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v4 - name: Locate latest Gate workflow run id: discover diff --git a/templates/consumer-repo/.github/workflows/pr-00-gate.yml b/templates/consumer-repo/.github/workflows/pr-00-gate.yml index 1eed8264e..5511d00b4 100644 --- a/templates/consumer-repo/.github/workflows/pr-00-gate.yml +++ b/templates/consumer-repo/.github/workflows/pr-00-gate.yml @@ -65,7 +65,7 @@ jobs: description: ${{ steps.summarize.outputs.description }} steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: sparse-checkout: | .github/scripts diff --git a/templates/cosmetic-repair.yml b/templates/cosmetic-repair.yml index c975e502e..ccac27f42 100644 --- a/templates/cosmetic-repair.yml +++ b/templates/cosmetic-repair.yml @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/templates/dependency-refresh.yml b/templates/dependency-refresh.yml index df9626ac3..e5acbdb30 100644 --- a/templates/dependency-refresh.yml +++ b/templates/dependency-refresh.yml @@ -35,7 +35,7 @@ jobs: DRY_RUN: ${{ inputs.dry-run || 'false' }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/templates/integration-repo/.github/workflows/notify-workflows.yml b/templates/integration-repo/.github/workflows/notify-workflows.yml index c9600fe9f..56eb42da9 100644 --- a/templates/integration-repo/.github/workflows/notify-workflows.yml +++ b/templates/integration-repo/.github/workflows/notify-workflows.yml @@ -52,7 +52,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout this repo - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: path: integration-tests From 87cac142d3849b629915008fcbf1f7495c7d5e90 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 1 Jan 2026 21:49:14 +0000 Subject: [PATCH 5/6] chore(codex-autofix): apply updates (PR #444) --- docs/ci/WORKFLOWS.md | 1 + docs/ci/WORKFLOW_SYSTEM.md | 3 +++ tests/workflows/test_workflow_naming.py | 1 + 3 files changed, 5 insertions(+) diff --git a/docs/ci/WORKFLOWS.md b/docs/ci/WORKFLOWS.md index 6bfb1463c..86ade5179 100644 --- a/docs/ci/WORKFLOWS.md +++ b/docs/ci/WORKFLOWS.md @@ -98,6 +98,7 @@ The gate uses the shared `.github/scripts/detect-changes.js` helper to decide wh * [`reusable-20-pr-meta.yml`](../../.github/workflows/reusable-20-pr-meta.yml) detects keepalive round-marker comments in PRs, dispatches the orchestrator when detected, and manages PR body section updates for consumer repositories using the dual-checkout pattern. * [`maint-45-cosmetic-repair.yml`](../../.github/workflows/maint-45-cosmetic-repair.yml) invokes the reusable autofix pipeline on a schedule to keep cosmetic issues in check. * [`maint-47-disable-legacy-workflows.yml`](../../.github/workflows/maint-47-disable-legacy-workflows.yml) sweeps the repository to make sure archived GitHub workflows remain disabled in the Actions UI. +* [`maint-sync-action-versions.yml`](../../.github/workflows/maint-sync-action-versions.yml) syncs action version pins from `.github/workflows` into the workflow templates after Dependabot updates land. * [`maint-50-tool-version-check.yml`](../../.github/workflows/maint-50-tool-version-check.yml) checks PyPI weekly for new versions of CI/autofix tools (black, ruff, mypy, pytest) and creates an issue when updates are available. * [`maint-51-dependency-refresh.yml`](../../.github/workflows/maint-51-dependency-refresh.yml) regenerates `requirements.lock` using `uv pip compile`, validates tool-pin alignment, and opens a refresh pull request when dependency updates are detected (dry-run friendly). * [`maint-sync-env-from-pyproject.yml`](../../.github/workflows/maint-sync-env-from-pyproject.yml) syncs dev tool version pins from `pyproject.toml` to `autofix-versions.env` after Dependabot updates land. diff --git a/docs/ci/WORKFLOW_SYSTEM.md b/docs/ci/WORKFLOW_SYSTEM.md index 2dd0b5d1f..7bb96fb0e 100644 --- a/docs/ci/WORKFLOW_SYSTEM.md +++ b/docs/ci/WORKFLOW_SYSTEM.md @@ -511,6 +511,9 @@ Keep this table handy when you are triaging automation: it confirms which workfl - **Maint 47 Disable Legacy Workflows** – `.github/workflows/maint-47-disable-legacy-workflows.yml` runs on-demand and disables archived workflows still listed as active in the Actions UI. +- **Maint Sync Action Versions** – `.github/workflows/maint-sync-action-versions.yml` + syncs action version pins from `.github/workflows` into workflow templates after + Dependabot updates land. - **Maint 50 Tool Version Check** – `.github/workflows/maint-50-tool-version-check.yml` runs weekly (Mondays 8:00 AM UTC) to check PyPI for new versions of CI/autofix tools (black, ruff, mypy, pytest, etc.) and creates an issue when updates are available. diff --git a/tests/workflows/test_workflow_naming.py b/tests/workflows/test_workflow_naming.py index dc13091dc..b5bb2c4e4 100644 --- a/tests/workflows/test_workflow_naming.py +++ b/tests/workflows/test_workflow_naming.py @@ -193,6 +193,7 @@ def test_workflow_display_names_are_unique(): "maint-47-disable-legacy-workflows.yml": "Maint 47 Disable Legacy Workflows", "maint-50-tool-version-check.yml": "Maint 50 Tool Version Check", "maint-51-dependency-refresh.yml": "Maint 51 Dependency Refresh", + "maint-sync-action-versions.yml": "Maint Sync Action Versions", "maint-sync-env-from-pyproject.yml": "Maint - Sync versions.env from pyproject.toml", "maint-52-validate-workflows.yml": "Maint 52 Validate Workflows", "maint-52-sync-dev-versions.yml": "Maint 52 Sync Dev Versions", From 260aa8bc238086605aab523cdbc568da6d77465e Mon Sep 17 00:00:00 2001 From: stranske Date: Thu, 1 Jan 2026 21:58:19 +0000 Subject: [PATCH 6/6] fix: address shellcheck warnings SC2129 and SC2044 - SC2129: Use grouped redirects { ... } >> file for GITHUB_OUTPUT - SC2044: Use find -exec instead of for loop over find output --- .../workflows/maint-sync-action-versions.yml | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/.github/workflows/maint-sync-action-versions.yml b/.github/workflows/maint-sync-action-versions.yml index d4c091d5e..ba8f392a1 100644 --- a/.github/workflows/maint-sync-action-versions.yml +++ b/.github/workflows/maint-sync-action-versions.yml @@ -55,12 +55,14 @@ jobs: done < "$file" done - # Output versions for key actions - echo "checkout=${versions[actions/checkout]:-v4}" >> "$GITHUB_OUTPUT" - echo "github_script=${versions[actions/github-script]:-v7}" >> "$GITHUB_OUTPUT" - echo "upload_artifact=${versions[actions/upload-artifact]:-v4}" >> "$GITHUB_OUTPUT" - echo "download_artifact=${versions[actions/download-artifact]:-v4}" >> "$GITHUB_OUTPUT" - echo "cache=${versions[actions/cache]:-v4}" >> "$GITHUB_OUTPUT" + # Output versions for key actions (grouped redirects for SC2129) + { + echo "checkout=${versions[actions/checkout]:-v4}" + echo "github_script=${versions[actions/github-script]:-v7}" + echo "upload_artifact=${versions[actions/upload-artifact]:-v4}" + echo "download_artifact=${versions[actions/download-artifact]:-v4}" + echo "cache=${versions[actions/cache]:-v4}" + } >> "$GITHUB_OUTPUT" echo "Detected versions:" for action in "${!versions[@]}"; do @@ -78,23 +80,25 @@ jobs: download_artifact="${{ steps.extract.outputs.download_artifact }}" cache="${{ steps.extract.outputs.cache }}" - # Update all YAML files in templates/ - for file in $(find templates/ -name "*.yml" -type f); do - orig_hash=$(md5sum "$file" | cut -d' ' -f1) - - sed -i \ - -e "s|actions/checkout@v[0-9]\+|actions/checkout@${checkout}|g" \ - -e "s|actions/github-script@v[0-9]\+|actions/github-script@${github_script}|g" \ - -e "s|actions/upload-artifact@v[0-9]\+|actions/upload-artifact@${upload_artifact}|g" \ - -e "s|actions/download-artifact@v[0-9]\+|actions/download-artifact@${download_artifact}|g" \ - -e "s|actions/cache@v[0-9]\+|actions/cache@${cache}|g" \ - "$file" - - new_hash=$(md5sum "$file" | cut -d' ' -f1) - if [[ "$orig_hash" != "$new_hash" ]]; then - echo "Updated: $file" - fi - done + # Update all YAML files in templates/ (using find -exec for SC2044) + find templates/ -name "*.yml" -type f -exec sh -c ' + for file do + orig_hash=$(md5sum "$file" | cut -d" " -f1) + + sed -i \ + -e "s|actions/checkout@v[0-9]\+|actions/checkout@'"${checkout}"'|g" \ + -e "s|actions/github-script@v[0-9]\+|actions/github-script@'"${github_script}"'|g" \ + -e "s|actions/upload-artifact@v[0-9]\+|actions/upload-artifact@'"${upload_artifact}"'|g" \ + -e "s|actions/download-artifact@v[0-9]\+|actions/download-artifact@'"${download_artifact}"'|g" \ + -e "s|actions/cache@v[0-9]\+|actions/cache@'"${cache}"'|g" \ + "$file" + + new_hash=$(md5sum "$file" | cut -d" " -f1) + if [ "$orig_hash" != "$new_hash" ]; then + echo "Updated: $file" + fi + done + ' sh {} + - name: Check for changes id: check