• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pantsbuild / pants / 26342152999

23 May 2026 07:59PM UTC coverage: 91.165% (-1.6%) from 92.792%
26342152999

push

github

web-flow
Run Linux ARM CI on Depot runners (#23363)

RunsOn is deprecating their v2 stack, and rather than migrate
to v3 we should use the resources kindly donated by Depot.

GitHub also now has Linux ARM runners, should we need them.

87305 of 95766 relevant lines covered (91.16%)

3.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

29.31
/src/python/pants/backend/go/util_rules/cgo_security.py
1
# Copyright 2022 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3
from __future__ import annotations
11✔
4

5
import re
11✔
6
import string
11✔
7
from collections.abc import Iterable, Sequence
11✔
8

9
from pants.util.memo import memoized
11✔
10

11
#
12
# Check compiler and linker arguments in CGo use cases against explicit allow lists.
13
# Adapted from https://github.com/golang/go/blob/master/src/cmd/go/internal/work/security.go.
14
#
15
# Original copyright:
16
#   // Copyright 2018 The Go Authors. All rights reserved.
17
#   // Use of this source code is governed by a BSD-style
18
#   // license that can be found in the LICENSE file.
19

20

21
class CGoFlagSecurityError(ValueError):
11✔
22
    pass
11✔
23

24

25
@memoized
11✔
26
def _valid_compiler_flags() -> tuple[re.Pattern, ...]:
11✔
27
    return (
×
28
        re.compile(r"-D([A-Za-z_][A-Za-z0-9_]*)(=[^@\-]*)?"),
29
        re.compile(r"-U([A-Za-z_][A-Za-z0-9_]*)"),
30
        re.compile(r"-F([^@\-].*)"),
31
        re.compile(r"-I([^@\-].*)"),
32
        re.compile(r"-O"),
33
        re.compile(r"-O([^@\-].*)"),
34
        re.compile(r"-W"),
35
        re.compile(r"-W([^@,]+)"),  # -Wall but not -Wa,-foo.
36
        re.compile(r"-Wa,-mbig-obj"),
37
        re.compile(r"-Wp,-D([A-Za-z_][A-Za-z0-9_]*)(=[^@,\-]*)?"),
38
        re.compile(r"-Wp,-U([A-Za-z_][A-Za-z0-9_]*)"),
39
        re.compile(r"-ansi"),
40
        re.compile(r"-f(no-)?asynchronous-unwind-tables"),
41
        re.compile(r"-f(no-)?blocks"),
42
        re.compile(r"-f(no-)builtin-[a-zA-Z0-9_]*"),
43
        re.compile(r"-f(no-)?common"),
44
        re.compile(r"-f(no-)?constant-cfstrings"),
45
        re.compile(r"-fdiagnostics-show-note-include-stack"),
46
        re.compile(r"-f(no-)?eliminate-unused-debug-types"),
47
        re.compile(r"-f(no-)?exceptions"),
48
        re.compile(r"-f(no-)?fast-math"),
49
        re.compile(r"-f(no-)?inline-functions"),
50
        re.compile(r"-finput-charset=([^@\-].*)"),
51
        re.compile(r"-f(no-)?fat-lto-objects"),
52
        re.compile(r"-f(no-)?keep-inline-dllexport"),
53
        re.compile(r"-f(no-)?lto"),
54
        re.compile(r"-fmacro-backtrace-limit=(.+)"),
55
        re.compile(r"-fmessage-length=(.+)"),
56
        re.compile(r"-f(no-)?modules"),
57
        re.compile(r"-f(no-)?objc-arc"),
58
        re.compile(r"-f(no-)?objc-nonfragile-abi"),
59
        re.compile(r"-f(no-)?objc-legacy-dispatch"),
60
        re.compile(r"-f(no-)?omit-frame-pointer"),
61
        re.compile(r"-f(no-)?openmp(-simd)?"),
62
        re.compile(r"-f(no-)?permissive"),
63
        re.compile(r"-f(no-)?(pic|PIC|pie|PIE)"),
64
        re.compile(r"-f(no-)?plt"),
65
        re.compile(r"-f(no-)?rtti"),
66
        re.compile(r"-f(no-)?split-stack"),
67
        re.compile(r"-f(no-)?stack-(.+)"),
68
        re.compile(r"-f(no-)?strict-aliasing"),
69
        re.compile(r"-f(un)signed-char"),
70
        re.compile(r"-f(no-)?use-linker-plugin"),  # safe if -B is not used; we don't permit -B
71
        re.compile(r"-f(no-)?visibility-inlines-hidden"),
72
        re.compile(r"-fsanitize=(.+)"),
73
        re.compile(r"-ftemplate-depth-(.+)"),
74
        re.compile(r"-fvisibility=(.+)"),
75
        re.compile(r"-g([^@\-].*)?"),
76
        re.compile(r"-m32"),
77
        re.compile(r"-m64"),
78
        re.compile(r"-m(abi|arch|cpu|fpu|tune)=([^@\-].*)"),
79
        re.compile(r"-m(no-)?v?aes"),
80
        re.compile(r"-marm"),
81
        re.compile(r"-m(no-)?avx[0-9a-z]*"),
82
        re.compile(r"-mfloat-abi=([^@\-].*)"),
83
        re.compile(r"-mfpmath=[0-9a-z,+]*"),
84
        re.compile(r"-m(no-)?avx[0-9a-z.]*"),
85
        re.compile(r"-m(no-)?ms-bitfields"),
86
        re.compile(r"-m(no-)?stack-(.+)"),
87
        re.compile(r"-mmacosx-(.+)"),
88
        re.compile(r"-mios-simulator-version-min=(.+)"),
89
        re.compile(r"-miphoneos-version-min=(.+)"),
90
        re.compile(r"-mtvos-simulator-version-min=(.+)"),
91
        re.compile(r"-mtvos-version-min=(.+)"),
92
        re.compile(r"-mwatchos-simulator-version-min=(.+)"),
93
        re.compile(r"-mwatchos-version-min=(.+)"),
94
        re.compile(r"-mnop-fun-dllimport"),
95
        re.compile(r"-m(no-)?sse[0-9.]*"),
96
        re.compile(r"-m(no-)?ssse3"),
97
        re.compile(r"-mthumb(-interwork)?"),
98
        re.compile(r"-mthreads"),
99
        re.compile(r"-mwindows"),
100
        re.compile(r"--param=ssp-buffer-size=[0-9]*"),
101
        re.compile(r"-pedantic(-errors)?"),
102
        re.compile(r"-pipe"),
103
        re.compile(r"-pthread"),
104
        re.compile(r"-?-std=([^@\-].*)"),
105
        re.compile(r"-?-stdlib=([^@\-].*)"),
106
        re.compile(r"--sysroot=([^@\-].*)"),
107
        re.compile(r"-w"),
108
        re.compile(r"-x([^@\-].*)"),
109
        re.compile(r"-v"),
110
    )
111

112

113
_valid_compiler_flags_with_next_arg = (
11✔
114
    "-arch",
115
    "-D",
116
    "-U",
117
    "-I",
118
    "-F",
119
    "-framework",
120
    "-include",
121
    "-isysroot",
122
    "-isystem",
123
    "--sysroot",
124
    "-target",
125
    "-x",
126
)
127

128

129
@memoized
11✔
130
def _valid_linker_flags() -> tuple[re.Pattern, ...]:
11✔
131
    return (
×
132
        re.compile(r"-F([^@\-].*)"),
133
        re.compile(r"-l([^@\-].*)"),
134
        re.compile(r"-L([^@\-].*)"),
135
        re.compile(r"-O"),
136
        re.compile(r"-O([^@\-].*)"),
137
        re.compile(r"-f(no-)?(pic|PIC|pie|PIE)"),
138
        re.compile(r"-f(no-)?openmp(-simd)?"),
139
        re.compile(r"-fsanitize=([^@\-].*)"),
140
        re.compile(r"-flat_namespace"),
141
        re.compile(r"-g([^@\-].*)?"),
142
        re.compile(r"-headerpad_max_install_names"),
143
        re.compile(r"-m(abi|arch|cpu|fpu|tune)=([^@\-].*)"),
144
        re.compile(r"-mfloat-abi=([^@\-].*)"),
145
        re.compile(r"-mmacosx-(.+)"),
146
        re.compile(r"-mios-simulator-version-min=(.+)"),
147
        re.compile(r"-miphoneos-version-min=(.+)"),
148
        re.compile(r"-mthreads"),
149
        re.compile(r"-mwindows"),
150
        re.compile(r"-(pic|PIC|pie|PIE)"),
151
        re.compile(r"-pthread"),
152
        re.compile(r"-rdynamic"),
153
        re.compile(r"-shared"),
154
        re.compile(r"-?-static([-a-z0-9+]*)"),
155
        re.compile(r"-?-stdlib=([^@\-].*)"),
156
        re.compile(r"-v"),
157
        # Note that any wildcards in -Wl need to exclude comma,
158
        # since -Wl splits its argument at commas and passes
159
        # them all to the linker uninterpreted. Allowing comma
160
        # in a wildcard would allow tunneling arbitrary additional
161
        # linker arguments through one of these.
162
        re.compile(r"-Wl,--(no-)?allow-multiple-definition"),
163
        re.compile(r"-Wl,--(no-)?allow-shlib-undefined"),
164
        re.compile(r"-Wl,--(no-)?as-needed"),
165
        re.compile(r"-Wl,-Bdynamic"),
166
        re.compile(r"-Wl,-berok"),
167
        re.compile(r"-Wl,-Bstatic"),
168
        re.compile(r"-Wl,-Bsymbolic-functions"),
169
        re.compile(r"-Wl,-O([^@,\-][^,]*)?"),
170
        re.compile(r"-Wl,-d[ny]"),
171
        re.compile(r"-Wl,--disable-new-dtags"),
172
        re.compile(r"-Wl,-e[=,][a-zA-Z0-9]*"),
173
        re.compile(r"-Wl,--enable-new-dtags"),
174
        re.compile(r"-Wl,--end-group"),
175
        re.compile(r"-Wl,--(no-)?export-dynamic"),
176
        re.compile(r"-Wl,-E"),
177
        re.compile(r"-Wl,-framework,[^,@\-][^,]+"),
178
        re.compile(r"-Wl,--hash-style=(sysv|gnu|both)"),
179
        re.compile(r"-Wl,-headerpad_max_install_names"),
180
        re.compile(r"-Wl,--no-undefined"),
181
        re.compile(r"-Wl,-R([^@\-][^,@]*$)"),
182
        re.compile(r"-Wl,--just-symbols[=,]([^,@\-][^,@]+)"),
183
        re.compile(r"-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)"),
184
        re.compile(r"-Wl,-s"),
185
        re.compile(r"-Wl,-search_paths_first"),
186
        re.compile(r"-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)"),
187
        re.compile(r"-Wl,--start-group"),
188
        re.compile(r"-Wl,-?-static"),
189
        re.compile(r"-Wl,-?-subsystem,(native|windows|console|posix|xbox)"),
190
        re.compile(r"-Wl,-syslibroot[=,]([^,@\-][^,]+)"),
191
        re.compile(r"-Wl,-undefined[=,]([^,@\-][^,]+)"),
192
        re.compile(r"-Wl,-?-unresolved-symbols=[^,]+"),
193
        re.compile(r"-Wl,--(no-)?warn-([^,]+)"),
194
        re.compile(r"-Wl,-?-wrap[=,][^,@\-][^,]*"),
195
        re.compile(r"-Wl,-z,(no)?execstack"),
196
        re.compile(r"-Wl,-z,relro"),
197
        re.compile(
198
            r"[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so|tbd)"
199
        ),  # direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
200
        re.compile(r"\./.*\.(a|o|obj|dll|dylib|so|tbd)"),
201
    )
202

203

204
_valid_linker_flags_with_next_arg = (
11✔
205
    "-arch",
206
    "-F",
207
    "-l",
208
    "-L",
209
    "-framework",
210
    "-isysroot",
211
    "--sysroot",
212
    "-target",
213
    "-Wl,-framework",
214
    "-Wl,-rpath",
215
    "-Wl,-R",
216
    "-Wl,--just-symbols",
217
    "-Wl,-undefined",
218
)
219

220

221
# SafeArg reports whether arg is a "safe" command-line argument,
222
# meaning that when it appears in a command-line, it probably
223
# doesn't have some special meaning other than its own name.
224
# Obviously args beginning with - are not safe (they look like flags).
225
# Less obviously, args beginning with @ are not safe (they look like
226
# GNU binutils flagfile specifiers, sometimes called "response files").
227
# To be conservative, we reject almost any arg beginning with non-alphanumeric ASCII.
228
# We accept leading . _ and / as likely in file system paths.
229
# There is a copy of this function in cmd/compile/internal/gc/noder.go.
230
def safe_arg(name: str) -> bool:
11✔
231
    if name == "":
×
232
        return False
×
233
    c = name[0]
×
234
    return (
×
235
        c in string.digits
236
        or c in string.ascii_letters
237
        or c == "."
238
        or c == "_"
239
        or c == "/"
240
        or ord(c) >= 0x80
241
    )
242

243

244
def _check_flags(
11✔
245
    flags: Sequence[str],
246
    regexps: Iterable[re.Pattern],
247
    valid_next_options: Iterable[str],
248
    source: str,
249
):
250
    i = 0
×
251
    while i < len(flags):
×
252
        flag = flags[i]
×
253
        continue_outer_loop = False
×
254
        for regexp in regexps:
×
255
            m = regexp.fullmatch(flag)
×
256
            if m:
×
257
                i = i + 1
×
258
                continue_outer_loop = True
×
259
                break
×
260

261
        if continue_outer_loop:
×
262
            continue
×
263

264
        for valid_next_option in valid_next_options:
×
265
            if valid_next_option == flag:
×
266
                if i + 1 < len(flags) and safe_arg(flags[i + 1]):
×
267
                    i = i + 2
×
268
                    continue_outer_loop = True
×
269
                    break
×
270

271
                # Permit -Wl,-framework -Wl,name.
272
                if (
×
273
                    i + 1 < len(flags)
274
                    and flag.startswith("-Wl,")
275
                    and flags[i + 1].startswith("-Wl,")
276
                    and safe_arg(flags[i + 1][4:])
277
                    and "," not in flags[i + 1][4:]
278
                ):
279
                    i = i + 2
×
280
                    continue_outer_loop = True
×
281
                    break
×
282

283
                # Permit -I= /path, -I $SYSROOT.
284
                if i + 1 < len(flags) and flag == "-I":
×
285
                    if (
×
286
                        flags[i + 1].startswith("=") or flags[i + 1].startswith("$SYSROOT")
287
                    ) and safe_arg(flags[i + 1][1:]):
288
                        i = i + 2
×
289
                        continue_outer_loop = True
×
290
                        break
×
291

292
                if i + 1 < len(flags):
×
293
                    raise CGoFlagSecurityError(
×
294
                        f"invalid flag in {source}: {flag} {flags[i + 1]} (see https://golang.org/s/invalidflag)"
295
                    )
296

297
                raise CGoFlagSecurityError(
×
298
                    f"invalid flag in {source}: {flag} without argument (see https://golang.org/s/invalidflag)"
299
                )
300

301
        if continue_outer_loop:
×
302
            continue
×
303

304
        raise CGoFlagSecurityError(f"invalid flag in {source}: {flag}")
×
305

306

307
def check_compiler_flags(flags: Sequence[str], source: str):
11✔
308
    _check_flags(flags, _valid_compiler_flags(), _valid_compiler_flags_with_next_arg, source)
×
309

310

311
def check_linker_flags(flags: Sequence[str], source: str):
11✔
312
    _check_flags(flags, _valid_linker_flags(), _valid_linker_flags_with_next_arg, source)
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc