Enable sitePermissions for internal iOS users #34795
Workflow file for this run
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
| # Auto Respond to PR Workflow | |
| # | |
| # This workflow automatically generates and posts diff comments showing changes to generated configuration files. | |
| # | |
| # ## Generated Diff Output Guide: | |
| # - **X files changed**: Multiple files with identical changes (collapsed for readability) | |
| # - **X files identical**: Files that are exactly the same between base and PR branches | |
| # - **File headers**: Show `--- filename (and X other files)` when multiple files share the same diff | |
| # - **File lists**: Individual files are listed under each collapsed section | |
| # - **Sections**: `latest` (current config version, expanded) and `legacy` (older versions, collapsed) | |
| # | |
| # The diff script groups files by their actual changes to reduce noise and improve review efficiency. | |
| name: Auto Respond to PR | |
| on: | |
| pull_request_review: | |
| pull_request: | |
| types: | |
| - opened | |
| - edited | |
| - closed | |
| - reopened | |
| - synchronize | |
| - review_requested | |
| jobs: | |
| # Dedicated job to sync Asana tasks when PR is closed (merged or abandoned) | |
| # Closes tasks for both merged PRs and abandoned PRs to clean up dead tasks | |
| # Runs independently of the main workflow | |
| sync_asana_on_close: | |
| if: github.event.action == 'closed' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: duckduckgo/action-asana-sync@v11 | |
| with: | |
| ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }} | |
| ASANA_WORKSPACE_ID: ${{ secrets.ASANA_WORKSPACE_ID }} | |
| ASANA_PROJECT_ID: '1206780406371845' | |
| GITHUB_PAT: ${{ secrets.GH_RO_PAT }} | |
| USER_MAP: ${{ vars.USER_MAP }} | |
| ASSIGN_PR_AUTHOR: 'true' | |
| auto_respond: | |
| if: github.event.action != 'closed' && github.event.pull_request.user.login != 'dependabot[bot]' | |
| runs-on: ubuntu-latest | |
| concurrency: auto-respond-${{ github.event.pull_request.number }} | |
| steps: | |
| - name: Check if holiday period | |
| run: | | |
| if [ "$(date -u +%Y%m%d)" -lt "20260105" ]; then | |
| echo "::notice::Auto review bot disabled until Jan 5th 2026" | |
| exit 1 | |
| fi | |
| - name: Debounce delay | |
| run: sleep 5 | |
| - name: Check repository permissions | |
| uses: actions/github-script@v9 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const username = context.payload.pull_request.user.login; | |
| try { | |
| const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| username: username | |
| }); | |
| const permission = repoPermission.data.permission; | |
| if (permission === 'write' || permission === 'admin') { | |
| console.log(`✅ User authorized to use workflow`); | |
| } else { | |
| core.setFailed(`User does not have sufficient repository permissions to use this workflow`); | |
| } | |
| } catch (error) { | |
| core.setFailed(`Unable to verify user permissions`); | |
| } | |
| - name: Checkout base branch | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ github.event.pull_request.base.ref }} | |
| repository: ${{ github.event.pull_request.head.repo.full_name }} | |
| path: base | |
| - name: Checkout PR branch | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ github.event.pull_request.head.ref }} | |
| repository: ${{ github.event.pull_request.head.repo.full_name }} | |
| path: pr | |
| fetch-depth: 0 | |
| - name: Use Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: pr/.nvmrc | |
| - name: Run build script on base branch | |
| run: | | |
| cd base | |
| npm ci | |
| node index.js | |
| cd .. | |
| - name: Run build script on PR branch | |
| run: | | |
| cd pr | |
| git config --global user.email "dax@duck.com" | |
| git config --global user.name "dax" | |
| git rebase -X theirs origin/${{ github.event.pull_request.base.ref }} | |
| npm ci | |
| node index.js | |
| cd .. | |
| - name: Create diff of file outputs | |
| run: node pr/.github/scripts/diff-directories.js base/generated pr/generated > diff_output.txt | |
| - name: Create JSON approval analysis | |
| run: node pr/.github/scripts/json-diff-directories.js base/generated pr/generated > approval_output.txt | |
| - name: Check changed files | |
| id: check_files | |
| run: | | |
| cd pr | |
| # Get list of changed files | |
| changed_files=$(git diff --name-only origin/${{ github.event.pull_request.base.ref }}...HEAD) | |
| echo "Changed files:" | |
| echo "$changed_files" | |
| # Check if all changed files are JSON files in overrides/ or features/ | |
| valid_changes=true | |
| while IFS= read -r file; do | |
| if [[ ! "$file" =~ ^(overrides|features)/.+\.json$ ]]; then | |
| echo "❌ Invalid file change detected: $file" | |
| echo "Only JSON files in overrides/ and features/ directories are allowed for auto-approval" | |
| valid_changes=false | |
| fi | |
| done <<< "$changed_files" | |
| if [ "$valid_changes" = true ]; then | |
| echo "✅ All changed files are valid JSON files in allowed directories" | |
| echo "files_valid=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "files_valid=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Parse approval output | |
| id: approval | |
| run: | | |
| if grep -q "AUTO-APPROVED" approval_output.txt; then | |
| echo "approved=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "approved=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Find Previous Diff Comment | |
| uses: peter-evans/find-comment@v4 | |
| id: find_diff_comment | |
| with: | |
| issue-number: ${{ github.event.pull_request.number }} | |
| comment-author: 'github-actions[bot]' # posted with default GITHUB_TOKEN | |
| body-includes: 'Generated file outputs' | |
| direction: last | |
| - name: Find Previous Approval Comment | |
| uses: peter-evans/find-comment@v4 | |
| id: find_approval_comment | |
| with: | |
| issue-number: ${{ github.event.pull_request.number }} | |
| comment-author: 'daxtheduck' # posted with PRIVACY_CONFIG_PAT to trigger issue_comment events | |
| body-includes: 'JSON approval analysis' | |
| direction: last | |
| - name: Create Diff Comment Body | |
| uses: actions/github-script@v9 | |
| id: create_diff_body | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const fs = require('fs'); | |
| const diffOutput = fs.readFileSync('diff_output.txt', 'utf8'); | |
| let commentBody = ` | |
| ### [Generated file outputs](https://github.com/duckduckgo/privacy-configuration/blob/main/.github/workflows/auto-respond-pr.yml#L5-L12): | |
| *Time updated:* ${new Date().toUTCString()} | |
| ${diffOutput} | |
| ` | |
| if (commentBody.length > 65536) { | |
| commentBody = '❌ Generated diff output is too large to post as a comment, run locally to see the diff and validate' | |
| } | |
| core.setOutput('comment_body', commentBody); | |
| - name: Check for existing approved reviews | |
| uses: actions/github-script@v9 | |
| id: check_reviews | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const { data: reviews } = await github.rest.pulls.listReviews({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.payload.pull_request.number | |
| }); | |
| const hasApprovedReview = reviews.some(review => | |
| review.state === 'APPROVED' && | |
| review.user.login === 'daxtheduck' | |
| ); | |
| console.log(`Found approved review from daxtheduck: ${hasApprovedReview}`); | |
| core.setOutput('has_approved_review', hasApprovedReview); | |
| - name: Auto approve | |
| if: steps.approval.outputs.approved == 'true' && steps.check_files.outputs.files_valid == 'true' && steps.check_reviews.outputs.has_approved_review == 'false' | |
| run: | | |
| gh pr review --approve "$PR_URL" | |
| env: | |
| PR_URL: ${{ github.event.pull_request.html_url }} | |
| GITHUB_TOKEN: ${{ secrets.PRIVACY_CONFIG_PAT }} | |
| # Sync Asana tasks for PRs that need manual review (non-auto-approved) | |
| # Task closure on merge is handled by the dedicated close_asana_on_merge job | |
| - uses: duckduckgo/action-asana-sync@v11 | |
| if: | | |
| github.event.action != 'closed' && | |
| ((steps.approval.outputs.approved == 'true' && steps.check_files.outputs.files_valid == 'true') != true) | |
| with: | |
| ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }} | |
| ASANA_WORKSPACE_ID: ${{ secrets.ASANA_WORKSPACE_ID }} | |
| ASANA_PROJECT_ID: '1206780406371845' | |
| GITHUB_PAT: ${{ secrets.GH_RO_PAT }} | |
| USER_MAP: ${{ vars.USER_MAP }} | |
| ASSIGN_PR_AUTHOR: 'true' | |
| - name: Create comment | |
| if: github.event.action == 'opened' && (steps.approval.outputs.approved == 'true' && steps.check_files.outputs.files_valid == 'true') != true | |
| uses: peter-evans/create-or-update-comment@v5 | |
| with: | |
| issue-number: ${{ github.event.pull_request.number }} | |
| body: | | |
| 👋 Don't forget to **add an individual reviewer** (in addition to those auto-added), as this will create a task for them in Asana. | |
| - The best reviewer is most likely a feature or platform owner. | |
| - If they've got permission to approve, you're good to merge. See [CODEOWNERS](https://github.com/duckduckgo/privacy-configuration/blob/main/CODEOWNERS) | |
| - As a fallback the Global owners are: | |
| - [Breakage AOR](https://github.com/orgs/duckduckgo/teams/breakage-aor) | |
| - [Breakage triagers](https://github.com/orgs/duckduckgo/teams/breakage) | |
| - [Config AOR](https://github.com/orgs/duckduckgo/teams/config-aor) | |
| 👉 Please mark this as DRAFT unless there's an intention to merge this immediately. | |
| 👉 Click "Merge when ready" if you're happy for this to be automatically merged once reviewed. (If not available, ensure you've signed in to DuckDuckGo oauth.) | |
| 👉 Don't forget to add schema changes to validate if you're adding/changing a feature. | |
| - [Config Reviewer Documentation](https://github.com/duckduckgo/privacy-configuration/blob/main/docs/config-reviewer-documentation.md) | |
| - [Config Maintainer Documentation](https://github.com/duckduckgo/privacy-configuration/blob/main/docs/config-maintainer-documentation.md) | |
| - [Feature Implementer Documentation](https://github.com/duckduckgo/privacy-configuration/blob/main/docs/feature-implementer-documentation.md) | |
| - name: Create Approval Comment Body | |
| uses: actions/github-script@v9 | |
| id: create_approval_body | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const fs = require('fs'); | |
| const approvalOutput = fs.readFileSync('approval_output.txt', 'utf8'); | |
| let commentBody = ` | |
| ### [JSON approval analysis](https://github.com/duckduckgo/privacy-configuration/blob/main/.github/workflows/auto-respond-pr.yml#L5-L12): | |
| *Time updated:* ${new Date().toUTCString()} | |
| ${approvalOutput} | |
| ` | |
| if (commentBody.length > 65536) { | |
| commentBody = '❌ Approval analysis output is too large to post as a comment, run locally to see the analysis and validate' | |
| } | |
| core.setOutput('comment_body', commentBody); | |
| - name: Create, or Update the Diff Comment | |
| uses: peter-evans/create-or-update-comment@v5 | |
| with: | |
| issue-number: ${{ github.event.pull_request.number }} | |
| comment-id: ${{ steps.find_diff_comment.outputs.comment-id }} | |
| body: ${{ steps.create_diff_body.outputs.comment_body }} | |
| edit-mode: replace | |
| # Uses PAT (not GITHUB_TOKEN) so this comment triggers issue_comment | |
| # events for downstream workflows (e.g., auto-notify-mattermost.yml). | |
| # See: https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow | |
| - name: Create, or Update the Approval Comment | |
| uses: peter-evans/create-or-update-comment@v5 | |
| with: | |
| token: ${{ secrets.PRIVACY_CONFIG_PAT }} | |
| issue-number: ${{ github.event.pull_request.number }} | |
| comment-id: ${{ steps.find_approval_comment.outputs.comment-id }} | |
| body: ${{ steps.create_approval_body.outputs.comment_body }} | |
| edit-mode: replace |

