fix(labels): defer fork-head writes to sweep

This commit is contained in:
codex-bot-andresmgsl 2026-08-24 23:57:07 +00:00
parent 311ef304fc
commit ffbc1afc3d

View file

@ -2,12 +2,14 @@ name: labels
# Reusable half of the labels automation. Triggers and permissions live in
# the caller; docs/CONSUMERS.md carries the complete caller stub.
#
# The caller uses pull_request_target, not pull_request: every PR in this
# family arrives from a fork, where pull_request runs with a READ-ONLY token
# and cannot label anything. _target is safe in this workflow because no PR
# code is ever checked out or executed — scope reads changed paths and the
# path mapping via the API and checks out only the ceremony implementation.
# Keep it that way.
# The caller uses pull_request_target, not pull_request, so same-repository PRs
# keep the base repository's write token without running PR code. On this
# Forgejo, unlike GitHub, fork-headed _target runs still receive a read-only
# token. Those runs therefore attempt no writes and leave labeling to the
# scheduled sweep; the explicit fork_head job below records that disposition
# as a successful check. Both write paths execute only for same-repository
# heads. Scope reads changed paths and the path mapping through the API and
# checks out only the ceremony implementation. Keep it that way (#241).
#
# The reconcile sweep lived here until #209. Riding the PR-triggered run
# meant every displacement in the sweep's shared concurrency queue recorded
@ -21,8 +23,11 @@ name: labels
# sweep now lives in labels-sweep.yml behind its own caller, and the
# trigger job below is its wake: it fires on every event this caller
# subscribes — the exact surface that used to run reconcile directly — so
# the wake latency (#137) is unchanged, while a displaced sweep cancels on
# the Actions tab, attached to no PR. PR checks show scope + trigger only.
# same-repository wake latency (#137) remains seconds-scale, while a displaced
# sweep cancels on the Actions tab, attached to no PR. Fork-headed runs cannot
# dispatch with their read-only token, so their labels arrive on the scheduled
# sweep cadence. PR checks show scope + trigger for same-repository heads, or
# fork_head for fork heads.
#
# This cannot loop: the trigger's dispatch and the reconciler's label
# writes both use GITHUB_TOKEN. GitHub does not create workflow runs from
@ -60,6 +65,7 @@ jobs:
# scope run is clobbered.
if: >-
github.event_name == 'pull_request_target' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.action != 'labeled' &&
github.event.action != 'unlabeled' &&
github.event.action != 'review_requested' &&
@ -106,15 +112,10 @@ jobs:
CONFIG_REF: ${{ github.sha }}
trigger:
# The sweep's wake (#209). No `if:`: reconcile carried none, so the
# trigger keeps the whole event surface the caller subscribes —
# workflow_dispatch of the labels caller itself included. That cannot
# double-fire bootstrap: this dispatch always carries bootstrap=no, so
# a dispatched labels caller yields one plain sweep, and the taxonomy
# bootstrap fires solely on a manual dispatch of the sweep caller
# (whose input defaults to "yes"). Excluding workflow_dispatch here
# would instead make a dispatched labels caller do nothing at all —
# a silent no-op run is worse than a redundant sweep.
# The sweep's instant wake (#209) keeps the whole non-PR event surface and
# same-repository PRs. Fork-headed PRs are excluded because this Forgejo
# gives their pull_request_target run a read-only token (#241); fork_head
# records the successful deferral to the scheduled sweep instead.
#
# LOUD on failure — never `|| true`: a red trigger is the
# misconfiguration alarm. A consumer that bumps the pin without adding
@ -122,6 +123,9 @@ jobs:
# `bootstrap` input (unexpected input), or without `actions: write`
# on this caller (permission denied) fails HERE, visibly on the PR,
# instead of silently never sweeping again.
if: >-
github.event_name != 'pull_request_target' ||
github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- name: dispatch the sweep
@ -199,3 +203,13 @@ jobs:
exit 1
fi
echo "labels: sweep dispatched — $SWEEP_WORKFLOW on $branch (bootstrap=no)"
fork_head:
if: >-
github.event_name == 'pull_request_target' &&
github.event.pull_request.head.repo.full_name != github.repository
runs-on: ubuntu-latest
steps:
- name: explain deferred fork labels
run: >-
echo "labels: fork head has a read-only token; writes deferred to the scheduled sweep cadence"