Skip to content

Commit 21175c7

Browse files
fix(dispatch): address review feedback on workflow_call dispatch
- Per-org stage jobs: explicit OIDC permissions; kill-switch ternary fix - Role mapping: code|fix → coder; prioritize workflow_call secrets - Per-repo reusable-dispatch: prioritize job via .fullsend/prioritize.yml - finding-agent-runs skill: dispatch.yml instead of removed thin workflows - reusable-fix: fail closed when gh pr view fails (bot eligibility) - pre-code-test: restore line-by-line extra_env parsing - e2e: capture issueCreatedAt before issue creation Signed-off-by: Barak Korren <bkorren@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: Barak Korren <bkorren@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 557c374 commit 21175c7

9 files changed

Lines changed: 67 additions & 23 deletions

File tree

.github/workflows/reusable-dispatch.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
contents: read
5050
pull-requests: read
5151
outputs:
52-
stage: ${{ steps.role-check.outputs.skipped == 'true' && '' || steps.route.outputs.stage }}
52+
stage: ${{ steps.role-check.outputs.skipped != 'true' && steps.route.outputs.stage || '' }}
5353
trigger_source: ${{ steps.route.outputs.trigger_source }}
5454
event_payload: ${{ steps.payload.outputs.event_payload }}
5555
steps:
@@ -413,3 +413,19 @@ jobs:
413413
FULLSEND_GCP_WIF_PROVIDER: ${{ secrets.FULLSEND_GCP_WIF_PROVIDER }}
414414

415415
FULLSEND_GCP_PROJECT_ID: ${{ secrets.FULLSEND_GCP_PROJECT_ID }}
416+
417+
prioritize:
418+
name: Prioritize
419+
needs: route
420+
if: needs.route.outputs.stage == 'prioritize'
421+
uses: ./.fullsend/.github/workflows/prioritize.yml
422+
permissions:
423+
contents: read
424+
id-token: write
425+
with:
426+
event_type: ${{ github.event_name }}
427+
source_repo: ${{ github.repository }}
428+
event_payload: ${{ needs.route.outputs.event_payload }}
429+
secrets:
430+
FULLSEND_GCP_WIF_PROVIDER: ${{ secrets.FULLSEND_GCP_WIF_PROVIDER }}
431+
FULLSEND_GCP_PROJECT_ID: ${{ secrets.FULLSEND_GCP_PROJECT_ID }}

.github/workflows/reusable-fix.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,8 @@ jobs:
259259
run: |
260260
if [[ "${TRIGGER_SOURCE}" =~ \[bot\]$ ]]; then
261261
PR_INFO=$(gh pr view "${PR_NUM}" --repo "${SOURCE_REPO}" \
262-
--json labels,author --jq '{labels: [.labels[].name], author: .author.login}' 2>/dev/null \
263-
|| echo '{"labels":[],"author":""}')
262+
--json labels,author --jq '{labels: [.labels[].name], author: .author.login}') \
263+
|| { echo "::error::Failed to fetch PR info for #${PR_NUM}"; exit 1; }
264264
265265
HAS_NO_FIX=$(echo "${PR_INFO}" | jq -r '.labels | any(. == "fullsend-no-fix")')
266266
if [[ "${HAS_NO_FIX}" == "true" ]]; then

.pre-commit-config.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ repos:
7070
- SC2016
7171
- -ignore
7272
- 'could not read reusable workflow file for "\./\.github/workflows/prioritize\.yml"'
73+
- -ignore
74+
- 'could not read reusable workflow file for "\./\.fullsend/\.github/workflows/prioritize\.yml"'
7375

7476
- repo: local
7577
hooks:

e2e/admin/admin_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,11 @@ func runTriageDispatchSmokeTest(t *testing.T, env *e2eEnv) {
250250
t.Helper()
251251
ctx := context.Background()
252252

253+
// Capture a lower-bound timestamp *before* creating the issue.
254+
// The shim/dispatch workflows can start very quickly, and we only want to
255+
// filter out runs from earlier test phases.
256+
issueCreatedAt := time.Now()
257+
253258
// File a test issue to trigger the shim workflow.
254259
issueTitle := fmt.Sprintf("e2e-triage-test-%s", env.runID)
255260
issueBody := `## Bug Report
@@ -294,7 +299,6 @@ Files over 64KB save fine if they contain only ASCII characters.`
294299
// Wait for dispatch.yml to run in .fullsend (shim → dispatch → reusable-triage).
295300
// The shim fires on issues:opened and runs the triage stage synchronously.
296301
// Filter by CreatedAt to avoid false positives from previous runs.
297-
issueCreatedAt := time.Now()
298302
t.Log("Waiting for dispatch workflow to run...")
299303
var dispatchRun *forge.WorkflowRun
300304
for attempt := 0; attempt < 12; attempt++ {

internal/scaffold/fullsend-repo/.github/workflows/dispatch.yml

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,14 @@ jobs:
2525
contents: read
2626
pull-requests: read
2727
outputs:
28-
stage: ${{ steps.role-check.outputs.skipped == 'true' && '' || steps.route.outputs.stage }}
28+
stage: ${{ steps.role-check.outputs.skipped != 'true' && steps.route.outputs.stage || '' }}
2929
trigger_source: ${{ steps.route.outputs.trigger_source }}
3030
event_payload: ${{ steps.payload.outputs.event_payload }}
3131
steps:
3232
- name: Checkout config repository
3333
uses: actions/checkout@v6
3434
with:
35+
repository: ${{ job.workflow_repository }}
3536
persist-credentials: false
3637
sparse-checkout: config.yaml
3738
sparse-checkout-cone-mode: false
@@ -231,7 +232,7 @@ jobs:
231232
set -euo pipefail
232233
STAGE_ROLE="$STAGE"
233234
case "$STAGE" in
234-
code) STAGE_ROLE="coder" ;;
235+
code|fix) STAGE_ROLE="coder" ;;
235236
retro|prioritize) STAGE_ROLE="fullsend" ;;
236237
esac
237238
@@ -292,6 +293,9 @@ jobs:
292293
name: Triage
293294
needs: route
294295
if: needs.route.outputs.stage == 'triage'
296+
permissions:
297+
contents: read
298+
id-token: write
295299
uses: fullsend-ai/fullsend/.github/workflows/reusable-triage.yml@v0
296300
with:
297301
event_type: ${{ github.event_name }}
@@ -308,6 +312,9 @@ jobs:
308312
name: Code
309313
needs: route
310314
if: needs.route.outputs.stage == 'code'
315+
permissions:
316+
contents: read
317+
id-token: write
311318
uses: fullsend-ai/fullsend/.github/workflows/reusable-code.yml@v0
312319
with:
313320
event_type: ${{ github.event_name }}
@@ -324,6 +331,9 @@ jobs:
324331
name: Review
325332
needs: route
326333
if: needs.route.outputs.stage == 'review'
334+
permissions:
335+
contents: read
336+
id-token: write
327337
uses: fullsend-ai/fullsend/.github/workflows/reusable-review.yml@v0
328338
with:
329339
event_type: ${{ github.event_name }}
@@ -340,6 +350,9 @@ jobs:
340350
name: Fix
341351
needs: route
342352
if: needs.route.outputs.stage == 'fix'
353+
permissions:
354+
contents: read
355+
id-token: write
343356
uses: fullsend-ai/fullsend/.github/workflows/reusable-fix.yml@v0
344357
with:
345358
event_type: ${{ github.event_name }}
@@ -357,6 +370,9 @@ jobs:
357370
name: Retro
358371
needs: route
359372
if: needs.route.outputs.stage == 'retro'
373+
permissions:
374+
contents: read
375+
id-token: write
360376
uses: fullsend-ai/fullsend/.github/workflows/reusable-retro.yml@v0
361377
with:
362378
event_type: ${{ github.event_name }}
@@ -374,6 +390,12 @@ jobs:
374390
needs: route
375391
if: needs.route.outputs.stage == 'prioritize'
376392
uses: ./.github/workflows/prioritize.yml
393+
permissions:
394+
contents: read
395+
id-token: write
396+
secrets:
397+
FULLSEND_GCP_WIF_PROVIDER: ${{ secrets.FULLSEND_GCP_WIF_PROVIDER }}
398+
FULLSEND_GCP_PROJECT_ID: ${{ secrets.FULLSEND_GCP_PROJECT_ID }}
377399
with:
378400
event_type: ${{ github.event_name }}
379401
source_repo: ${{ github.repository }}

internal/scaffold/fullsend-repo/.github/workflows/prioritize.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ on:
1212
event_payload:
1313
required: true
1414
type: string
15+
secrets:
16+
FULLSEND_GCP_WIF_PROVIDER:
17+
required: true
18+
FULLSEND_GCP_PROJECT_ID:
19+
required: true
1520
workflow_dispatch:
1621
inputs:
1722
event_type:

internal/scaffold/fullsend-repo/scripts/pre-code-test.sh

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,11 @@ run_test() {
8686
GH_TOKEN="fake-token"
8787
)
8888

89-
# Add extra env vars if provided.
89+
# Add extra env vars if provided (read line-by-line to support values with spaces).
9090
if [[ -n "${extra_env}" ]]; then
91-
for kv in ${extra_env}; do
92-
env_cmd+=("${kv}")
93-
done
91+
while IFS= read -r kv; do
92+
[[ -n "${kv}" ]] && env_cmd+=("${kv}")
93+
done <<< "${extra_env}"
9494
fi
9595

9696
local exit_code=0
@@ -139,9 +139,9 @@ run_test_stdout() {
139139
)
140140

141141
if [[ -n "${extra_env}" ]]; then
142-
for kv in ${extra_env}; do
143-
env_cmd+=("${kv}")
144-
done
142+
while IFS= read -r kv; do
143+
[[ -n "${kv}" ]] && env_cmd+=("${kv}")
144+
done <<< "${extra_env}"
145145
fi
146146

147147
local exit_code=0

internal/scaffold/fullsend-repo/skills/finding-agent-runs/SKILL.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ gh run list --workflow=fullsend.yaml \
8181
Confirm `dispatch-review completed/success`, then find the run:
8282

8383
```bash
84-
gh run list --repo "${DISPATCH_REPO}" --workflow=review.yml --limit 5 \
84+
gh run list --repo "${DISPATCH_REPO}" --workflow=dispatch.yml --limit 5 \
8585
--json databaseId,status,conclusion,createdAt
8686
```
8787

@@ -99,7 +99,7 @@ gh run list --workflow=fullsend.yaml \
9999
Find the actual retro agent run:
100100

101101
```bash
102-
gh run list --repo "${DISPATCH_REPO}" --workflow=retro.yml --limit 5 \
102+
gh run list --repo "${DISPATCH_REPO}" --workflow=dispatch.yml --limit 5 \
103103
--json databaseId,status,conclusion,createdAt
104104
```
105105

internal/scaffold/scaffold_test.go

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ func TestDispatchWorkflowContent(t *testing.T) {
231231
assert.Contains(t, s, "install_mode: per-org")
232232
assert.Contains(t, s, "permissions: {}")
233233
assert.Contains(t, s, "sparse-checkout: config.yaml")
234+
assert.Contains(t, s, "repository: ${{ job.workflow_repository }}")
235+
assert.Contains(t, s, "FULLSEND_GCP_WIF_PROVIDER")
236+
assert.Contains(t, s, "FULLSEND_GCP_PROJECT_ID")
234237
assert.Contains(t, s, "set -euo pipefail")
235238
assert.Contains(t, s, "Invalid stage name")
236239
assert.Contains(t, s, `^[a-z][a-z0-9_-]*$`)
@@ -389,14 +392,6 @@ func TestCodeAgentContent(t *testing.T) {
389392
assert.Contains(t, s, "code-implementation")
390393
}
391394

392-
func TestCodeImplementationSkillAPIContractGuidance(t *testing.T) {
393-
content, err := FullsendRepoFile("skills/code-implementation/SKILL.md")
394-
require.NoError(t, err)
395-
s := string(content)
396-
assert.Contains(t, s, "Verify API contracts per code path")
397-
assert.Contains(t, s, "or changes a parameter sent to an external API")
398-
}
399-
400395
func TestSetupGcpActionContent(t *testing.T) {
401396
content, err := FullsendRepoFile(".github/actions/setup-gcp/action.yml")
402397
require.NoError(t, err)

0 commit comments

Comments
 (0)