mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-10-01 05:52:42 +02:00
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:
8
.github/ai/README.md
vendored
8
.github/ai/README.md
vendored
@@ -12,10 +12,10 @@ maintainer.
|
|||||||
3. Reports missing essential evidence receive focused questions.
|
3. Reports missing essential evidence receive focused questions.
|
||||||
4. New add-on requests are marked for maintainer review and are never
|
4. New add-on requests are marked for maintainer review and are never
|
||||||
implemented by this automation.
|
implemented by this automation.
|
||||||
5. High-confidence improvements to existing add-ons proceed automatically to a
|
5. High-confidence bugs and existing-add-on improvements opened by the
|
||||||
draft fix attempt.
|
repository owner proceed directly to Codex analysis; those opened by anyone
|
||||||
6. Bugs opened by the repository owner proceed directly to Codex analysis;
|
else wait for a maintainer to add `ai: fix-approved`.
|
||||||
other bugs 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.
|
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
|
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.
|
pull request, and posts the root-cause report and pull-request URL.
|
||||||
|
|||||||
5
.github/scripts/validate_ai_patch.sh
vendored
5
.github/scripts/validate_ai_patch.sh
vendored
@@ -84,6 +84,11 @@ for file in "${changed_files[@]}"; do
|
|||||||
echo "Creating a new top-level directory is not permitted: $top" >&2
|
echo "Creating a new top-level directory is not permitted: $top" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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
|
fi
|
||||||
|
|
||||||
if [[ "$request_category" == "improvement" && -n "$expected_addon" && "$file" != "$expected_addon/"* ]]; then
|
if [[ "$request_category" == "improvement" && -n "$expected_addon" && "$file" != "$expected_addon/"* ]]; then
|
||||||
|
|||||||
56
.github/workflows/on_issues_ai.yml
vendored
56
.github/workflows/on_issues_ai.yml
vendored
@@ -261,14 +261,22 @@ jobs:
|
|||||||
improvement)
|
improvement)
|
||||||
labels+=("enhancement")
|
labels+=("enhancement")
|
||||||
if [[ "$EXISTING_ADDON" == true ]]; then
|
if [[ "$EXISTING_ADDON" == true ]]; then
|
||||||
labels+=("ai: fix-proposed" "ai: fixing")
|
labels+=("ai: fix-proposed")
|
||||||
body="**Assessment:** ${summary}
|
body="**Assessment:** ${summary}
|
||||||
|
|
||||||
**Estimated risk:** ${risk}
|
**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
|
else
|
||||||
labels+=("ai: maintainer-review")
|
labels+=("ai: maintainer-review")
|
||||||
body="${response}
|
body="${response}
|
||||||
@@ -319,18 +327,16 @@ jobs:
|
|||||||
needs.triage.outputs.category == 'improvement' &&
|
needs.triage.outputs.category == 'improvement' &&
|
||||||
needs.triage.outputs.existing_addon == 'true'
|
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 == '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 == 'opened' || github.event.action == 'reopened') &&
|
|
||||||
github.event.issue.user.login == github.repository_owner
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
needs: [detect_submitter, triage]
|
needs: [detect_submitter, triage]
|
||||||
@@ -395,7 +401,7 @@ jobs:
|
|||||||
- name: Run Codex
|
- name: Run Codex
|
||||||
id: codex
|
id: codex
|
||||||
if: steps.prepare.outputs.existing_pr == ''
|
if: steps.prepare.outputs.existing_pr == ''
|
||||||
uses: openai/codex-action@v1
|
uses: openai/codex-action@52fe01ec70a42f454c9d2ebd47598f9fd6893d56 # v1
|
||||||
with:
|
with:
|
||||||
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
|
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
|
||||||
prompt-file: codex-prompt.md
|
prompt-file: codex-prompt.md
|
||||||
@@ -652,3 +658,23 @@ jobs:
|
|||||||
gh issue edit "$ISSUE_NUMBER" --repo "$REPO" \
|
gh issue edit "$ISSUE_NUMBER" --repo "$REPO" \
|
||||||
--add-label "ai: pr-created"
|
--add-label "ai: pr-created"
|
||||||
gh issue comment "$ISSUE_NUMBER" --repo "$REPO" --body "$body"
|
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})."
|
||||||
|
|||||||
Reference in New Issue
Block a user