-
Notifications
You must be signed in to change notification settings - Fork 9
114 lines (104 loc) · 5.28 KB
/
Copy pathformat-suggest.yaml
File metadata and controls
114 lines (104 loc) · 5.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# Workflow derived from https://github.com/posit-dev/setup-air/tree/main/examples
on:
# We keep `pull_request_target` (rather than `pull_request`) so that this job
# can post review suggestions on pull requests that come from forks, which is
# our main use case. A fork's `pull_request` run only gets a read-only token,
# so it cannot comment; `pull_request_target` runs with the base repository's
# token and can be granted `pull-requests: write`.
#
# SECURITY -- this is a classic "pwn request" surface, so the fork's code is
# treated strictly as *data to be formatted*, never as code to run:
#
# 1. The formatter tooling (the `style` action and the air / clang-format
# binaries) is loaded from the BASE repository, not from the PR checkout.
# This is the critical point. The naive pattern
# - uses: actions/checkout@v6 # ref: fork head
# - uses: ./.github/workflows/style
# resolves `./...style` from the *checked-out fork*, so an attacker only
# has to edit their fork's `style/action.yml` to run arbitrary commands
# with our token and secrets. Here we run the base repo's copy instead
# (checked out into `ci-base/`), so the fork controls only the input
# files, not the code that executes.
# 2. air and clang-format merely parse and re-print source; they do not
# evaluate it. No build / install / test step ever runs the fork's code.
# 3. The PR is checked out with `persist-credentials: false`, so the token
# is not written to disk alongside untrusted files.
# 4. Permissions are reduced to `pull-requests: write` only, and
# `harden-runner` observes (and can block) network egress.
#
# https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/
# https://gh.io/securely-using-pull_request_target
pull_request_target:
name: format-suggest.yaml
# Deny everything by default; the job below opts back into the single scope it
# needs. This caps the blast radius of the elevated `pull_request_target` token.
permissions: {}
jobs:
format-suggest:
name: format-suggest
runs-on: ubuntu-26.04
# Only run this job if changes come from a fork.
# We commit changes directly on the main repository.
if: github.event.pull_request.head.repo.full_name != github.repository
permissions:
# Required to push suggestion comments to the PR
pull-requests: write
steps:
# Defense in depth: block all outbound network traffic except the
# endpoints the formatters legitimately need. Even if a formatter ever
# mishandled attacker-controlled input, it could not exfiltrate the token
# or fetch a second-stage payload.
#
# The GitHub endpoints below were confirmed from a harden-runner `audit`
# run of this workflow (git checkout, setup-air / reviewdog binary
# downloads, reviewdog posting via the API). The apt.llvm.org / Ubuntu
# archive endpoints are only hit when a package ships a `.clang-format`
# file and the `style` action installs clang-format; they are included so
# C++ consumers of this template are not broken, even though a pure-R
# package never contacts them.
#
# If a run is ever blocked, harden-runner reports the denied endpoint in
# the job's "Harden Runner" step summary (and the StepSecurity insights
# for the run) -- add it here and re-run. See the note in the PR for the
# audit -> block workflow.
- name: Harden runner
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2
with:
egress-policy: block
allowed-endpoints: >
github.com:443
api.github.com:443
release-assets.githubusercontent.com:443
objects.githubusercontent.com:443
codeload.github.com:443
apt.llvm.org:443
azure.archive.ubuntu.com:80
# The untrusted PR code, checked out at the workspace root. It is DATA
# only -- nothing below executes it. `allow-unsafe-pr-checkout` is required
# by actions/checkout@v6 for a fork ref under pull_request_target; it is
# safe here specifically because the code that runs comes from `ci-base/`
# (the base repo), never from this checkout. See the security notes above.
- name: Check out PR code (treated as data)
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
persist-credentials: false
allow-unsafe-pr-checkout: true
# The trusted formatter tooling, from the base repository, into a separate
# directory the fork cannot influence.
- name: Check out trusted tooling from base repo
uses: actions/checkout@v6
with:
path: ci-base
persist-credentials: false
# Runs the base repo's `style` action against the PR code at the workspace
# root. Because the action comes from `ci-base/`, the fork controls only
# the files being formatted, not the code that runs.
- name: Format
uses: ./ci-base/.github/workflows/style
- name: Suggest
uses: reviewdog/action-suggester@2558ba17e65a9039e73764a73009fc05fef28a46 # v1
with:
level: error
fail_level: error
tool_name: air-and-clang-format