Skip to content
Merged
Show file tree
Hide file tree
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
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@
/.cursor/ @redhat-developer/rhdh-plugins-maintainers @redhat-developer/rhdh-fullsend
/.fullsend/ @redhat-developer/rhdh-plugins-maintainers @redhat-developer/rhdh-fullsend
/.github/workflows/fullsend.yaml @redhat-developer/rhdh-plugins-maintainers @redhat-developer/rhdh-fullsend
/.github/workflows/prioritize.yml @redhat-developer/rhdh-plugins-maintainers @redhat-developer/rhdh-fullsend
81 changes: 57 additions & 24 deletions .github/workflows/fullsend.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,66 +12,70 @@
# attacks.
#
# Routing: this shim forwards the raw event context to reusable-dispatch.yml,
# which determines the stage and conditionally calls the appropriate
# reusable-{stage}.yml workflow. Adding a new stage requires only a case
# branch in reusable-dispatch.yml — zero changes to this repo.
# 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 and agent-scoped groups on reusable-{stage}.yml — not on this shim.
# A monolithic shim group would serialize unrelated roles and drop pending runs (#2452).
# stage jobs with -agent- suffix. Roles operate independently (#2452).
name: fullsend

permissions:
actions: write
id-token: write
contents: write
issues: write
packages: read
pull-requests: write

on:
issues:
types: [opened, edited, labeled]
issue_comment:
types: [created]
pull_request_target:
types: [opened, synchronize, ready_for_review, closed]
types: [opened, synchronize, ready_for_review, closed, labeled, unlabeled]
# Monorepo: only auto-dispatch on workspaces enrolled for fullsend.
# Slash commands on other workspaces still work via issue_comment.
paths:
- "workspaces/boost/**"
- "workspaces/scorecard/**"
- "workspaces/ai-integrations/**"
pull_request_review:
types: [submitted]

permissions: {}

jobs:
dispatch:
if: >-
github.event_name != 'issue_comment'
|| github.event.comment.user.type != 'Bot'
uses: fullsend-ai/fullsend/.github/workflows/reusable-dispatch.yml@3cfa255ab4cc8190670585ea42da529119251632 # v0.32.0
(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'
|| 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@84c8bbbb821ff85136854150b06740253709b3b8 # v0.37.0
with:
event_action: ${{ github.event.action }}
install_mode: per-repo
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 }}
OTEL_EXPORTER_OTLP_TRACES_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_TRACES_HEADERS }}
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}

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'
&& (
github.event.comment.author_association == 'OWNER'
|| github.event.comment.author_association == 'MEMBER'
|| github.event.comment.author_association == 'COLLABORATOR'
|| github.event.comment.author_association == 'CONTRIBUTOR'
|| github.event.comment.user.login == github.event.issue.user.login
)
runs-on: ubuntu-24.04
permissions:
contents: read
Expand All @@ -83,8 +87,37 @@ jobs:
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 dispatch.yml; 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 '.role_name' 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" \
--force 2>/dev/null || true
Expand Down
50 changes: 50 additions & 0 deletions .github/workflows/prioritize.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 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/prioritize.yml
---
# fullsend-stage: prioritize
name: Prioritize

permissions:
actions: write
contents: read
id-token: write
issues: write

on:
workflow_dispatch:
inputs:
event_type:
required: true
type: string
source_repo:
required: true
type: string
event_payload:
required: true
type: string
project_number:
description: GitHub Projects V2 project number for RICE scoring
required: false
type: string

concurrency:
group: fullsend-prioritize-${{ inputs.source_repo }}-${{ fromJSON(inputs.event_payload).issue.number }}
cancel-in-progress: true

jobs:
prioritize:
uses: fullsend-ai/fullsend/.github/workflows/reusable-prioritize.yml@84c8bbbb821ff85136854150b06740253709b3b8 # v0.37.0
with:
event_type: ${{ inputs.event_type }}
source_repo: ${{ inputs.source_repo }}
event_payload: ${{ inputs.event_payload }}
mint_url: ${{ vars.FULLSEND_MINT_URL }}
gcp_region: ${{ vars.FULLSEND_GCP_REGION }}
project_number: ${{ inputs.project_number || vars.FULLSEND_PROJECT_NUMBER }}
install_mode: per-repo
runner_image: ubuntu-24.04
secrets:
FULLSEND_GCP_WIF_PROVIDER: ${{ secrets.FULLSEND_GCP_WIF_PROVIDER }}
FULLSEND_GCP_PROJECT_ID: ${{ secrets.FULLSEND_GCP_PROJECT_ID }}
OTEL_EXPORTER_OTLP_TRACES_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_TRACES_HEADERS }}
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}
Loading