diff --git a/.github/workflows/fullsend.yaml b/.github/workflows/fullsend.yaml new file mode 100644 index 0000000..09335f9 --- /dev/null +++ b/.github/workflows/fullsend.yaml @@ -0,0 +1,96 @@ +# fullsend shim workflow +# Routes events to per-role agent dispatch workflows in .fullsend. +# +# Security: pull_request_target runs the BASE branch version of this workflow, +# preventing PRs from modifying it to exfiltrate the dispatch token. +# This shim never checks out PR code, so it is not vulnerable to "pwn request" +# attacks (see: Trivy CVE-2026-33634, hackerbot-claw campaign). +# +# The event payload is passed via an environment variable (not inline shell) +# to prevent script injection from attacker-controlled fields like issue +# titles, comment bodies, and PR descriptions. +name: fullsend + +on: + issues: + types: [opened, edited, labeled] + issue_comment: + types: [created] + pull_request_target: + types: [opened, synchronize, ready_for_review] + pull_request_review: + types: [submitted] + +jobs: + dispatch-triage: + runs-on: ubuntu-latest + if: >- + github.event_name == 'issues' || + (github.event_name == 'issue_comment' && ( + github.event.comment.body == '/triage' || + startsWith(github.event.comment.body, '/triage ') + )) + steps: + - name: Dispatch triage + env: + GH_TOKEN: ${{ secrets.FULLSEND_DISPATCH_TOKEN }} + EVENT_PAYLOAD: ${{ toJSON(github.event) }} + EVENT_TYPE: ${{ github.event_name }} + SOURCE_REPO: ${{ github.repository }} + DISPATCH_REPO: ${{ github.repository_owner }}/.fullsend + run: | + gh workflow run triage.yml \ + --repo "$DISPATCH_REPO" \ + --field event_type="$EVENT_TYPE" \ + --field source_repo="$SOURCE_REPO" \ + --field event_payload="$EVENT_PAYLOAD" + + dispatch-code: + runs-on: ubuntu-latest + if: >- + (github.event_name == 'issues' && github.event.action == 'labeled' + && github.event.label.name == 'ready-to-code') || + (github.event_name == 'issue_comment' && ( + github.event.comment.body == '/code' || + startsWith(github.event.comment.body, '/code ') + )) + steps: + - name: Dispatch code + env: + GH_TOKEN: ${{ secrets.FULLSEND_DISPATCH_TOKEN }} + EVENT_PAYLOAD: ${{ toJSON(github.event) }} + EVENT_TYPE: ${{ github.event_name }} + SOURCE_REPO: ${{ github.repository }} + DISPATCH_REPO: ${{ github.repository_owner }}/.fullsend + run: | + gh workflow run code.yml \ + --repo "$DISPATCH_REPO" \ + --field event_type="$EVENT_TYPE" \ + --field source_repo="$SOURCE_REPO" \ + --field event_payload="$EVENT_PAYLOAD" + + dispatch-review: + runs-on: ubuntu-latest + if: >- + (github.event_name == 'issues' && github.event.action == 'labeled' + && github.event.label.name == 'ready-for-review') || + (github.event_name == 'issue_comment' && ( + github.event.comment.body == '/review' || + startsWith(github.event.comment.body, '/review ') + )) || + github.event_name == 'pull_request_target' || + github.event_name == 'pull_request_review' + steps: + - name: Dispatch review + env: + GH_TOKEN: ${{ secrets.FULLSEND_DISPATCH_TOKEN }} + EVENT_PAYLOAD: ${{ toJSON(github.event) }} + EVENT_TYPE: ${{ github.event_name }} + SOURCE_REPO: ${{ github.repository }} + DISPATCH_REPO: ${{ github.repository_owner }}/.fullsend + run: | + gh workflow run review.yml \ + --repo "$DISPATCH_REPO" \ + --field event_type="$EVENT_TYPE" \ + --field source_repo="$SOURCE_REPO" \ + --field event_payload="$EVENT_PAYLOAD"