name: VRT Update - Apply # SECURITY: This workflow runs in trusted base repo context. # It treats the patch artifact as untrusted data, validates it contains only PNGs, # and safely applies it to the contributor's fork branch. on: workflow_run: workflows: ['VRT Update - Generate'] types: - completed permissions: contents: write pull-requests: write jobs: apply-vrt-updates: name: Apply VRT Updates runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - name: Download patch artifact uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} run-id: ${{ github.event.workflow_run.id }} pattern: vrt-patch-* path: /tmp/artifacts - name: Download metadata artifact uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} run-id: ${{ github.event.workflow_run.id }} pattern: vrt-metadata-* path: /tmp/metadata - name: Extract metadata id: metadata run: | if [ ! -f "/tmp/metadata/pr-number.txt" ]; then echo "No metadata found, skipping..." exit 0 fi PR_NUMBER=$(cat "/tmp/metadata/pr-number.txt") HEAD_REF=$(cat "/tmp/metadata/head-ref.txt") HEAD_REPO=$(cat "/tmp/metadata/head-repo.txt") echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT" echo "head_ref=$HEAD_REF" >> "$GITHUB_OUTPUT" echo "head_repo=$HEAD_REPO" >> "$GITHUB_OUTPUT" echo "Found PR #$PR_NUMBER: $HEAD_REPO @ $HEAD_REF" - name: Checkout fork branch if: steps.metadata.outputs.pr_number != '' uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: repository: ${{ steps.metadata.outputs.head_repo }} ref: ${{ steps.metadata.outputs.head_ref }} token: ${{ secrets.ACTIONS_UPDATE_TOKEN }} persist-credentials: false fetch-depth: 0 - name: Validate and apply patch if: steps.metadata.outputs.pr_number != '' id: apply run: | PATCH_FILE="/tmp/artifacts/vrt-update.patch" if [ ! -f "$PATCH_FILE" ]; then echo "No patch file found" exit 0 fi echo "Found patch file: $PATCH_FILE" # Validate patch only contains PNG files echo "Validating patch contains only PNG files..." if grep -E '^(\+\+\+|---) [ab]/' "$PATCH_FILE" | grep -v '\.png$'; then echo "ERROR: Patch contains non-PNG files! Rejecting for security." echo "applied=false" >> "$GITHUB_OUTPUT" echo "error=Patch validation failed: contains non-PNG files" >> "$GITHUB_OUTPUT" exit 1 fi # Extract file list for verification FILES_CHANGED=$(grep -E '^\+\+\+ b/' "$PATCH_FILE" | sed 's/^+++ b\///' | wc -l) echo "Patch modifies $FILES_CHANGED PNG file(s)" # Configure git git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com" # Apply patch echo "Applying patch..." if git apply --check "$PATCH_FILE" 2>&1; then git apply "$PATCH_FILE" # Stage only PNG files (extra safety) git add "**/*.png" if git diff --staged --quiet; then echo "No changes after applying patch" echo "applied=false" >> "$GITHUB_OUTPUT" exit 0 fi # Commit git commit -m "Update VRT screenshots" -m "Auto-generated by VRT workflow" -m "PR: #${{ steps.metadata.outputs.pr_number }}" echo "applied=true" >> "$GITHUB_OUTPUT" else echo "Patch could not be applied cleanly" echo "applied=false" >> "$GITHUB_OUTPUT" echo "error=Patch conflicts with current branch state" >> "$GITHUB_OUTPUT" exit 1 fi - name: Push changes if: steps.apply.outputs.applied == 'true' env: HEAD_REF: ${{ steps.metadata.outputs.head_ref }} HEAD_REPO: ${{ steps.metadata.outputs.head_repo }} GITHUB_TOKEN: ${{ secrets.ACTIONS_UPDATE_TOKEN }} run: | # Use PAT in URL to ensure push triggers CI workflows # Note: GitHub Actions automatically masks secrets in logs git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${HEAD_REPO}.git" git push origin "HEAD:refs/heads/$HEAD_REF" echo "Successfully pushed VRT updates to $HEAD_REPO@$HEAD_REF" - name: Comment on PR - Failure if: failure() && steps.metadata.outputs.pr_number != '' uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: | const error = `${{ steps.apply.outputs.error }}` || 'Unknown error occurred'; await github.rest.issues.createComment({ issue_number: ${{ steps.metadata.outputs.pr_number }}, owner: context.repo.owner, repo: context.repo.repo, body: `❌ Failed to apply VRT updates: ${error}\n\nPlease check the workflow logs for details.` });