Copilot review of QuantEcon/lecture-python.myst#979 (the intermediate zh-cn sync wiring) found two hardening gaps in the source-sync workflow — and since #979 is byte-identical to the deployed template, both are fleet-wide. Same rollout pattern as #130 (same-repo head-branch guard): a Copilot catch on one PR that belongs in the template.
1. Unauthenticated \translate-resync. The template's job condition only checks contains(github.event.comment.body, '\translate-resync') on issue_comment: created. Any GitHub user commenting on any issue (not even a PR) fires a secrets-bearing run — Anthropic spend plus a PAT-authenticated job — at will. Fix applied on myst#979 (QuantEcon/lecture-python.myst@8abdb57): require github.event.issue.pull_request and contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association).
2. No permissions block. The action authenticates via its github-token input (the PAT), so the ambient GITHUB_TOKEN is unused beyond checkout — permissions: contents: read at job level is sufficient and shrinks the blast radius. Also applied in the same commit.
Scope: the canonical template in the docs (quickstart / connect-existing tutorial, source-sync side) plus the deployed instances — lecture-python-intro/sync-translations-zh-cn.yml, lecture-python-programming/sync-translations-{zh-cn,fa,fr}.yml, and any future edition wiring. myst#979 carries the fixed shape already; the others should adopt it once the template updates.
One design question worth settling while editing the template: whether author_association gating should also allow CONTRIBUTOR, given RA reviewers who may legitimately re-trigger syncs — the conservative OWNER/MEMBER/COLLABORATOR set is what shipped on myst#979.
Copilot review of QuantEcon/lecture-python.myst#979 (the intermediate zh-cn sync wiring) found two hardening gaps in the source-sync workflow — and since #979 is byte-identical to the deployed template, both are fleet-wide. Same rollout pattern as #130 (same-repo head-branch guard): a Copilot catch on one PR that belongs in the template.
1. Unauthenticated
\translate-resync. The template's job condition only checkscontains(github.event.comment.body, '\translate-resync')onissue_comment: created. Any GitHub user commenting on any issue (not even a PR) fires a secrets-bearing run — Anthropic spend plus a PAT-authenticated job — at will. Fix applied on myst#979 (QuantEcon/lecture-python.myst@8abdb57): requiregithub.event.issue.pull_requestandcontains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association).2. No
permissionsblock. The action authenticates via itsgithub-tokeninput (the PAT), so the ambientGITHUB_TOKENis unused beyond checkout —permissions: contents: readat job level is sufficient and shrinks the blast radius. Also applied in the same commit.Scope: the canonical template in the docs (quickstart / connect-existing tutorial, source-sync side) plus the deployed instances —
lecture-python-intro/sync-translations-zh-cn.yml,lecture-python-programming/sync-translations-{zh-cn,fa,fr}.yml, and any future edition wiring. myst#979 carries the fixed shape already; the others should adopt it once the template updates.One design question worth settling while editing the template: whether
author_associationgating should also allowCONTRIBUTOR, given RA reviewers who may legitimately re-trigger syncs — the conservative OWNER/MEMBER/COLLABORATOR set is what shipped on myst#979.