ci: widen the publish-attempt path list (#1560)

#1524 tried to publish by adding
`data/servers/io.decisionrules/server.json`. The detector ran fine and
logged:

```
Non-publish file changed: data/servers/io.decisionrules/server.json
PR #1524 match=false
```

The path list only knew `servers/**` at the repo root and exactly
`data/seed.json`. Putting the file under `data/servers/` is a natural
guess given `data/seed.json` exists, and it fell straight through.

Adds `data/servers/**` plus root-level `server.json` / `servers.json`.
`find` confirms nothing legitimate lives at any of those paths today.

The list stays explicit rather than becoming a broad `**/server.json`
glob. The classifier only flags a PR when *every* changed file matches,
which makes widening asymmetric: too narrow silently misses spam, too
broad auto-closes a legitimate single-file PR.

Both copies of the list (stage 1 and stage 2) are updated identically,
with a comment on each pointing at the other.

## Testing

`actionlint` clean. macOS ships bash 3.2, so I extracted the literal `if
[[ ... ]]` condition from each workflow file and ran it under bash 5 in
Docker — testing the shipped text rather than a retyped copy. Both
copies are byte-identical and agree:

```
MATCH data/servers/io.decisionrules/server.json   # PR 1524
MATCH servers/com.aradia/x.json                   # PR 1549
MATCH data/seed.json
MATCH server.json
MATCH servers.json
keep  internal/api/handler.go
keep  internal/servers/service.go
keep  data/servers.md
keep  docs/README.md
```

Also dry-ran the full classifier against all 35 currently-open PRs from
untrusted authors: **0 would be closed**. No legitimate open PR is
affected.

## Known remaining gap (deliberately not fixed here)

The detector does not run at all for authors new to GitHub. This repo's
Actions approval policy is `first_time_contributors_new_to_github`, so
their fork PRs sit in `action_required` until a maintainer approves the
run. That is why #1549 was never flagged.

I'm leaving that alone for now because the numbers don't justify the
fix. Since the automation landed on 2026-07-09 it has had **71 detect
runs: 70 ran, 1 was gated**. It has correctly closed 3 publish attempts
(SAGE, Diagram Generation API, Kairos Signal) and missed 2 — one to the
path bug this PR fixes, one to the gate. So the gate costs roughly one
missed PR every six weeks, and those get closed manually within a day.

The only ways around it are `pull_request_target` (runs untrusted PRs in
a privileged context — one future `actions/checkout` from being a
privilege-escalation hole) or a scheduled sweep (works, but trades the
two-stage design for cron semantics and a ~15 min delay). Neither seems
worth it at that rate. Happy to open a follow-up if you'd rather close
the gap.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Radoslav Dimitrov 2026-08-21 01:43:05 +03:00 • committed by GitHub
commit 5022e04399
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -48,12 +48,24 @@ jobs:
mapfile -t FILES < <(gh api --paginate "repos/$GH_REPO/pulls/$PR_NUMBER/files" --jq '.[].filename')
if [ "${#FILES[@]}" -gt 0 ]; then
# Flag only if the PR touches *exclusively* publish-attempt files
# (servers/** and/or data/seed.json) and nothing else, so that
# legit PRs touching seed data alongside real code are left alone.
# and nothing else, so that legit PRs touching seed data
# alongside real code are left alone.
#
# Keep this list in sync with the copy in stage 2. It stays an
# explicit list rather than a broad `**/server.json` glob:
# because we require *every* file to match, an over-broad
# pattern would auto-close a legitimate single-file PR.
# data/servers/** is here because #1524 put its server.json
# there - a natural guess next to data/seed.json - and slipped
# through the original servers/**-only list.
publish_attempt=0
other=0
for f in "${FILES[@]}"; do
if [[ "$f" == servers/* || "$f" == "data/seed.json" ]]; then
if [[ "$f" == servers/* \
|| "$f" == data/servers/* \
|| "$f" == "data/seed.json" \
|| "$f" == "server.json" \
|| "$f" == "servers.json" ]]; then
publish_attempt=1
else
echo "Non-publish file changed: $f"