feat(triage): add prerequisites action for upstream issue creation (#401)#2197
feat(triage): add prerequisites action for upstream issue creation (#401)#2197ralphbean wants to merge 12 commits into
Conversation
Design for a new `prerequisites` triage action that replaces `blocked`. The agent can now express both existing blockers and new issues that need to be created upstream before progress can happen. Includes allowlist configuration for cross-repo issue creation and a degraded path when targets are not authorized. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Seven-task plan covering config structs, JSON schema, agent prompt, post-script, user docs, and caller updates. TDD approach with exact file paths and code blocks. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Add CreateIssuesConfig and AllowTargets types to both OrgConfig and PerRepoConfig. NewOrgConfig populates defaults with the org and fullsend-ai/fullsend. NewPerRepoConfig populates with the target repo and fullsend-ai/fullsend. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
…ues (#401) Pass org name and target repo to config constructors so create_issues defaults are populated at install time. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Replace the blocked action and blocked_by field with a prerequisites action containing existing[] and create[] arrays. At least one array must be non-empty. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
…pt (#401) The triage agent can now recommend creating upstream issues via the prerequisites action's create array, in addition to referencing existing blockers. Adds hard constraint against emitting sufficient when prerequisites exist. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Update triage agent docs to explain the new prerequisites action and the create_issues.allow_targets configuration surface. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Replace the blocked handler with prerequisites. The post-script reads the create_issues allowlist from config.yaml, creates permitted upstream issues via gh, and includes collapsed draft bodies for disallowed or failed creates so humans can file them manually. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Site previewPreview: https://33c98cb6-site.fullsend-ai.workers.dev Commit: |
|
🤖 Review · Started 8:33 PM UTC |
…401) The agent prompt referenced a nonexistent `prerequisites` label when checking for prior blockers — the post-script actually applies the `blocked` label. Also removed unused SOURCE_ORG variable from post-triage.sh. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
|
🤖 Finished Review · ✅ Success · Started 8:37 PM UTC · Completed 8:51 PM UTC |
ReviewFindingsMedium
Low
Info
Previous runReviewFindingsHigh
Medium
Low
Info
Previous run (2)ReviewFindingsHigh
Medium
Low
Info
Previous runReviewFindingsHigh
Medium
Info
Previous run (3)ReviewFindingsHigh
Medium
Low
Info
Previous run (4)ReviewFindingsHigh
Medium
Info
|
Replace the four blocked-action test cases with five prerequisites-action test cases that exercise the new schema (existing[], create[], allowlist validation). Set up GITHUB_WORKSPACE with a config.yaml fixture and add a mock gh issue-create handler that returns a fake URL. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
|
🤖 Finished Review · ✅ Success · Started 9:24 PM UTC · Completed 9:38 PM UTC |
|
|
||
| # Process create entries: create issues, collect URLs. | ||
| CREATE_COUNT=$(jq '.prerequisites.create // [] | length' "${RESULT_FILE}") | ||
| CREATED_URLS="" |
There was a problem hiding this comment.
[medium] command_injection
CREATED_URL from gh error path (captured via 2>&1) is interpolated into a ::warning:: GHA workflow command. Error messages from gh are unconstrained and could contain %0A/newline sequences. TARGET_REPO is schema-constrained but CREATED_URL has no such constraint.
Suggested fix: Sanitize CREATED_URL before interpolation into ::warning:: by stripping %0A, %0D, ::, and control characters.
| # Process create entries: create issues, collect URLs. | ||
| CREATE_COUNT=$(jq '.prerequisites.create // [] | length' "${RESULT_FILE}") | ||
| CREATED_URLS="" | ||
| FAILED_CREATES="" |
There was a problem hiding this comment.
[medium] data_exposure
AI-generated ISSUE_BODY posted to external public repos without human review. Prompt injection in source issue could instruct agent to include sensitive internal context. No maxLength on body field in schema.
Suggested fix: Add maxLength to body field in schema. Consider logging the full body for audit purposes before creation.
| If a cross-repo search fails or returns an error (e.g., due to access restrictions), note this in your reasoning as an information gap rather than concluding no blocking work exists. | ||
|
|
||
| ### 2c. Check existing blockers | ||
| ### 2c. Check existing prerequisites |
There was a problem hiding this comment.
[medium] naming-inconsistency
Section 2c heading changed to 'Check existing prerequisites' but body text still references 'blocker', 'blocked label', and 'blocking issue' inconsistently.
Suggested fix: Align terminology consistently to prerequisites throughout section 2c.
|
Ran The agent picked {
"action": "prerequisites",
"prerequisites": {
"existing": [
{ "url": "https://github.com/appdumpster/misleading/issues/2" }
],
"create": []
}
}Also pushed 080368c to fix the Trace: |
|
Second run — this time against appdumpster/test-repo#35, an issue that depends on a missing feature in The agent picked {
"action": "prerequisites",
"prerequisites": {
"existing": [],
"create": [
{
"repo": "appdumpster/workflows",
"title": "Add optional SBOM attestation support to sign-artifact.yml",
"body": "## Problem\n\nThe `sign-artifact.yml` reusable workflow currently supports cosign signing and build provenance attestation, but has no support for SBOM generation or SBOM attestation. ..."
}
]
}
}So both paths work — Trace: |
|
Full end-to-end run against appdumpster/test-repo#35 with the post-script enabled. The agent identified a missing upstream issue in Trace: |
…401) Replace blocked-action test cases with prerequisites-action equivalents and update the expected property list (blocked_by → prerequisites). Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
|
🤖 Review · Started 1:16 AM UTC |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
| "action": { | ||
| "type": "string", | ||
| "enum": ["insufficient", "duplicate", "sufficient", "blocked", "question"] | ||
| "enum": ["insufficient", "duplicate", "sufficient", "prerequisites", "question"] |
There was a problem hiding this comment.
[high] breaking-change-schema-contract
The triage result schema replaces the blocked enum value with prerequisites and removes the blocked_by property. The schema, agent prompt, and post-script are scaffolded files deployed atomically, but customer repos pinning @v0 receive the breaking change when the tag is updated.
Suggested fix: Ensure all three components ship in the same release. Document the breaking change in release notes so operators know to configure create_issues.allow_targets.
| # Process create entries: create issues, collect URLs. | ||
| CREATE_COUNT=$(jq '.prerequisites.create // [] | length' "${RESULT_FILE}") | ||
| CREATED_URLS="" | ||
| FAILED_CREATES="" |
There was a problem hiding this comment.
[medium] data_exposure
AI-generated ISSUE_BODY is posted to external public repositories via gh issue create without human review. A prompt injection in the source issue could instruct the triage agent to include sensitive internal context in the body of issues created in public upstream repos.
Suggested fix: Consider adding content-length limits on the body field in the JSON schema and stripping patterns that look like secrets or internal URLs.
|
🤖 Finished Review · ✅ Success · Started 1:16 AM UTC · Completed 1:34 AM UTC |
- Replace stale blocked-* schema validation tests with prerequisites equivalents (missing field, both arrays empty, malformed URL) - Fix validateCreateIssues to reject malformed repo formats like "/", "/repo", "owner/" - Align triage.md section 2c terminology from "blocker" to "prerequisite" consistently - Update bugfix-workflow.md and architecture.md to document upstream issue creation capability - Emit ::warning:: when yq is unavailable so silent degradation of cross-repo issue creation is diagnosable Signed-off-by: Ralph Bean <rbean@redhat.com> Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
|
🤖 Finished Review · ✅ Success · Started 4:06 PM UTC · Completed 4:23 PM UTC |
Summary
blockedaction with a newprerequisitesaction that can both reference existing blockers and create new upstream issuescreate_issues.allow_targetsconfig (orgs + repos allowlist) to control where agents can file issues, with sensible install-time defaults<details>block for manual filingMotivation
The triage agent could detect that an issue was blocked by work elsewhere, but couldn't create the missing tracking issue when none existed. This forced humans to manually identify, draft, and file prerequisite issues in upstream repos. A GitHub App token scoped to one repo can create issues in any public repo (confirmed by GitHub as known behavior), so no auth changes were needed.
Changes
internal/config/config.goCreateIssuesConfig+AllowTargetstypes on bothOrgConfigandPerRepoConfig, with install-time defaults and validationschemas/triage-result.schema.jsonblocked→prerequisitesaction withexisting[]andcreate[]arraysagents/triage.mdprerequisitesaction docs, hard constraint againstsufficientwhen prerequisites existscripts/post-triage.shgh issue createfor permitted targets, collapsed draft for disallowed/failed createsdocs/agents/triage.mdcreate_issuesconfig surfaceScope
This is one of three decomposition strategies identified during design. The other two (split muddled issues, parent/child decompose) are future work.
Test plan
make go-test)make lint)make go-vet)jq empty)bash -n)Closes #401
🤖 Generated with Claude Code