Skip to content

Commit 5520764

Browse files
authored
Merge pull request #3582 from conforma/fullsend/scaffold-install
chore: initialize fullsend per-repo installation
2 parents 8a9bb47 + 08d00b5 commit 5520764

7 files changed

Lines changed: 313 additions & 31 deletions

File tree

‎.fullsend/config.yaml‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright The Conforma Contributors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# SPDX-License-Identifier: Apache-2.0
16+
17+
# fullsend per-repo configuration
18+
# https://github.com/fullsend-ai/fullsend
19+
#
20+
# This file configures fullsend for per-repo installation mode.
21+
# See https://fullsend.sh/docs/guides/infrastructure/layered-config-reference
22+
version: "1"
23+
roles:
24+
- fullsend
25+
- triage
26+
- coder
27+
- fix
28+
- review
29+
- retro
30+
- prioritize
31+
agents:
32+
- name: review
33+
source: customized/harness/review.yaml
34+
- name: retro
35+
source: customized/harness/retro.yaml
36+
allowed_remote_resources:
37+
- https://raw.githubusercontent.com/fullsend-ai/fullsend/
38+
- https://raw.githubusercontent.com/fullsend-ai/agents/
39+
create_issues:
40+
allow_targets:
41+
repos:
42+
- conforma/cli
43+
- fullsend-ai/fullsend
44+
status_notifications:
45+
comment:
46+
completion: on_failure
47+
reaction:
48+
start: enabled
49+
completion: disabled
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright The Conforma Contributors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# SPDX-License-Identifier: Apache-2.0
16+
17+
# Derived retro harness: retain upstream analysis and append the Conforma gate.
18+
base: https://raw.githubusercontent.com/fullsend-ai/agents/69ade99f1b61bea99aee98e604384e26ff7b45e0/harness/retro.yaml#sha256=6d858c90cc6f1c7526d2b36b8cd47df079d1332ac7184bb70dfb1587e9cb04d8
19+
20+
skills:
21+
- customized/skills/retro-filing-policy
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright The Conforma Contributors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# SPDX-License-Identifier: Apache-2.0
16+
17+
base: https://raw.githubusercontent.com/fullsend-ai/agents/440d3e3c1a4a770309e37c2fd2826dfc88297d99/harness/review.yaml#sha256=c259d94e7c50e5e01cb0fa38df2b70765f8e35beb7ad8bf006c9193a05589917
18+
19+
# Fullsend's bool merge treats an omitted readonly_repo as false, so carry
20+
# forward the upstream read-only guarantee explicitly.
21+
readonly_repo: true
22+
23+
env:
24+
runner:
25+
REVIEW_FINDING_SEVERITY_THRESHOLD: "high"
26+
sandbox:
27+
REVIEW_FINDING_SEVERITY_THRESHOLD: "high"
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
name: retro-filing-policy
3+
description: >-
4+
Required on every Conforma retro run. Score every candidate from 0 to 5
5+
and file only score-4 and score-5 findings after duplicate checks.
6+
---
7+
8+
# Conforma retro filing policy
9+
10+
This skill is mandatory for every retro run. Invoke it before writing
11+
`$FULLSEND_OUTPUT_DIR/agent-result.json`. It augments the upstream retro
12+
analysis and does not replace its workflow reconstruction, duplicate checks,
13+
recently-closed checks, evidence handling, or proposal limit.
14+
15+
## Required filing sequence
16+
17+
1. Build the complete candidate list from the upstream retro analysis.
18+
2. Before deciding what belongs in `proposals[]`, assign every candidate an
19+
integer judge score from 0 through 5 using the rubric below.
20+
3. Apply the upstream checks for an existing open duplicate or a substantially
21+
equivalent issue closed recently. A duplicate or recently closed equivalent
22+
is summary-only even when its score is 4 or 5. Supporting evidence for an
23+
existing issue is summary-only and must never become an "Evidence for ..."
24+
proposal.
25+
4. Put only eligible, non-duplicate candidates scored 4 or 5 in `proposals[]`.
26+
Preserve the upstream maximum of three proposals, keeping the highest-value
27+
candidates when there are more than three.
28+
5. Keep every score-0-through-3 candidate out of `proposals[]`. Mention it in
29+
the retro `summary` as summary-only, with a compact reason.
30+
6. In the `summary`, include a compact **Judge scores** list covering every
31+
candidate, filed and summary-only. Each entry must contain the score, a
32+
short title, and the disposition (`filed` or `summary-only`).
33+
7. For every filed proposal, begin the existing
34+
`what_could_go_better` text field with:
35+
36+
`Judge score: N/5 — <one-line justification>`
37+
38+
Do not add new JSON fields or change the upstream result schema.
39+
40+
Do not create, edit, or post issues yourself. The upstream post-script handles
41+
writes after output validation.
42+
43+
## Conforma scoring rubric
44+
45+
Score the impact of the candidate, not how interesting the observation is.
46+
Use the lower range by default for isolated improvements:
47+
48+
- One-off pitfalls, cosmetic documentation edits, historical-document
49+
cleanup, speculative prevention rules, and isolated preferences score 0–3
50+
by default. They are not eligible for filing without evidence that a higher
51+
threshold applies.
52+
- An `AGENTS.md` proposal scores 0–3 by default. It can score 4 or 5 only
53+
when there is evidence of a recurring contributor or agent failure, the rule
54+
applies to human contributors as well as bots, and the instruction has a
55+
credible preventive mechanism.
56+
57+
Use score 4 only when there is a likely recurring impact, such as repeated
58+
human time loss, repeated bad bot output, pipeline or policy integrity risk,
59+
or persistent operational cost.
60+
61+
Use score 5 only for a systemic or recurring correctness, security,
62+
reliability, or policy failure.
63+
64+
A high score does not bypass the upstream duplicate, recently-closed, or
65+
evidence-for checks. If those checks suppress a candidate, list it as
66+
summary-only and explain the disposition in the summary.

‎.github/workflows/fullsend.yaml‎

Lines changed: 75 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,67 +14,81 @@
1414
#
1515
# SPDX-License-Identifier: Apache-2.0
1616

17-
# lint-workflow-size: max-lines=280
18-
# fullsend shim workflow (workflow_call mode)
19-
# Routes events to agent workflows in .fullsend via workflow_call.
20-
# No secrets are needed in the enrolled repo — agents fetch scoped tokens
21-
# from the centralized token mint using GitHub OIDC.
17+
# This file is managed by fullsend. Do not edit it directly.
18+
# Upstream: https://github.com/fullsend-ai/fullsend/blob/main/internal/scaffold/fullsend-repo/.github/workflows/fullsend.yaml
19+
---
20+
# fullsend shim workflow (per-repo installation mode)
21+
# Routes events to agent workflows via reusable-dispatch.yml.
22+
# All agent execution happens in this repo's context — no external
23+
# config repo is needed.
2224
#
2325
# Security: pull_request_target runs the BASE branch version of this workflow,
2426
# preventing PRs from modifying it to exfiltrate credentials.
2527
# This shim never checks out PR code, so it is not vulnerable to "pwn request"
2628
# attacks.
2729
#
28-
# conforma is replaced by reconcile-repos.sh at deploy time.
30+
# Routing: this shim forwards the raw event context to reusable-dispatch.yml,
31+
# which determines the stage and runs the agent inline (ADR 62).
32+
# Adding a new stage requires only a job in reusable-dispatch.yml — zero changes to this repo.
2933
#
30-
# Routing: this shim forwards the raw event context to dispatch.yml, which
31-
# determines the stage from event_type + event_action + payload fields.
32-
# Adding a new stage requires only a case branch in dispatch.yml — zero
33-
# changes to enrolled repos.
34+
# Concurrency: per-role cancel-in-progress groups live in reusable-dispatch.yml
35+
# stage jobs with -agent- suffix. Roles operate independently (#2452).
3436
name: fullsend
3537

36-
permissions:
37-
actions: write
38-
id-token: write
39-
contents: read
40-
pull-requests: read
41-
4238
on:
4339
issues:
4440
types: [opened, edited, labeled]
4541
issue_comment:
4642
types: [created]
4743
pull_request_target:
48-
types: [opened, synchronize, ready_for_review, closed]
44+
types: [opened, synchronize, ready_for_review, closed, labeled, unlabeled]
4945
pull_request_review:
5046
types: [submitted]
5147

48+
permissions: {}
49+
5250
jobs:
5351
dispatch:
54-
concurrency:
55-
group: fullsend-dispatch-${{ github.event.issue.number || github.event.pull_request.number }}
56-
cancel-in-progress: false
5752
if: >-
58-
github.event_name != 'issue_comment'
59-
|| github.event.comment.user.type != 'Bot'
60-
uses: conforma/.fullsend/.github/workflows/dispatch.yml@cd011389fdff80dc8ef963f82f7f200901e62f5c # main
53+
(github.event_name != 'pull_request_target' && github.event_name != 'pull_request_review'
54+
|| github.event.pull_request.head.ref != 'fullsend/scaffold-install')
55+
&& (github.event_name != 'issue_comment'
56+
|| (startsWith(github.event.comment.body, '/fs-')
57+
&& github.event.comment.user.type != 'Bot'))
58+
permissions:
59+
actions: write
60+
id-token: write
61+
contents: write
62+
issues: write
63+
packages: read
64+
pull-requests: write
65+
uses: fullsend-ai/fullsend/.github/workflows/reusable-dispatch.yml@main
6166
with:
6267
event_action: ${{ github.event.action }}
68+
install_mode: per-repo
69+
mint_url: ${{ vars.FULLSEND_MINT_URL }}
70+
gcp_region: ${{ vars.FULLSEND_GCP_REGION }}
71+
project_number: ${{ vars.FULLSEND_PROJECT_NUMBER }}
72+
runner_image: ubuntu-24.04
73+
secrets:
74+
FULLSEND_GCP_WIF_PROVIDER: ${{ secrets.FULLSEND_GCP_WIF_PROVIDER }}
75+
FULLSEND_GCP_PROJECT_ID: ${{ secrets.FULLSEND_GCP_PROJECT_ID }}
76+
FULLSEND_OPENAI_API_KEY: ${{ secrets.FULLSEND_OPENAI_API_KEY }}
77+
OTEL_EXPORTER_OTLP_TRACES_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_TRACES_HEADERS }}
78+
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}
6379

6480
stop-fix:
81+
# Job-level if: is intentionally coarse — it only screens for the
82+
# /fs-fix-stop command on a PR from a non-bot. The authoritative
83+
# authorization decision (collaborator permission API + PR-author escape
84+
# hatch) is made in the step below, so a maintainer whose author_association
85+
# is not MEMBER (e.g. private org membership) is not filtered out (ADR 0054).
6586
if: >-
6687
github.event_name == 'issue_comment'
6788
&& github.event.issue.pull_request
6889
&& github.event.comment.user.type != 'Bot'
6990
&& github.event.comment.body == '/fs-fix-stop'
70-
&& (
71-
github.event.comment.author_association == 'OWNER'
72-
|| github.event.comment.author_association == 'MEMBER'
73-
|| github.event.comment.author_association == 'COLLABORATOR'
74-
|| github.event.comment.author_association == 'CONTRIBUTOR'
75-
|| github.event.comment.user.login == github.event.issue.user.login
76-
)
77-
runs-on: ubuntu-latest
91+
runs-on: ubuntu-24.04
7892
permissions:
7993
contents: read
8094
issues: write
@@ -85,7 +99,37 @@ jobs:
8599
GH_TOKEN: ${{ github.token }}
86100
PR_NUMBER: ${{ github.event.issue.number }}
87101
REPO: ${{ github.repository }}
102+
COMMENT_USER_LOGIN: ${{ github.event.comment.user.login }}
103+
ISSUE_USER_LOGIN: ${{ github.event.issue.user.login }}
88104
run: |
105+
set -euo pipefail
106+
# ADR 0054: authorize via the collaborator permission API
107+
# (admin|maintain|write), not author_association — the latter grants
108+
# contributor status to anyone with a single merged PR (issue #5421).
109+
# Mirrors has_repo_permission() in dispatch.yml; keep the two in sync.
110+
# The PR author may always stop the fix agent on their own PR.
111+
authorized=false
112+
if [[ -n "$COMMENT_USER_LOGIN" && "$COMMENT_USER_LOGIN" == "$ISSUE_USER_LOGIN" ]]; then
113+
authorized=true
114+
else
115+
if api_err=$(mktemp); then
116+
if role=$(gh api "repos/$REPO/collaborators/$COMMENT_USER_LOGIN/permission" \
117+
--jq '.role_name' 2>"$api_err"); then
118+
case "$role" in
119+
admin|maintain|write) authorized=true ;;
120+
esac
121+
else
122+
echo "::warning::Permission API call failed for $COMMENT_USER_LOGIN: $(cat "$api_err")"
123+
fi
124+
rm -f "$api_err"
125+
else
126+
echo "::warning::Failed to create temp file for permission check of $COMMENT_USER_LOGIN"
127+
fi
128+
fi
129+
if [[ "$authorized" != "true" ]]; then
130+
echo "::notice::User $COMMENT_USER_LOGIN is not authorized to stop the fix agent (requires write access or PR authorship)"
131+
exit 0
132+
fi
89133
gh label create "fullsend-no-fix" --repo "$REPO" \
90134
--description "Skip bot-triggered fix agent runs" --color "FBCA04" \
91135
--force 2>/dev/null || true

‎.github/workflows/prioritize.yml‎

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright The Conforma Contributors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# SPDX-License-Identifier: Apache-2.0
16+
17+
# This file is managed by fullsend. Do not edit it directly.
18+
# Upstream: https://github.com/fullsend-ai/fullsend/blob/main/internal/scaffold/fullsend-repo/.github/workflows/prioritize.yml
19+
---
20+
# fullsend-stage: prioritize
21+
name: Prioritize
22+
23+
permissions:
24+
actions: write
25+
contents: read
26+
id-token: write
27+
issues: write
28+
29+
on:
30+
workflow_dispatch:
31+
inputs:
32+
event_type:
33+
required: true
34+
type: string
35+
source_repo:
36+
required: true
37+
type: string
38+
event_payload:
39+
required: true
40+
type: string
41+
project_number:
42+
description: GitHub Projects V2 project number for RICE scoring
43+
required: false
44+
type: string
45+
46+
concurrency:
47+
group: fullsend-prioritize-${{ inputs.source_repo }}-${{ fromJSON(inputs.event_payload).issue.number }}
48+
cancel-in-progress: true
49+
50+
jobs:
51+
prioritize:
52+
uses: fullsend-ai/fullsend/.github/workflows/reusable-prioritize.yml@main
53+
with:
54+
event_type: ${{ inputs.event_type }}
55+
source_repo: ${{ inputs.source_repo }}
56+
event_payload: ${{ inputs.event_payload }}
57+
mint_url: ${{ vars.FULLSEND_MINT_URL }}
58+
gcp_region: ${{ vars.FULLSEND_GCP_REGION }}
59+
project_number: ${{ inputs.project_number || vars.FULLSEND_PROJECT_NUMBER }}
60+
install_mode: per-repo
61+
runner_image: ubuntu-24.04
62+
secrets:
63+
FULLSEND_GCP_WIF_PROVIDER: ${{ secrets.FULLSEND_GCP_WIF_PROVIDER }}
64+
FULLSEND_GCP_PROJECT_ID: ${{ secrets.FULLSEND_GCP_PROJECT_ID }}
65+
FULLSEND_OPENAI_API_KEY: ${{ secrets.FULLSEND_OPENAI_API_KEY }}
66+
OTEL_EXPORTER_OTLP_TRACES_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_TRACES_HEADERS }}
67+
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}

‎AGENTS.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,11 @@ System-level issues that surface in acceptance tests:
188188
## Dependency Management
189189

190190
Go version updates are managed by both Renovate and Mintmaker (`red-hat-konflux[bot]`). The local `renovate.json` extends the org-level preset at `conforma/.github` with an additional `helpers:pinGitHubActionDigests` extension. The org-level config's dependency grouping strategy for Go has changed over time — config comments may reference a "go version" group that was never fully implemented. Do not propose changes to the Renovate or Mintmaker configuration for Go version management (e.g., adding package rules, re-enabling or disabling automated Go version bumps, or creating new dependency groups) without explicit maintainer approval.
191+
192+
## Retro filing
193+
194+
When running as the `retro` agent, invoke the `retro-filing-policy` skill
195+
before writing output. It is loaded by the derived retro harness and is the
196+
enforcement layer; this pointer is only reinforcement. Scores 0–3 are
197+
summary-only, while scores 4–5 remain subject to the upstream duplicate and
198+
recently-closed checks before filing.

0 commit comments

Comments
 (0)