Files
hassio-addons/.github/prompts
Alexandre 455853cd43 fix(ci): revive AI issue triage — permission gate and catch-up dispatch (#2947)
* fix(ci): revive AI issue triage — permission gate and catch-up dispatch

Tier 1 has been failing on every issue since it went live, while every run
reported success. Two independent causes, both masked:

1. claude-code-action treats `issues` / `issue_comment` as entity contexts
   and runs checkWritePermissions() against github.actor — the outside
   reporter, who never has write. Every Classify step died with "Actor does
   not have write permissions"; continue-on-error painted the job green, and
   Apply verdict found no verdict.json and exited 0. No issue ever got the
   `ai-triage` label, so the tier-2 sweep collected an empty batch nightly
   and there were no automatic fixes either.

   Fixed with `allowed_non_write_users: "*"`, which is the input this case
   exists for. It only takes effect alongside the `github_token` already
   passed. `schedule` / `workflow_dispatch` are automation contexts and skip
   the gate, which is why tiers 2 and 3 were unaffected.

2. The catch-up job dispatched with AI_PR_TOKEN, a fine-grained PAT with no
   actions scope: every dispatch returned 403 and `|| echo :⚠️:`
   swallowed it. Switched to GITHUB_TOKEN with a job-level actions:write —
   workflow_dispatch is exempt from the no-recursion rule, so no PAT is
   needed at all.

Both failures now fail the run instead of reporting success, which is the
part that stops this recurring.

Harden the model's output path, as the action's docs require when the
permission gate is bypassed: drop Bash and GH_TOKEN from the Classify step
(the context script already ran the duplicate search), validate the verdict
enum, cap the comment at 4000 chars, defuse @mentions in it, and accept only
`bug`/`enhancement` as model-supplied labels — the repo also carries
automerge, Priority, codex and wontfix, which a crafted issue body must not
be able to reach.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(ci): require the verdict document to be a JSON object

`jq -e .` accepts any truthy JSON, so a verdict of `[1,2]` or `"hi"` passed
the guard and then died on `.verdict` with "Cannot index array with string".
Under set -e that killed the step before the ai:needs-info restore, stranding
the issue so no later reporter reply could re-trigger classification.

Reproduced at exit 5 on an issue_comment event before the fix; the same case
now takes the restore path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(ci): drop the Write tool from triage, deliver the verdict via json-schema

Codex review raised a real escalation path. `allowed_non_write_users: "*"`
deliberately admits untrusted reporters, and the model reads their issue body.
It also had a Write tool, so an injected instruction could write a script to
disk and append BASH_ENV=<that script> to the runner's $GITHUB_ENV file command
— discoverable under $RUNNER_TEMP with Glob. The runner applies $GITHUB_ENV
between steps, so the very next bash step (Apply verdict, holding an
issues:write GH_TOKEN) would source it before any validation ran.

Removing Write closes the chain at its source rather than patching a link:
the verdict now comes back through the action's --json-schema structured
output, so the model needs no filesystem write at all and is left with
Read/Glob/Grep. The schema also enforces the verdict and confidence enums and
the two-label cap at the action layer; the shell-side validation stays as
defence in depth.

Apply verdict materialises the structured output through env, never inline
interpolation. issue-classify.md updated to match. All existing behaviour
re-tested through the new path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 11:55:06 +02:00
..