harden(ai-issues): gate improvements, pin codex-action, report publish failures

- Require repo-owner authorship or the `ai: fix-approved` label before Codex
  runs on existing-add-on improvements, mirroring the bug path. Closes the
  cost/abuse vector where any external user could auto-trigger expensive Codex
  runs and draft PRs.
- Pin openai/codex-action to a commit SHA (was the mutable @v1 tag) since it
  receives OPENAI_API_KEY.
- Add a catch-all failure reporter to publish_fix so apply/push/PR-create
  failures notify the issue and swap labels instead of failing silently.
- Reject creation of new top-level files in the patch validator (previously
  only new directories were blocked).
- Update triage comment wording and README to match the new gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
alexbelgium
2026-07-23 12:51:33 +02:00
parent ee0c1e2b96
commit c7f5a9a292
3 changed files with 50 additions and 19 deletions

View File

@@ -12,10 +12,10 @@ maintainer.
3. Reports missing essential evidence receive focused questions.
4. New add-on requests are marked for maintainer review and are never
implemented by this automation.
5. High-confidence improvements to existing add-ons proceed automatically to a
draft fix attempt.
6. Bugs opened by the repository owner proceed directly to Codex analysis;
other bugs wait for a maintainer to add `ai: fix-approved`.
5. High-confidence bugs and existing-add-on improvements opened by the
repository owner proceed directly to Codex analysis; those opened by anyone
else wait for a maintainer to add `ai: fix-approved`.
6. New add-on requests never enter Codex, regardless of who opens them.
7. Codex edits an isolated checkout without repository write permissions.
8. A fresh job applies and validates the patch, pushes a branch, opens a draft
pull request, and posts the root-cause report and pull-request URL.

View File

@@ -84,6 +84,11 @@ for file in "${changed_files[@]}"; do
echo "Creating a new top-level directory is not permitted: $top" >&2
exit 1
fi
else
if ! git cat-file -e "$base_ref:$file" 2>/dev/null; then
echo "Creating a new top-level file is not permitted: $file" >&2
exit 1
fi
fi
if [[ "$request_category" == "improvement" && -n "$expected_addon" && "$file" != "$expected_addon/"* ]]; then

View File

@@ -261,14 +261,22 @@ jobs:
improvement)
labels+=("enhancement")
if [[ "$EXISTING_ADDON" == true ]]; then
labels+=("ai: fix-proposed" "ai: fixing")
labels+=("ai: fix-proposed")
body="**Assessment:** ${summary}
**Estimated risk:** ${risk}
${response}
${response}"
if [[ "$ISSUE_AUTHOR" == "$REPOSITORY_OWNER" ]]; then
labels+=("ai: fixing")
body="${body}
This targets an existing add-on, so repository analysis and a validated draft fix attempt will start automatically."
This targets an existing add-on, so repository analysis and a validated draft fix attempt will start automatically because the issue was opened by the repository owner."
else
body="${body}
This targets an existing add-on. A maintainer can approve repository analysis and an automated draft fix attempt by adding the \`ai: fix-approved\` label."
fi
else
labels+=("ai: maintainer-review")
body="${response}
@@ -319,18 +327,16 @@ jobs:
needs.triage.outputs.category == 'improvement' &&
needs.triage.outputs.existing_addon == 'true'
) ||
needs.triage.outputs.category == 'bug'
) &&
(
(
needs.triage.outputs.category == 'bug' &&
(
(
github.event.action == 'labeled' &&
github.event.label.name == 'ai: fix-approved'
) ||
(
(github.event.action == 'opened' || github.event.action == 'reopened') &&
github.event.issue.user.login == github.repository_owner
)
)
github.event.action == 'labeled' &&
github.event.label.name == 'ai: fix-approved'
) ||
(
(github.event.action == 'opened' || github.event.action == 'reopened') &&
github.event.issue.user.login == github.repository_owner
)
)
needs: [detect_submitter, triage]
@@ -395,7 +401,7 @@ jobs:
- name: Run Codex
id: codex
if: steps.prepare.outputs.existing_pr == ''
uses: openai/codex-action@v1
uses: openai/codex-action@52fe01ec70a42f454c9d2ebd47598f9fd6893d56 # v1
with:
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
prompt-file: codex-prompt.md
@@ -652,3 +658,23 @@ jobs:
gh issue edit "$ISSUE_NUMBER" --repo "$REPO" \
--add-label "ai: pr-created"
gh issue comment "$ISSUE_NUMBER" --repo "$REPO" --body "$body"
- name: Report publication failure
if: failure() && steps.validation.outcome != 'failure'
env:
GH_TOKEN: ${{ secrets.AI_PR_TOKEN || secrets.GITHUB_TOKEN }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
REPO: ${{ github.repository }}
RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
for label in "ai: fix-approved" "ai: fix-proposed" "ai: fixing"; do
gh issue edit "$ISSUE_NUMBER" --repo "$REPO" \
--remove-label "$label" || true
done
gh issue edit "$ISSUE_NUMBER" --repo "$REPO" \
--add-label "ai: maintainer-review" || true
gh issue comment "$ISSUE_NUMBER" --repo "$REPO" --body \
"### Automated publication failed
A patch was generated but could not be published (applying, pushing, or opening the draft pull request failed), so no pull request was created. A maintainer should review the [workflow run](${RUN_URL})."