Github Copilot Max Plan not activating #4122
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: "PR Test Checker" | |
| # Grades whether a PR has adequate test coverage and posts a verdict comment. | |
| # Runs only on demand: comment `/pete` (or `/recheck-tests`, `/rePETE`, | |
| # `/re-pete`) on a PR to trigger it. It does NOT run automatically on PR | |
| # open/push (see #14494) -- authors get the same rubric locally via the `pete` | |
| # skill before opening a PR, so the automatic CI pass was redundant with that | |
| # plus the on-demand comment trigger below. | |
| # | |
| # Scope: runs only for PR authors / commenters in the posit-dev `positron-dev` | |
| # team. GitHub Actions `if:` has no team-membership predicate, and the default | |
| # GITHUB_TOKEN cannot read org membership, so a dedicated `gate` job resolves | |
| # membership at runtime via the GitHub API. It mints a short-lived token from | |
| # the "Positron Projects" GitHub App (secrets POSITRON_PROJECTS_CLIENT_ID + | |
| # POSITRON_PROJECTS_PEM, shared with release-generate-sbom.yml) scoped to the | |
| # posit-dev org, which carries the App's `Members: read` permission, and | |
| # exposes an `ok` output the grading job depends on via `needs`. The gate | |
| # FAILS CLOSED: if the token can't be minted or any API call fails (e.g. the | |
| # App is missing `Members: read`), `ok=false` and nothing is graded. Membership | |
| # is always live -- there is no allowlist to maintain. To change who PETE runs | |
| # for, edit the `positron-dev` team on GitHub, not this file. | |
| # | |
| # Security model: the job checks out two trees -- the BASE branch (trusted | |
| # action + skill code, used to run the analyzer with secrets) and the PR HEAD | |
| # (untrusted source code, mounted as read-only data for the agent's | |
| # Read/Grep/Glob tools). The analyzer is invoked from the base checkout via | |
| # `uses: ./base/.github/actions/pr-test-checker` so that PR-head code is never | |
| # executed with secrets in scope. This closes the "pwn request" pattern where | |
| # a fork PR modifies action code, and a positron-dev member comments | |
| # /recheck-tests (an `issue_comment` event that runs in base context with | |
| # full secrets, unlike `pull_request` events which strip secrets for forks). | |
| on: | |
| issue_comment: | |
| types: | |
| - created | |
| jobs: | |
| # Resolve positron-dev team membership at runtime. This is a pure GitHub API | |
| # read with a short-lived App token; it checks out no PR code, so it is safe | |
| # to run in base context. Emits `ok=true` only when BOTH the commenter and | |
| # the PR author are *active* team members, and FAILS CLOSED (`ok=false`) on | |
| # a token/API error. | |
| gate: | |
| name: Check positron-dev membership | |
| # Cheap event-shape pre-filter so we don't spin up a runner (or hit the | |
| # API) for every PR comment -- only trigger-command comments on PRs reach | |
| # the membership check below. Recognized commands: /pete, /recheck-tests, | |
| # /rePETE, /re-pete (contains() is case-insensitive, so casing doesn't | |
| # matter; the /pete substring check does not match /repete or /re-pete, | |
| # since neither contains a "/pete" substring). NOTE: keep this command | |
| # list in sync with the `run` job's `if` below. | |
| if: | | |
| github.event.issue.pull_request != null && | |
| (contains(github.event.comment.body, '/pete') || | |
| contains(github.event.comment.body, '/recheck-tests') || | |
| contains(github.event.comment.body, '/repete') || | |
| contains(github.event.comment.body, '/re-pete')) | |
| runs-on: ubuntu-latest | |
| # No GITHUB_TOKEN scopes needed: the check uses the App token in GH_TOKEN. | |
| permissions: {} | |
| concurrency: | |
| group: pr-test-checker-gate-${{ github.event.issue.number }} | |
| cancel-in-progress: true | |
| outputs: | |
| ok: ${{ steps.check.outputs.ok }} | |
| steps: | |
| - name: Mint org-scoped App token | |
| id: app-token | |
| uses: actions/create-github-app-token@v3 | |
| with: | |
| client-id: ${{ secrets.POSITRON_PROJECTS_CLIENT_ID }} | |
| private-key: ${{ secrets.POSITRON_PROJECTS_PEM }} | |
| owner: posit-dev | |
| - name: Check team membership | |
| id: check | |
| env: | |
| # Short-lived token from the Positron Projects GitHub App, scoped to | |
| # the posit-dev org. Reading team membership needs the App's | |
| # `Members: read` permission; without it the gh calls 404 and the gate | |
| # stays ok=false -- fail closed. | |
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | |
| COMMENTER: ${{ github.event.comment.user.login }} | |
| ISSUE_AUTHOR: ${{ github.event.issue.user.login }} | |
| run: | | |
| set -uo pipefail | |
| # Active member -> HTTP 200 {"state":"active"}; non-member -> 404 | |
| # (gh exits non-zero, stdout empty). Pending invite -> "pending". | |
| is_member() { | |
| local state | |
| state=$(gh api "orgs/posit-dev/teams/positron-dev/memberships/$1" --jq '.state' 2>/dev/null) | |
| [ "$state" = "active" ] | |
| } | |
| # BOTH the commenter and the PR author must be members, so an | |
| # attacker can't bait a run by commenting the trigger phrase on a | |
| # PR whose author is outside the team. | |
| ok=false | |
| if is_member "$COMMENTER" && is_member "$ISSUE_AUTHOR"; then | |
| ok=true | |
| fi | |
| echo "Membership gate result: ok=$ok" | |
| echo "ok=$ok" >> "$GITHUB_OUTPUT" | |
| run: | |
| name: Grade on command | |
| needs: gate | |
| # Fires when a positron-dev member comments a trigger command | |
| # (/pete, /recheck-tests, /rePETE, /re-pete) on a PR. The issue_comment | |
| # event runs in base-repo context with full secrets even when the PR is | |
| # from a fork, so two layers of defense: | |
| # 1. The `gate` job requires BOTH the commenter AND the PR author to be | |
| # positron-dev members (the PR-author check blocks comments on fork | |
| # PRs by non-members -- attackers can't bait a run on a PR whose | |
| # author is outside the team). | |
| # 2. The job checks out the base branch to RUN the action and the | |
| # PR head only as READ-ONLY DATA -- PR-head code never executes. | |
| # NOTE: keep the command list in sync with the gate job's `if` above. | |
| if: | | |
| github.event.issue.pull_request != null && | |
| (contains(github.event.comment.body, '/pete') || | |
| contains(github.event.comment.body, '/recheck-tests') || | |
| contains(github.event.comment.body, '/repete') || | |
| contains(github.event.comment.body, '/re-pete')) && | |
| needs.gate.outputs.ok == 'true' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| concurrency: | |
| group: pr-test-checker-${{ github.event.issue.number }} | |
| cancel-in-progress: true | |
| steps: | |
| # Acknowledge the command with an "eyes" reaction so the commenter gets | |
| # immediate visual confirmation that PETE picked it up and is running. | |
| # First step so it lands before the slower checkout/analysis steps. | |
| # Capture the reaction id so the finalize step can remove it once PETE | |
| # is done. | |
| - name: Acknowledge command | |
| id: ack | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| COMMENT_ID: ${{ github.event.comment.id }} | |
| run: | | |
| REACTION_ID=$(gh api --method POST \ | |
| "repos/${GITHUB_REPOSITORY}/issues/comments/${COMMENT_ID}/reactions" \ | |
| -f content=eyes --jq '.id' 2>/dev/null) || echo "Failed to add reaction (non-fatal)" | |
| echo "reaction_id=${REACTION_ID}" >> "$GITHUB_OUTPUT" | |
| - name: Resolve PR head SHA | |
| id: pr | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| PR_NUMBER: ${{ github.event.issue.number }} | |
| run: | | |
| HEAD_SHA=$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}" --jq '.head.sha') | |
| echo "head_sha=${HEAD_SHA}" >> "$GITHUB_OUTPUT" | |
| - name: Checkout BASE (trusted action + skill code) | |
| uses: actions/checkout@v7 | |
| with: | |
| ref: ${{ github.event.repository.default_branch }} | |
| path: base | |
| sparse-checkout: | | |
| .claude/skills/pr-test-checker | |
| .claude/rules | |
| .github/actions/pr-test-checker | |
| - name: Checkout PR HEAD (untrusted source data) | |
| uses: actions/checkout@v7 | |
| with: | |
| ref: ${{ steps.pr.outputs.head_sha }} | |
| path: pr-head | |
| sparse-checkout: | | |
| CLAUDE.md | |
| src | |
| extensions | |
| test/e2e | |
| - name: Load Anthropic API key | |
| uses: 1password/load-secrets-action@v4 | |
| with: | |
| export-env: true | |
| env: | |
| OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }} | |
| ANTHROPIC_KEY: "op://Positron/Anthropic/credential" | |
| - name: Run pr-test-checker (from base, source from PR head) | |
| uses: ./base/.github/actions/pr-test-checker | |
| with: | |
| pr-number: ${{ github.event.issue.number }} | |
| anthropic-api-key: ${{ env.ANTHROPIC_KEY }} | |
| repo-root: ${{ github.workspace }}/pr-head | |
| # Replace the "eyes" acknowledgement with a terminal reaction once PETE | |
| # finishes: rocket on success, confused on failure. Runs on always() so | |
| # the comment never gets stuck showing "running". Skipped if the ack | |
| # step never recorded a reaction id (e.g. the initial reaction POST | |
| # failed). | |
| - name: Finalize reaction | |
| if: always() && steps.ack.outputs.reaction_id != '' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| COMMENT_ID: ${{ github.event.comment.id }} | |
| REACTION_ID: ${{ steps.ack.outputs.reaction_id }} | |
| JOB_STATUS: ${{ job.status }} | |
| run: | | |
| # Remove the "eyes" acknowledgement reaction. | |
| gh api --method DELETE \ | |
| "repos/${GITHUB_REPOSITORY}/issues/comments/${COMMENT_ID}/reactions/${REACTION_ID}" \ | |
| || echo "Failed to remove eyes reaction (non-fatal)" | |
| # Signal completion: rocket on success, confused otherwise. | |
| if [ "$JOB_STATUS" = "success" ]; then | |
| FINAL=rocket | |
| else | |
| FINAL=confused | |
| fi | |
| gh api --method POST \ | |
| "repos/${GITHUB_REPOSITORY}/issues/comments/${COMMENT_ID}/reactions" \ | |
| -f content="$FINAL" || echo "Failed to add ${FINAL} reaction (non-fatal)" |