22# SPDX-FileCopyrightText: 2025 The Linux Foundation
33# SPDX-License-Identifier: Apache-2.0
44
5+ # Pull request autolabeler (organisation-wide).
6+ #
7+ # Thin caller for the reusable lane in lfreleng-actions/generic-workflows.
8+ # This file is the canonical copy enforced organisation-wide via the
9+ # mandatory-workflows ruleset, so labelling runs on every targeted
10+ # repository without being copied into each one (it also labels pull
11+ # requests raised against this repository).
12+ #
13+ # The labels matter beyond the pull request view: Release Drafter reads
14+ # them to sort entries into release-note categories and to resolve the
15+ # next version, because each category in .github/release-drafter.yml
16+ # carries its own semver-increment.
17+ #
18+ # The routing between the two triggers below lives in the reusable, not
19+ # here. See docs/autolabeler.md in generic-workflows.
520name : ' Auto Label 🏷️'
621
722# yamllint disable-line rule:truthy
823on :
9- # pull_request is required for autolabeler
10- pull_request :
11- types :
12- - opened
13- - synchronize
14- - reopened
15- # pull_request_target is required for autolabeler on PRs from forks.
24+ # pull_request covers pull requests raised from a branch of the
25+ # target repository.
1626 #
17- # This use of pull_request_target is safe and does NOT need
18- # manual-approval gating because:
27+ # 'edited' is load-bearing. Every autolabeler rule in
28+ # .github/release-drafter.yml matches on the pull request TITLE, so a
29+ # title corrected after opening needs a fresh run to earn its label.
30+ # Without it, the common sequence of opening without a Conventional
31+ # Commits prefix, failing the semantic pull request check, then fixing
32+ # the title, leaves the pull request unlabelled for good: it lands in
33+ # no release-note category and contributes no version increment.
34+ # 'synchronize' does not cover this, firing on a push rather than on a
35+ # metadata edit.
36+ pull_request :
37+ types : [opened, synchronize, reopened, edited]
38+ # pull_request_target covers pull requests raised from another
39+ # repository, which pull_request cannot label because GitHub hands it
40+ # a token without write access.
1941 #
20- # 1. The workflow performs no checkout of PR code
21- # (no actions/checkout step), so no PR-provided source
22- # ever runs.
23- # 2. The workflow body is loaded from the base branch
24- # (pull_request_target semantics), not from the PR head.
25- # 3. Every step is pinned to a full commit SHA and runs
26- # only trusted, pinned action code, never PR-provided
27- # source. Each is a well-scoped consumer:
28- # - `lfreleng-actions/harden-runner-block-action`
29- # fetches one allow-list file over HTTPS, sanitises
30- # it, and publishes it as $CONNECTION_ALLOW_LIST.
31- # It reads no PR content.
32- # - `step-security/harden-runner` installs the egress
33- # block filter from $CONNECTION_ALLOW_LIST. Pure
34- # runner-hardening; reads no PR content.
35- # - `release-drafter/release-drafter/autolabeler`
36- # makes only GitHub API calls; it reads PR metadata
37- # (e.g. title and labels) to apply labels but never
38- # checks out or runs PR head source.
39- # 4. Permissions are scoped to the minimum needed:
40- # pull-requests: write and contents: read. No
41- # repository secrets are passed to the job beyond the
42- # default GITHUB_TOKEN, which the job receives with the
43- # permissions scope above and nothing more.
44- # 5. The runner is hardened with an egress block applied
45- # before the autolabeler step runs.
42+ # This use of pull_request_target is safe and needs no manual-approval
43+ # gating, because the conditions zizmor's dangerous-triggers audit
44+ # warns about (pull request head code running with elevated
45+ # privileges) cannot arise:
4646 #
47- # See the SECURITY block on the autolabel job below for the
48- # full rationale. The zizmor `dangerous-triggers` audit is
49- # silenced here because the conditions it warns about (PR
50- # head code running with elevated privileges) cannot occur in
51- # this workflow.
47+ # 1. The lane has NO checkout step, so head source never reaches the
48+ # runner, let alone runs.
49+ # 2. pull_request_target loads the workflow body from the base
50+ # branch, and the pinned 'uses:' ref below fixes the content of
51+ # the reusable it calls.
52+ # 3. Every step in the lane pins a commit SHA and runs trusted code:
53+ # harden-runner-block-action fetches one allow-list file,
54+ # harden-runner installs the egress filter, and the autolabeler
55+ # makes GitHub API calls against pull request metadata. None of
56+ # the three reads or runs head source.
57+ # 4. Permissions stop at the two grants declared on the job below,
58+ # and the egress block lands before the autolabeler step runs.
5259 pull_request_target : # zizmor: ignore[dangerous-triggers]
53- types :
54- - opened
55- - synchronize
56- - reopened
60+ types : [opened, synchronize, reopened, edited]
5761
5862permissions : {}
5963
@@ -71,53 +75,33 @@ concurrency:
7175 # serialise every open pull request into one group.
7276 # yamllint disable-line rule:line-length
7377 group : ' org-autolabeler-${{ github.event_name }}-pr-${{ github.event.pull_request.number }}'
78+ # Cancelling is safe here, unlike the semantic pull request check.
79+ # Labelling is idempotent, and this workflow publishes no check run
80+ # that a required status check names, so a superseded run leaves
81+ # nothing behind for the merge box to report.
7482 cancel-in-progress : true
7583
7684jobs :
7785 autolabel :
7886 name : ' Label PR'
79- # Run on pull_request_target for forks, or pull_request for same-repo PRs
80- # This prevents duplicate runs for same-repo PRs
81- # yamllint disable rule:line-length
82- if : >
83- (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork) ||
84- (github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork)
85- # yamllint enable rule:line-length
86- # SECURITY: pull_request_target with write permissions is safe here because:
87- # 1. This workflow does NOT checkout any code from the PR
88- # 2. The workflow code itself runs from the base branch (not the fork)
89- # 3. release-drafter runs only trusted, SHA-pinned action code and
90- # makes GitHub API calls; it reads PR metadata but never runs
91- # PR head source
92- # 4. pull_request_target is needed ONLY for autolabeling fork PRs
87+ # No 'if:' here by design. The reusable carries the routing
88+ # condition, which compares the head repository against the base
89+ # repository so that each pull request takes exactly one of the two
90+ # triggers. Repeating it here would duplicate logic that is easy to
91+ # get wrong, and the version this file used to carry keyed on
92+ # head.repo.fork, which reports whether the head repository is
93+ # itself a fork rather than whether the pull request crosses
94+ # repositories.
95+ # yamllint disable-line rule:line-length
96+ uses : lfreleng-actions/generic-workflows/.github/workflows/autolabeler.yaml@41059e423606179bc80dedcdd1a50331d059788e # v0.2.1
9397 permissions :
94- pull-requests : write # Autolabeler applies labels to pull requests
95- # read is sufficient; autolabeler does not create releases
96- contents : read
97- runs-on : ' ubuntu-latest'
98- timeout-minutes : 3
99- steps :
100- # Load the egress allow-list out-of-band from
101- # lfreleng-actions/.github and publish it as
102- # $CONNECTION_ALLOW_LIST for the harden-runner step below
103- # to consume in 'block' mode. Loading out-of-band means
104- # the workflow no longer depends on any org-level GitHub
105- # variable being exposed at runtime (org variables are
106- # unreachable from workflows triggered by PRs raised from
107- # forks, which previously forced a fallback to audit mode).
108- # yamllint disable-line rule:line-length
109- - uses : lfreleng-actions/harden-runner-block-action@6db537b3e6d060c3287c5a3ce2c28b55b0af330d # v0.2.1
110- with :
111- config : ' @18d9c4446bea555d0783e850f6d295f844fe8f67' # v0.1.1
112-
113- # Harden the runner with the just-loaded allow-list.
114- - name : ' Harden runner (block)'
115- # yamllint disable-line rule:line-length
116- uses : step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
117- with :
118- egress-policy : ' block'
119- allowed-endpoints : >
120- ${{ env.CONNECTION_ALLOW_LIST }}
121-
122- # yamllint disable-line rule:line-length
123- - uses : release-drafter/release-drafter/autolabeler@34d80673e067bdc0c24568d3af899c216adcfaa9 # v7.7.0
98+ contents : read # Lane reads the release-drafter config from the repo
99+ pull-requests : write # Lane applies labels to the pull request
100+ # No 'with:' block: the lane's defaults are this organisation's
101+ # policy. config_name defaults to 'release-drafter.yml', which
102+ # release-drafter resolves from the target repository and falls back
103+ # to this one when the target has no copy.
104+ #
105+ # No 'secrets:' block either. The lane's optional 'token' secret
106+ # exists for callers needing labels under a different identity;
107+ # unset, it uses the job's GITHUB_TOKEN, which is what ran before.
0 commit comments