Validate PAT Pool #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Validate PAT Pool | |
| on: | |
| schedule: | |
| - cron: '17 2 * * *' # Daily at ~2:17 AM UTC (off-round to reduce contention) | |
| workflow_dispatch: | |
| # No GitHub API permissions needed | |
| permissions: {} | |
| jobs: | |
| validate: | |
| name: Validate Copilot PAT Pool | |
| if: ${{ github.event_name == 'workflow_dispatch' || !github.event.repository.fork }} | |
| runs-on: ubuntu-latest | |
| env: | |
| VALIDATE_PAT: | | |
| if [ -z "$COPILOT_GITHUB_TOKEN" ]; then echo "status=empty" >> "$GITHUB_OUTPUT"; exit 0; fi | |
| set +e; timeout 30 copilot --prompt "Say OK" --available-tools="" --silent --effort=low; rc=$?; set -e | |
| if [ $rc -eq 0 ]; then echo "status=valid" >> "$GITHUB_OUTPUT" | |
| elif [ $rc -eq 124 ]; then echo "status=unknown" >> "$GITHUB_OUTPUT" | |
| else echo "status=invalid" >> "$GITHUB_OUTPUT"; fi | |
| steps: | |
| - name: Setup gh-aw scripts | |
| uses: github/gh-aw-actions/setup@8cfea5ae9bee18df8e50a96affdb6d666cd7b9a3 # v0.78.3 | |
| with: | |
| destination: ${{ runner.temp }}/gh-aw/actions | |
| - name: Install Copilot CLI | |
| run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55 | |
| # ----------------------------------------------------------- | |
| # Make a Copilot CLI request with each PAT in the pool. | |
| # Each step sets COPILOT_GITHUB_TOKEN directly from the secret | |
| # via env: so the value never passes through shell variables. | |
| # The pool maps slot 0 -> COPILOT_GITHUB_TOKEN and slots 1-7 -> | |
| # COPILOT_GITHUB_TOKEN_2 .. COPILOT_GITHUB_TOKEN_8. | |
| # ----------------------------------------------------------- | |
| - name: Validate COPILOT_GITHUB_TOKEN | |
| id: pat0 | |
| continue-on-error: true | |
| env: | |
| COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} | |
| shell: bash | |
| run: | | |
| # copilot --prompt "Say OK" | |
| eval "$VALIDATE_PAT" | |
| - name: Validate COPILOT_GITHUB_TOKEN_2 | |
| id: pat1 | |
| continue-on-error: true | |
| env: | |
| COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }} | |
| shell: bash | |
| run: | | |
| # copilot --prompt "Say OK" | |
| eval "$VALIDATE_PAT" | |
| - name: Validate COPILOT_GITHUB_TOKEN_3 | |
| id: pat2 | |
| continue-on-error: true | |
| env: | |
| COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }} | |
| shell: bash | |
| run: | | |
| # copilot --prompt "Say OK" | |
| eval "$VALIDATE_PAT" | |
| - name: Validate COPILOT_GITHUB_TOKEN_4 | |
| id: pat3 | |
| continue-on-error: true | |
| env: | |
| COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }} | |
| shell: bash | |
| run: | | |
| # copilot --prompt "Say OK" | |
| eval "$VALIDATE_PAT" | |
| - name: Validate COPILOT_GITHUB_TOKEN_5 | |
| id: pat4 | |
| continue-on-error: true | |
| env: | |
| COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }} | |
| shell: bash | |
| run: | | |
| # copilot --prompt "Say OK" | |
| eval "$VALIDATE_PAT" | |
| - name: Validate COPILOT_GITHUB_TOKEN_6 | |
| id: pat5 | |
| continue-on-error: true | |
| env: | |
| COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }} | |
| shell: bash | |
| run: | | |
| # copilot --prompt "Say OK" | |
| eval "$VALIDATE_PAT" | |
| - name: Validate COPILOT_GITHUB_TOKEN_7 | |
| id: pat6 | |
| continue-on-error: true | |
| env: | |
| COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }} | |
| shell: bash | |
| run: | | |
| # copilot --prompt "Say OK" | |
| eval "$VALIDATE_PAT" | |
| - name: Validate COPILOT_GITHUB_TOKEN_8 | |
| id: pat7 | |
| continue-on-error: true | |
| env: | |
| COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }} | |
| shell: bash | |
| run: | | |
| # copilot --prompt "Say OK" | |
| eval "$VALIDATE_PAT" | |
| # ----------------------------------------------------------- | |
| # Collect results and build the step summary | |
| # ----------------------------------------------------------- | |
| - name: Build summary | |
| if: always() | |
| env: | |
| S0: ${{ steps.pat0.outputs.status }} | |
| S1: ${{ steps.pat1.outputs.status }} | |
| S2: ${{ steps.pat2.outputs.status }} | |
| S3: ${{ steps.pat3.outputs.status }} | |
| S4: ${{ steps.pat4.outputs.status }} | |
| S5: ${{ steps.pat5.outputs.status }} | |
| S6: ${{ steps.pat6.outputs.status }} | |
| S7: ${{ steps.pat7.outputs.status }} | |
| shell: bash | |
| run: | | |
| # Build summary | |
| statuses=("$S0" "$S1" "$S2" "$S3" "$S4" "$S5" "$S6" "$S7") | |
| names=("COPILOT_GITHUB_TOKEN" "COPILOT_GITHUB_TOKEN_2" "COPILOT_GITHUB_TOKEN_3" "COPILOT_GITHUB_TOKEN_4" "COPILOT_GITHUB_TOKEN_5" "COPILOT_GITHUB_TOKEN_6" "COPILOT_GITHUB_TOKEN_7" "COPILOT_GITHUB_TOKEN_8") | |
| valid=0; empty=0; invalid=0; unknown=0 | |
| for s in "${statuses[@]}"; do | |
| case "$s" in | |
| valid) valid=$((valid + 1)) ;; | |
| empty) empty=$((empty + 1)) ;; | |
| invalid) invalid=$((invalid + 1)) ;; | |
| *) unknown=$((unknown + 1)) ;; | |
| esac | |
| done | |
| { | |
| if [ $invalid -eq 0 ] && [ $unknown -eq 0 ] && [ $valid -gt 0 ]; then | |
| echo "> [!NOTE]" | |
| echo "> **PAT pool is valid** — no action needed" | |
| echo "" | |
| fi | |
| if [ $invalid -eq 0 ] && [ $unknown -eq 0 ] && [ $valid -eq 0 ]; then | |
| echo "> [!WARNING]" | |
| echo "> **Empty PAT pool** — agentic workflows will fall back to the default \`COPILOT_GITHUB_TOKEN\`." | |
| echo "" | |
| fi | |
| if [ $invalid -gt 0 ]; then | |
| echo "> [!CAUTION]" | |
| echo "> **Invalid PAT pool** — agentic workflows selecting an invalid PAT will fail." | |
| echo "" | |
| fi | |
| if [ $unknown -gt 0 ]; then | |
| echo "> [!WARNING]" | |
| echo "> **PAT pool not verified** due to transient errors — re-run the workflow to retry." | |
| echo "" | |
| fi | |
| echo "☑️ Valid: ${valid} • ⏹️ Empty: ${empty} • ❌ Invalid: ${invalid} • ❓ Unknown: ${unknown}" | |
| echo "" | |
| echo "| PAT Secret | Status |" | |
| echo "|:-----------|:-------|" | |
| for i in $(seq 0 7); do | |
| case "${statuses[$i]}" in | |
| valid) symbol="☑️ Valid" ;; | |
| empty) symbol="⏹️ Empty" ;; | |
| invalid) symbol="❌ Invalid" ;; | |
| *) symbol="❓ Unknown" ;; | |
| esac | |
| echo "| \`${names[$i]}\` | ${symbol} |" | |
| done | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| if [ $invalid -gt 0 ]; then | |
| echo "::error::${invalid} PAT(s) in the pool are invalid and need to be removed or replaced" | |
| exit 1 | |
| fi | |
| if [ $unknown -gt 0 ]; then | |
| echo "::error::${unknown} PAT(s) could not be verified due to transient errors — re-run to retry" | |
| exit 1 | |
| fi | |
| if [ $valid -eq 0 ]; then | |
| echo "::error::The PAT pool is empty — no PATs are available" | |
| exit 1 | |
| fi | |
| echo "PAT pool validation passed: ${valid} valid PAT(s)" |