Skip to content

Commit 530b572

Browse files
committed
docs: move fork PR docs to docs/fork-pr-comments.md for stable linking
Code now links to docs/fork-pr-comments.md (a fixed file path) instead of README section anchors (#fork-pr-comments). This prevents link rot when the README gets restructured. README keeps a brief summary with a link to the dedicated docs file.
1 parent 21bb90a commit 530b572

4 files changed

Lines changed: 174 additions & 153 deletions

File tree

README.md

Lines changed: 6 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ A GitHub Action for checking commit message formatting, branch naming, committer
2626
* [Optional Inputs](#optional-inputs)
2727
* [GitHub Action Job Summary](#github-action-job-summary)
2828
* [GitHub Pull Request Comments](#github-pull-request-comments)
29-
* [Fork PR Comments](#fork-pr-comments)
29+
* [Fork PR Comments](docs/fork-pr-comments.md)
3030
* [Badging Your Repository](#badging-your-repository)
3131
* [Versioning](#versioning)
3232

@@ -125,8 +125,8 @@ jobs:
125125
> `pr-comments` is an experimental feature. By default, it's disabled.
126126
>
127127
> PR comments are skipped for pull requests from forked repositories. See
128-
> [Fork PR Comments](#fork-pr-comments) for details on how to enable this feature
129-
> for fork contributions.
128+
> [docs/fork-pr-comments.md](docs/fork-pr-comments.md) for details on how to enable
129+
> this feature for fork contributions.
130130
>
131131
> Note: write-access to pull-requests requires the `pull-requests: write` permission.
132132
> See [usage example](#usage).
@@ -168,154 +168,9 @@ By default, commit-check-action handles this gracefully:
168168
- The commit checks themselves **still run normally**
169169

170170
> **For most projects, this is sufficient** — contributors can see check results in the
171-
> action Job Summary. But if you *must* have PR comments on fork contributions, there
172-
> are two recommended approaches.
173-
174-
---
175-
176-
### Option 1: Two-workflow pattern (recommended)
177-
178-
This is the **official GitHub-recommended best practice** for writing PR comments from
179-
fork PRs. It uses the [`workflow_run`](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run)
180-
event with **no security risks**.
181-
182-
> 📁 Ready-to-use files: [`examples/commit-check-workflow-a.yml`](examples/commit-check-workflow-a.yml)
183-
> and [`examples/commit-check-workflow-b.yml`](examples/commit-check-workflow-b.yml)
184-
185-
**How it works:**
186-
187-
```
188-
pull_request workflow_run
189-
│ │
190-
▼ ▼
191-
┌──────────────┐ ┌──────────────────┐
192-
│ Workflow A │ │ Workflow B │
193-
│ (checks) │────►│ (comment writer) │
194-
│ │ │ │
195-
│ Token: READ │ │ Token: WRITE │
196-
│ Saves result │ │ Reads artifact │
197-
│ as artifact │ │ Posts PR comment │
198-
└──────────────┘ └──────────────────┘
199-
```
200-
201-
**Workflow A** — `.github/workflows/commit-check.yml` (triggered by `pull_request`):
202-
203-
```yaml
204-
name: Commit Check
205-
206-
on:
207-
pull_request:
208-
branches: ["main"]
209-
210-
jobs:
211-
check:
212-
runs-on: ubuntu-latest
213-
steps:
214-
- uses: actions/checkout@v5
215-
with:
216-
fetch-depth: 0
217-
- uses: commit-check/commit-check-action@v2
218-
with:
219-
message: true
220-
branch: true
221-
pr-comments: false # comments handled by Workflow B
222-
job-summary: true
223-
- uses: actions/upload-artifact@v4
224-
with:
225-
name: commit-check-result-${{ github.event.number }}
226-
path: result.txt # saved for Workflow B
227-
```
228-
229-
> 📄 Full file: [`examples/commit-check-workflow-a.yml`](examples/commit-check-workflow-a.yml)
230-
231-
**Workflow B**`.github/workflows/commit-check-comment.yml` (triggered by `workflow_run`):
232-
233-
```yaml
234-
name: Commit Check Comment
235-
236-
on:
237-
workflow_run:
238-
workflows: ["Commit Check"] # must match Workflow A's name exactly
239-
types: [completed]
240-
241-
jobs:
242-
comment:
243-
runs-on: ubuntu-latest
244-
permissions:
245-
pull-requests: write
246-
actions: read # needed to download artifacts
247-
steps:
248-
- uses: actions/download-artifact@v4
249-
with:
250-
name: commit-check-result-${{ github.event.workflow_run.pull_requests[0].number }}
251-
run-id: ${{ github.event.workflow_run.id }}
252-
github-token: ${{ github.token }}
253-
- name: Read result and post PR comment
254-
uses: actions/github-script@v7
255-
with:
256-
script: |
257-
// See examples/commit-check-workflow-b.yml for full script
258-
const fs = require('fs');
259-
const prNumber = ${{ github.event.workflow_run.pull_requests[0].number }};
260-
const resultText = fs.readFileSync('result.txt', 'utf8').trim();
261-
const body = resultText
262-
? '# Commit-Check ❌\n```\n' + resultText + '\n```'
263-
: '# Commit-Check ✔️';
264-
// Creates or updates the matching PR comment
265-
```
266-
267-
> 📄 Full file: [`examples/commit-check-workflow-b.yml`](examples/commit-check-workflow-b.yml)
268-
269-
> **Key security benefits:**
270-
> - Workflow B runs in the **base repository's context**, so `GITHUB_TOKEN` has full write
271-
> permissions (you explicitly grant `pull-requests: write`)
272-
> - Workflow B **does not checkout the PR code**, so untrusted fork code never runs
273-
> with elevated permissions
274-
> - The artifact only contains `result.txt` — no code or secrets
275-
276-
---
277-
278-
### Option 2: pull_request_target (advanced, use with caution)
279-
280-
If you understand the security implications, you can use
281-
[`pull_request_target`](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target)
282-
which runs in the base repository's context with **write token access**.
283-
284-
> **⚠️ Security warning:** Never check out (`actions/checkout`) the PR's HEAD commit
285-
> when using `pull_request_target`. Always check out the base branch or use the
286-
> default merge commit. Otherwise, fork code could exfiltrate your repository's secrets.
287-
288-
```yaml
289-
name: Commit Check
290-
291-
on:
292-
pull_request_target:
293-
branches: ["main"]
294-
295-
jobs:
296-
commit-check:
297-
runs-on: ubuntu-latest
298-
permissions:
299-
contents: read
300-
pull-requests: write
301-
steps:
302-
# SAFE: checkout the merge commit, NOT the PR head
303-
- uses: actions/checkout@v5
304-
with:
305-
fetch-depth: 0
306-
- uses: commit-check/commit-check-action@v2
307-
with:
308-
message: true
309-
branch: true
310-
pr-comments: true
311-
```
312-
313-
> ✅ With `pull_request_target`, `pr-comments: true` **does work** on fork PRs —
314-
> the token has the workflow's configured permissions regardless of whether the PR
315-
> is from a fork.
316-
>
317-
> **When to use this:** Only if the two-workflow pattern is too complex for your setup
318-
> and you have thoroughly reviewed the security implications.
171+
> action Job Summary. But if you *must* have PR comments on fork contributions, see
172+
> the **[Fork PR Comments](docs/fork-pr-comments.md)** documentation for
173+
> two recommended approaches with ready-to-use workflow examples.
319174

320175
## Badging Your Repository
321176

docs/fork-pr-comments.md

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# Fork PR Comments
2+
3+
When a pull request is opened from a **forked repository**, the `GITHUB_TOKEN` used by the
4+
`pull_request` event has **read-only** permissions by design (GitHub security policy).
5+
This means `pr-comments: true` cannot write a comment back to the PR.
6+
7+
By default, commit-check-action handles this gracefully:
8+
9+
- PR comment writing is **skipped** with a `::warning::` message in the logs
10+
- A **notice is added to the Job Summary** explaining why and how to fix it
11+
- The commit checks themselves **still run normally**
12+
13+
> **For most projects, this is sufficient** — contributors can see check results in the
14+
> action Job Summary. But if you *must* have PR comments on fork contributions, there
15+
> are two recommended approaches.
16+
17+
---
18+
19+
## Option 1: Two-workflow pattern (recommended)
20+
21+
This is the **official GitHub-recommended best practice** for writing PR comments from
22+
fork PRs. It uses the [`workflow_run`](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run)
23+
event with **no security risks**.
24+
25+
> 📁 Ready-to-use files: [`examples/commit-check-workflow-a.yml`](../examples/commit-check-workflow-a.yml)
26+
> and [`examples/commit-check-workflow-b.yml`](../examples/commit-check-workflow-b.yml)
27+
28+
**How it works:**
29+
30+
```
31+
pull_request workflow_run
32+
│ │
33+
▼ ▼
34+
┌──────────────┐ ┌──────────────────┐
35+
│ Workflow A │ │ Workflow B │
36+
│ (checks) │────►│ (comment writer) │
37+
│ │ │ │
38+
│ Token: READ │ │ Token: WRITE │
39+
│ Saves result │ │ Reads artifact │
40+
│ as artifact │ │ Posts PR comment │
41+
└──────────────┘ └──────────────────┘
42+
```
43+
44+
### Workflow A
45+
46+
`.github/workflows/commit-check.yml` (triggered by `pull_request`):
47+
48+
```yaml
49+
name: Commit Check
50+
51+
on:
52+
pull_request:
53+
branches: ["main"]
54+
55+
jobs:
56+
check:
57+
runs-on: ubuntu-latest
58+
steps:
59+
- uses: actions/checkout@v5
60+
with:
61+
fetch-depth: 0
62+
- uses: commit-check/commit-check-action@v2
63+
with:
64+
message: true
65+
branch: true
66+
pr-comments: false # comments handled by Workflow B
67+
job-summary: true
68+
- uses: actions/upload-artifact@v4
69+
with:
70+
name: commit-check-result-${{ github.event.number }}
71+
path: result.txt # saved for Workflow B
72+
```
73+
74+
> 📄 Full file: [`examples/commit-check-workflow-a.yml`](../examples/commit-check-workflow-a.yml)
75+
76+
### Workflow B
77+
78+
`.github/workflows/commit-check-comment.yml` (triggered by `workflow_run`):
79+
80+
```yaml
81+
name: Commit Check Comment
82+
83+
on:
84+
workflow_run:
85+
workflows: ["Commit Check"] # must match Workflow A's name exactly
86+
types: [completed]
87+
88+
jobs:
89+
comment:
90+
runs-on: ubuntu-latest
91+
permissions:
92+
pull-requests: write
93+
actions: read # needed to download artifacts
94+
steps:
95+
- uses: actions/download-artifact@v4
96+
with:
97+
name: commit-check-result-${{ github.event.workflow_run.pull_requests[0].number }}
98+
run-id: ${{ github.event.workflow_run.id }}
99+
github-token: ${{ github.token }}
100+
- name: Read result and post PR comment
101+
uses: actions/github-script@v7
102+
with:
103+
script: |
104+
// See examples/commit-check-workflow-b.yml for full script
105+
const fs = require('fs');
106+
const prNumber = ${{ github.event.workflow_run.pull_requests[0].number }};
107+
const resultText = fs.readFileSync('result.txt', 'utf8').trim();
108+
const body = resultText
109+
? '# Commit-Check ❌\n```\n' + resultText + '\n```'
110+
: '# Commit-Check ✔️';
111+
// Creates or updates the matching PR comment
112+
```
113+
114+
> 📄 Full file: [`examples/commit-check-workflow-b.yml`](../examples/commit-check-workflow-b.yml)
115+
116+
### Key security benefits
117+
118+
- Workflow B runs in the **base repository's context**, so `GITHUB_TOKEN` has full write
119+
permissions (you explicitly grant `pull-requests: write`)
120+
- Workflow B **does not checkout the PR code**, so untrusted fork code never runs
121+
with elevated permissions
122+
- The artifact only contains `result.txt` — no code or secrets
123+
124+
---
125+
126+
## Option 2: pull_request_target (advanced, use with caution)
127+
128+
If you understand the security implications, you can use
129+
[`pull_request_target`](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target)
130+
which runs in the base repository's context with **write token access**.
131+
132+
> **⚠️ Security warning:** Never check out (`actions/checkout`) the PR's HEAD commit
133+
> when using `pull_request_target`. Always check out the base branch or use the
134+
> default merge commit. Otherwise, fork code could exfiltrate your repository's secrets.
135+
136+
```yaml
137+
name: Commit Check
138+
139+
on:
140+
pull_request_target:
141+
branches: ["main"]
142+
143+
jobs:
144+
commit-check:
145+
runs-on: ubuntu-latest
146+
permissions:
147+
contents: read
148+
pull-requests: write
149+
steps:
150+
# SAFE: checkout the merge commit, NOT the PR head
151+
- uses: actions/checkout@v5
152+
with:
153+
fetch-depth: 0
154+
- uses: commit-check/commit-check-action@v2
155+
with:
156+
message: true
157+
branch: true
158+
pr-comments: true
159+
```
160+
161+
> ✅ With `pull_request_target`, `pr-comments: true` **does work** on fork PRs —
162+
> the token has the workflow's configured permissions regardless of whether the PR
163+
> is from a fork.
164+
>
165+
> **When to use this:** Only if the two-workflow pattern is too complex for your setup
166+
> and you have thoroughly reviewed the security implications.

main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ def add_pr_comments() -> int:
315315
"Skipping PR comment: pull requests from forked repositories "
316316
"cannot write comments via the pull_request event (GITHUB_TOKEN is "
317317
"read-only for forks). "
318-
"See https://github.com/commit-check/commit-check-action#fork-pr-comments "
318+
"See https://github.com/commit-check/commit-check-action/blob/main/docs/fork-pr-comments.md "
319319
"for how to enable PR comments on fork PRs."
320320
)
321321
print(f"::warning::{msg}")
@@ -329,7 +329,7 @@ def add_pr_comments() -> int:
329329
"read-only permissions.\n\n"
330330
"> **\U0001f4a1 Tip:** To enable PR comments on fork PRs, see "
331331
"[Enabling PR Comments on Fork Pull Requests]"
332-
"(https://github.com/commit-check/commit-check-action#fork-pr-comments).\n"
332+
"(https://github.com/commit-check/commit-check-action/blob/main/docs/fork-pr-comments.md).\n"
333333
)
334334
return 0
335335

result.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)