Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 75 additions & 27 deletions .github/workflows/fullsend.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
# fullsend shim workflow
# Routes events to per-role agent dispatch workflows in .fullsend.
# Routes events to agent workflows in .fullsend via the dispatch.yml workflow.
#
# Credentials: uses secrets.FULLSEND_DISPATCH_TOKEN to trigger dispatch.yml
# in owner/.fullsend via workflow_dispatch. The dispatcher (running in .fullsend)
# generates its own GitHub App tokens and scans for agent workflows to trigger.
#
# Security: pull_request_target runs the BASE branch version of this workflow,
# preventing PRs from modifying it to exfiltrate the dispatch token.
# preventing PRs from modifying it to exfiltrate credentials.
# This shim never checks out PR code, so it is not vulnerable to "pwn request"
# attacks (see: Trivy CVE-2026-33634, hackerbot-claw campaign).
#
Expand All @@ -20,7 +24,7 @@ permissions:

on:
issues:
types: [labeled]
types: [labeled, opened]
issue_comment:
types: [created]
pull_request_target:
Expand Down Expand Up @@ -59,19 +63,20 @@ jobs:
--arg iu "${ISSUE_HTML_URL:-}" \
'{issue: {number: (if $in != "" then ($in | tonumber) else null end), html_url: (if $iu != "" then $iu else null end)}}')
echo "json=$PAYLOAD" >> "$GITHUB_OUTPUT"
- name: Dispatch triage
- name: Dispatch triage stage
env:
GH_TOKEN: ${{ secrets.FULLSEND_DISPATCH_TOKEN }}
EVENT_PAYLOAD: ${{ steps.payload.outputs.json }}
EVENT_TYPE: ${{ github.event_name }}
SOURCE_REPO: ${{ github.repository }}
DISPATCH_REPO: ${{ github.repository_owner }}/.fullsend
run: |
gh workflow run triage.yml \
gh workflow run dispatch.yml \
--repo "$DISPATCH_REPO" \
--field event_type="$EVENT_TYPE" \
--field source_repo="$SOURCE_REPO" \
--field event_payload="$EVENT_PAYLOAD"
-f stage=triage \
-f event_type="$EVENT_TYPE" \
-f source_repo="$SOURCE_REPO" \
-f event_payload="$EVENT_PAYLOAD"

dispatch-code:
runs-on: ubuntu-latest
Expand All @@ -97,19 +102,20 @@ jobs:
--arg iu "${ISSUE_HTML_URL:-}" \
'{issue: {number: (if $in != "" then ($in | tonumber) else null end), html_url: (if $iu != "" then $iu else null end)}}')
echo "json=$PAYLOAD" >> "$GITHUB_OUTPUT"
- name: Dispatch code
- name: Dispatch code stage
env:
GH_TOKEN: ${{ secrets.FULLSEND_DISPATCH_TOKEN }}
EVENT_PAYLOAD: ${{ steps.payload.outputs.json }}
EVENT_TYPE: ${{ github.event_name }}
SOURCE_REPO: ${{ github.repository }}
DISPATCH_REPO: ${{ github.repository_owner }}/.fullsend
run: |
gh workflow run code.yml \
gh workflow run dispatch.yml \
--repo "$DISPATCH_REPO" \
--field event_type="$EVENT_TYPE" \
--field source_repo="$SOURCE_REPO" \
--field event_payload="$EVENT_PAYLOAD"
-f stage=code \
-f event_type="$EVENT_TYPE" \
-f source_repo="$SOURCE_REPO" \
-f event_payload="$EVENT_PAYLOAD"

dispatch-review:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -143,19 +149,20 @@ jobs:
'{issue: {number: (if $in != "" then ($in | tonumber) else null end), html_url: (if $iu != "" then $iu else null end)},
pull_request: {number: (if $pn != "" then ($pn | tonumber) else null end), html_url: (if $pu != "" then $pu else null end)}}')
echo "json=$PAYLOAD" >> "$GITHUB_OUTPUT"
- name: Dispatch review
- name: Dispatch review stage
env:
GH_TOKEN: ${{ secrets.FULLSEND_DISPATCH_TOKEN }}
EVENT_PAYLOAD: ${{ steps.payload.outputs.json }}
EVENT_TYPE: ${{ github.event_name }}
SOURCE_REPO: ${{ github.repository }}
DISPATCH_REPO: ${{ github.repository_owner }}/.fullsend
run: |
gh workflow run review.yml \
gh workflow run dispatch.yml \
--repo "$DISPATCH_REPO" \
--field event_type="$EVENT_TYPE" \
--field source_repo="$SOURCE_REPO" \
--field event_payload="$EVENT_PAYLOAD"
-f stage=review \
-f event_type="$EVENT_TYPE" \
-f source_repo="$SOURCE_REPO" \
-f event_payload="$EVENT_PAYLOAD"

dispatch-fix-bot:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -186,20 +193,22 @@ jobs:
--arg brepo "${BASE_REPO}" \
'{pull_request: {number: ($pn | tonumber), head: {ref: $hr, repo: {full_name: $hrepo}}, base: {ref: $br, repo: {full_name: $brepo}}}}')
echo "json=$PAYLOAD" >> "$GITHUB_OUTPUT"
- name: Dispatch fix (bot-triggered)
- name: Dispatch fix stage (bot-triggered)
env:
GH_TOKEN: ${{ secrets.FULLSEND_DISPATCH_TOKEN }}
EVENT_PAYLOAD: ${{ steps.payload.outputs.json }}
EVENT_TYPE: ${{ github.event_name }}
SOURCE_REPO: ${{ github.repository }}
DISPATCH_REPO: ${{ github.repository_owner }}/.fullsend
TRIGGER_USER: ${{ github.event.review.user.login }}
run: |
gh workflow run fix.yml \
gh workflow run dispatch.yml \
--repo "$DISPATCH_REPO" \
--field event_type="$EVENT_TYPE" \
--field source_repo="$SOURCE_REPO" \
--field event_payload="$EVENT_PAYLOAD" \
--field trigger_source="bot"
-f stage=fix \
-f event_type="$EVENT_TYPE" \
-f source_repo="$SOURCE_REPO" \
-f event_payload="$EVENT_PAYLOAD" \
-f trigger_source="$TRIGGER_USER"

dispatch-fix-human:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -243,17 +252,56 @@ jobs:
--arg cb "${COMMENT_BODY:-}" \
'{issue: {number: ($in | tonumber)}, comment: {body: $cb}}')
echo "json=$PAYLOAD" >> "$GITHUB_OUTPUT"
- name: Dispatch fix (human-triggered)
- name: Dispatch fix stage (human-triggered)
env:
GH_TOKEN: ${{ secrets.FULLSEND_DISPATCH_TOKEN }}
EVENT_PAYLOAD: ${{ steps.payload.outputs.json }}
EVENT_TYPE: ${{ github.event_name }}
SOURCE_REPO: ${{ github.repository }}
DISPATCH_REPO: ${{ github.repository_owner }}/.fullsend
TRIGGER_USER: ${{ github.event.comment.user.login }}
run: |
gh workflow run dispatch.yml \
--repo "$DISPATCH_REPO" \
-f stage=fix \
-f event_type="$EVENT_TYPE" \
-f source_repo="$SOURCE_REPO" \
-f event_payload="$EVENT_PAYLOAD" \
-f trigger_source="$TRIGGER_USER"

dispatch-gh-classify:
runs-on: ubuntu-latest
if: >-
github.event_name == 'issues' && github.event.action == 'opened'
steps:
- name: Build minimal payload
id: payload
env:
ISSUE_NUMBER: ${{ github.event.issue.number }}
ISSUE_HTML_URL: ${{ github.event.issue.html_url }}
ISSUE_AUTHOR: ${{ github.event.issue.user.login }}
run: |
set -euo pipefail
PAYLOAD=$(jq -cn \
--arg in "${ISSUE_NUMBER:-}" \
--arg iu "${ISSUE_HTML_URL:-}" \
--arg au "${ISSUE_AUTHOR:-}" \
--arg repo "${{ github.repository }}" \
'{issue: {number: (if $in != "" then ($in | tonumber) else null end), html_url: (if $iu != "" then $iu else null end), author: $au}, repository: $repo}')
echo "json=$PAYLOAD" >> "$GITHUB_OUTPUT"
- name: Dispatch gh-classify
env:
GH_TOKEN: ${{ secrets.FULLSEND_DISPATCH_TOKEN }}
EVENT_PAYLOAD: ${{ steps.payload.outputs.json }}
EVENT_TYPE: issues
SOURCE_REPO: ${{ github.repository }}
DISPATCH_REPO: ${{ github.repository_owner }}/.fullsend
ISSUE_NUMBER: ${{ github.event.issue.number }}
run: |
gh workflow run fix.yml \
gh workflow run gh-classify.yml \
--repo "$DISPATCH_REPO" \
--field event_type="$EVENT_TYPE" \
--field source_repo="$SOURCE_REPO" \
--field event_payload="$EVENT_PAYLOAD" \
--field trigger_source="human"
--field classify_mode="single" \
--field issue_number="$ISSUE_NUMBER"