-
Notifications
You must be signed in to change notification settings - Fork 0
247 lines (217 loc) · 9.44 KB
/
Copy pathbuild-mitmproxy-linux.yml
File metadata and controls
247 lines (217 loc) · 9.44 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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# This workflow is based on the `build-linux-wheel` job of
# https://github.com/mitmproxy/mitmproxy_rs/blob/v0.12.11/.github/workflows/ci.yml
name: Build mitmproxy-linux wheels (riscv64)
on:
workflow_dispatch:
inputs:
version:
description: 'Version glob to (re)build; empty builds every version of docs/packages/mitmproxy-linux.yaml not released yet'
required: false
default: ''
pull_request:
branches: [main]
paths:
- '.github/workflows/build-mitmproxy-linux.yml'
- 'docs/packages/mitmproxy-linux.yaml'
push:
branches: [main]
paths:
- '.github/workflows/build-mitmproxy-linux.yml'
- 'docs/packages/mitmproxy-linux.yaml'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
setup:
uses: $/.github/workflows/_setup.yml
with:
package: mitmproxy-linux
version: ${{ inputs.version }}
build_ebpf:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
# bpf-linker calls LLVM through the shared library the Rust toolchain ships,
# which riscv64 toolchains do not carry, and the newest LLVM packaged for
# riscv64 is older than this release's MSRV emits bitcode for. The object is
# architecture-independent BPF bytecode apart from the bpf_target_arch cfg,
# so it is cross-compiled here and embedded by patch 0001.
name: Cross-compile mitmproxy-linux ${{ matrix.version }} eBPF object
runs-on: ubuntu-latest
timeout-minutes: 60
env:
MITMPROXY_LINUX_VERSION: ${{ matrix.version }}
steps:
- name: Checkout mitmproxy_rs v${{ env.MITMPROXY_LINUX_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: mitmproxy/mitmproxy_rs
ref: v${{ env.MITMPROXY_LINUX_VERSION }}
persist-credentials: false
- name: Install the nightly toolchain and bpf-linker
run: |
rustup toolchain install nightly --profile minimal --component rust-src
cargo install --locked bpf-linker@0.9.15
- name: Build the eBPF object
# The flags aya_build::build_ebpf passes, with bpf_target_arch set for
# the wheel's architecture rather than this runner's.
run: |
env -u RUSTC -u RUSTC_WORKSPACE_WRAPPER \
CARGO_ENCODED_RUSTFLAGS=$'--cfg=bpf_target_arch="riscv64"\x1f-Cdebuginfo=2\x1f-Clink-arg=--btf' \
rustup run nightly cargo build --package mitmproxy-linux-ebpf --bins \
--release --target bpfel-unknown-none -Z build-std=core
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: mitmproxy-linux-${{ env.MITMPROXY_LINUX_VERSION }}-ebpf-object
path: target/bpfel-unknown-none/release/mitmproxy-linux
if-no-files-found: error
build_wheel:
needs: [setup, build_ebpf]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
name: Build mitmproxy-linux ${{ matrix.version }} manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 1440
env:
MITMPROXY_LINUX_VERSION: ${{ matrix.version }}
steps:
- name: Checkout mitmproxy_rs v${{ env.MITMPROXY_LINUX_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: mitmproxy/mitmproxy_rs
ref: v${{ env.MITMPROXY_LINUX_VERSION }}
persist-credentials: false
- name: Checkout python-wheels
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: python-wheels
persist-credentials: false
- name: Patch mitmproxy_rs source
run: git apply python-wheels/patches/mitmproxy-linux/${{ env.MITMPROXY_LINUX_VERSION }}/00*.patch
- name: Download the eBPF object
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: mitmproxy-linux-${{ env.MITMPROXY_LINUX_VERSION }}-ebpf-object
path: ebpf-prebuilt
- name: Stage the licence beside mitmproxy-linux's pyproject.toml
# maturin globs LICEN[CS]E* relative to the pyproject directory, which
# in this monorepo is mitmproxy-linux/ -- so upstream's own aarch64
# wheel ships no licence text at all.
run: cp LICENSE mitmproxy-linux/
# `[tool.maturin] bindings = "bin"`: the wheel is one compiled executable
# with no ABI tag, so a single native build covers every interpreter.
- name: Build wheel
uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
with:
command: build
target: riscv64gc-unknown-linux-gnu
args: --release --locked --out dist --manifest-path mitmproxy-linux/Cargo.toml
manylinux: '2_39'
before-script-linux: |
git config --global --add safe.directory "*"
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: mitmproxy-linux-${{ env.MITMPROXY_LINUX_VERSION }}-manylinux_riscv64
path: dist/*.whl
if-no-files-found: error
test_wheel:
name: Test mitmproxy-linux ${{ matrix.version }} on Python ${{ matrix.python-version }}
needs: [setup, build_wheel]
if: needs.setup.outputs.versions != '[]'
runs-on: ubuntu-24.04-riscv
timeout-minutes: 30
env:
MITMPROXY_LINUX_VERSION: ${{ matrix.version }}
# Without this uv would reuse the runner image's system CPython for 3.12
# and download a standalone build for the others.
UV_PYTHON_PREFERENCE: only-managed
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
# The wheel is interpreter-agnostic (bindings = "bin"), so every
# interpreter exercises the same binary.
python-version: ['3.12', '3.13', '3.14', '3.14t']
steps:
- name: Download wheel
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: mitmproxy-linux-${{ env.MITMPROXY_LINUX_VERSION }}-manylinux_riscv64
- name: Install Python
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
python-version: ${{ matrix.python-version }}
activate-environment: true
enable-cache: false
- name: Install wheel
run: uv pip install --reinstall --no-index --find-links . mitmproxy_linux
# The redirector needs root, a tun device and cgroup eBPF attach, so it
# cannot be driven end to end here (upstream gates that behind its own
# `root-tests` feature). Assert instead that the eBPF object its build.rs
# cross-compiles to bpfel-unknown-none really is embedded in the riscv64
# executable -- loading it is all the binary does.
- name: Test wheel
run: |
set -euo pipefail
cat > verify.py <<'EOF'
import struct
import subprocess
import sys
from mitmproxy_linux import executable_path
exe = executable_path()
assert exe.is_file(), exe
buf = exe.read_bytes()
assert buf[:6] == b"\x7fELF\x02\x01", buf[:6]
(machine,) = struct.unpack_from("<H", buf, 18)
assert machine == 243, f"redirector is not riscv64: e_machine={machine}"
pos = 0
while True:
pos = buf.find(b"\x7fELF\x02\x01\x01", pos + 1)
assert pos > 0, "no embedded eBPF object in the redirector"
if struct.unpack_from("<H", buf, pos + 18)[0] == 247:
break
(shoff,) = struct.unpack_from("<Q", buf, pos + 0x28)
shentsize, shnum, shstrndx = struct.unpack_from("<HHH", buf, pos + 0x3A)
base = pos + shoff
(strtab,) = struct.unpack_from("<Q", buf, base + shstrndx * shentsize + 0x18)
names = []
for i in range(shnum):
(name,) = struct.unpack_from("<I", buf, base + i * shentsize)
start = pos + strtab + name
names.append(buf[start:buf.index(b"\0", start)].decode())
print("eBPF sections:", [n for n in names if n])
assert "cgroup/sock_create" in names, names
assert b"INTERCEPT_CONF" in buf[pos:], "INTERCEPT_CONF map missing"
run = subprocess.run([exe], capture_output=True, text=True, timeout=60)
print(run.stderr, file=sys.stderr)
assert run.returncode != 0, run
assert "usage:" in run.stderr, run.stderr
EOF
python verify.py
publish:
name: Publish mitmproxy-linux ${{ matrix.version }}
needs: [setup, build_wheel, test_wheel]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
permissions:
contents: write
pull-requests: write
uses: $/.github/workflows/_publish-wheel.yml
secrets:
app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }}
with:
artifact-pattern: mitmproxy-linux-${{ matrix.version }}-manylinux_riscv64