Repository navigation
136 lines (132 loc) · 6.27 KB
/
Copy pathfullsend.yaml
File metadata and controls
136 lines (132 loc) · 6.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# This file is managed by fullsend. Do not edit it directly.
# Upstream: https://github.com/fullsend-ai/fullsend/blob/main/internal/scaffold/fullsend-repo/.github/workflows/fullsend.yaml
---
# fullsend shim workflow (per-repo installation mode)
# Routes events to agent workflows via reusable-dispatch.yml.
# All agent execution happens in this repository's context.
#
# Security: pull_request_target runs the BASE branch version of this workflow,
# preventing PRs from modifying it to exfiltrate credentials.
# This shim never checks out PR code, so it is not vulnerable to "pwn request"
# attacks.
#
# Routing: this shim forwards the raw event context to reusable-dispatch.yml,
# which determines the stage and runs the agent inline (ADR 62).
# Adding a new stage requires only a job in reusable-dispatch.yml — zero changes to this repo.
#
# Concurrency: per-role cancel-in-progress groups live in reusable-dispatch.yml
# stage jobs with -agent- suffix. Roles operate independently (#2452).
name: fullsend
on:
issues:
types: [opened, edited, labeled]
issue_comment:
types: [created]
pull_request_target:
types: [opened, synchronize, ready_for_review, closed, labeled, unlabeled]
pull_request_review:
types: [submitted]
permissions: {}
jobs:
dispatch:
if: >-
(github.event_name != 'pull_request_target' && github.event_name != 'pull_request_review'
|| github.event.pull_request.head.ref != 'fullsend/scaffold-install')
&& (github.event_name != 'issue_comment'
|| (startsWith(github.event.comment.body, '/fs-')
&& github.event.comment.user.type != 'Bot'))
permissions:
actions: write
id-token: write
contents: write
issues: write
packages: read
pull-requests: write
uses: fullsend-ai/fullsend/.github/workflows/reusable-dispatch.yml@main
with:
event_action: ${{ github.event.action }}
mint_url: ${{ vars.FULLSEND_MINT_URL }}
gcp_region: ${{ vars.FULLSEND_GCP_REGION }}
project_number: ${{ vars.FULLSEND_PROJECT_NUMBER }}
runner_image: ubuntu-24.04
secrets:
FULLSEND_GCP_WIF_PROVIDER: ${{ secrets.FULLSEND_GCP_WIF_PROVIDER }}
FULLSEND_GCP_PROJECT_ID: ${{ secrets.FULLSEND_GCP_PROJECT_ID }}
FULLSEND_OPENAI_API_KEY: ${{ secrets.FULLSEND_OPENAI_API_KEY }}
FULLSEND_INFERENCE_GATEWAY_API_KEY: ${{ secrets.FULLSEND_INFERENCE_GATEWAY_API_KEY }}
OTEL_EXPORTER_OTLP_TRACES_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_TRACES_HEADERS }}
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}
FULLSEND_GITHUB_RUNNER_SECRETS: ${{ secrets.FULLSEND_GITHUB_RUNNER_SECRETS }}
stop-fix:
# Job-level if: is intentionally coarse — it only screens for the
# /fs-fix-stop command on a PR from a non-bot. The authoritative
# authorization decision (collaborator permission API + PR-author escape
# hatch) is made in the step below, so a maintainer whose author_association
# is not MEMBER (e.g. private org membership) is not filtered out (ADR 0054).
if: >-
github.event_name == 'issue_comment'
&& github.event.issue.pull_request
&& github.event.comment.user.type != 'Bot'
&& github.event.comment.body == '/fs-fix-stop'
runs-on: ubuntu-24.04
permissions:
contents: read
issues: write
pull-requests: write
steps:
- name: Add fullsend-no-fix label and notify
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.issue.number }}
REPO: ${{ github.repository }}
COMMENT_USER_LOGIN: ${{ github.event.comment.user.login }}
ISSUE_USER_LOGIN: ${{ github.event.issue.user.login }}
run: |
set -euo pipefail
# ADR 0054: authorize via the collaborator permission API
# (admin|maintain|write), not author_association — the latter grants
# contributor status to anyone with a single merged PR (issue #5421).
# Mirrors has_repo_permission() in reusable-dispatch.yml, including the
# custom-role --jq resolution; keep the two in sync.
# The PR author may always stop the fix agent on their own PR.
authorized=false
if [[ -n "$COMMENT_USER_LOGIN" && "$COMMENT_USER_LOGIN" == "$ISSUE_USER_LOGIN" ]]; then
authorized=true
else
if api_err=$(mktemp); then
if role=$(gh api "repos/$REPO/collaborators/$COMMENT_USER_LOGIN/permission" \
--jq '.user.permissions as $p
| if (.role_name | type) != "string" or .role_name == "" then "none"
elif (.role_name | IN("admin", "maintain", "write", "triage", "read")) then .role_name
elif $p == null then
if (.permission | IN("admin", "write", "read")) then .permission else "none" end
elif ($p | type) == "object" then
if $p.admin == true then "admin"
elif $p.maintain == true then "maintain"
elif $p.push == true then "write"
elif $p.triage == true then "triage"
elif $p.pull == true then "read"
else "none" end
else "none" end' 2>"$api_err"); then
case "$role" in
admin|maintain|write) authorized=true ;;
esac
else
echo "::warning::Permission API call failed for $COMMENT_USER_LOGIN: $(cat "$api_err")"
fi
rm -f "$api_err"
else
echo "::warning::Failed to create temp file for permission check of $COMMENT_USER_LOGIN"
fi
fi
if [[ "$authorized" != "true" ]]; then
echo "::notice::User $COMMENT_USER_LOGIN is not authorized to stop the fix agent (requires write access or PR authorship)"
exit 0
fi
gh label create "fullsend-no-fix" --repo "$REPO" \
--description "Skip bot-triggered fix agent runs" --color "FBCA04" \
2>/dev/null || true
gh pr edit "$PR_NUMBER" --repo "$REPO" \
--add-label "fullsend-no-fix"
gh pr comment "$PR_NUMBER" --repo "$REPO" \
--body "Fix agent disabled for this PR. Remove the \`fullsend-no-fix\` label or use \`/fs-fix\` to re-engage."