liquidsoap

maintainer wjhandley · 0 votes · scanned 2026-08-03 00:08:14.047287
LOW
View on AUR ↗
Why flagged The package uses opam to fetch OCaml dependencies at build time, which is a normal and expected part of building OCaml projects; the resulting binary is self-contained and only links against standard system libraries at runtime, posing no remote code execution or supply-chain risk.

Triggered rules

LOW AI review downgraded a static finding llm_review

The static rules flagged this MEDIUM, but an AI model (qwen/qwen3-235b-a22b-07-25) reviewed the full PKGBUILD and judged it LOW (confidence 95%): The package uses opam to fetch OCaml dependencies at build time, which is a normal and expected part of building OCaml projects; the resulting binary is self-contained and only links against standard system libraries at runtime, posing no remote code execution or supply-chain risk.

  • PKGBUILD:113 opam install --yes "${_opam_packages[@]}"
1 higher static finding superseded - not the current verdict (shown for transparency)
MEDIUM External install via pipx/uv/poetry/cargo/go/gem alt_pkg_manager_install

A non-pip/npm package manager (pipx, uv, poetry, cargo install, go install, gem, conda…) fetches and builds an external package at build time, outside source=() and makepkg's checksums.

  • PKGBUILD:114 opam install --yes --deps-only liquidsoap-lang liquidsoap

PKGBUILD

2 offending line(s) highlighted
1# Maintainer: Will Handley <wh260@cam.ac.uk>
2#
3# Liquidsoap is an OCaml-based scripting language and runtime for live audio
4# composition. Upstream is built with opam (the OCaml package manager), which
5# pulls in ~80 OCaml libraries. Rather than packaging each OCaml dependency
6# as its own Arch package, this PKGBUILD uses opam at build time with a
7# private OPAM root scoped to the build directory. The resulting native
8# binary is then installed into $pkgdir via `dune install`.
9#
10# Build deps come from Arch (opam, ocaml, dune, system C libs); OCaml deps
11# come from opam-repository at build time. Runtime deps are only the C
12# shared libraries the binary links against, since `dune build --release`
13# produces a self-contained native executable.
14
15pkgname=liquidsoap
16pkgver=2.4.4
17pkgrel=1
18pkgdesc='Swiss-army knife for multimedia streaming — scriptable live-audio engine used by Radio France, AzuraCast, Libretime'
19arch=('x86_64')
20url='https://www.liquidsoap.info/'
21license=('GPL-2.0-or-later')
22depends=(
23 'glibc'
24 'gcc-libs'
25 'curl'
26 'ffmpeg' # HLS input, audio/video decoding (linked by build)
27 'openssl' # HTTPS sources, TLS output (linked by build)
28 'libsamplerate' # high-quality resampling (linked by build)
29)
30makedepends=(
31 'opam'
32 'ocaml'
33 'dune'
34 'pkgconf'
35 'git'
36 'unzip'
37 'python'
38)
39source=("https://github.com/savonet/liquidsoap/archive/refs/tags/v${pkgver}.tar.gz")
40sha256sums=('ed5ce71363f28e4f5a0d11eca2426cd973f9d0d929e1b864de93973a18e2d39c')
41
42_opam_packages=(
43 # Core deps from liquidsoap.opam
44 'dune-build-info'
45 'dune-site'
46 'mm'
47 're'
48 'curl'
49 'camomile'
50 'uri'
51 'menhirLib'
52 'mem_usage'
53 'metadata'
54 'magic-mime'
55 'ppx_string'
56 'base-bytes'
57 # Optional but wanted for our use case
58 'ffmpeg' # HLS input + decoding
59 'ssl' # HTTPS sources
60 'samplerate' # Resampling
61 'posix-time2'
62)
63
64_opam_env() {
65 export OPAMROOT="${srcdir}/.opam"
66 export OPAMYES=1
67 export OPAMCONFIRMLEVEL=unsafe-yes
68 export OPAMVERBOSE=0
69 export OPAMCOLOR=never
70 # Use system OCaml, don't recompile it
71 export OPAMNOEXTERNALSOLVERFETCH=true
72 # opam's sandboxing uses bubblewrap which can clash with makepkg's
73 # restrictions; disable for the build.
74 export OPAMSANDBOXING=false
75}
76
77prepare() {
78 cd "${srcdir}/${pkgname}-${pkgver}"
79
80 _opam_env
81
82 if [[ ! -d "${OPAMROOT}" ]]; then
83 opam init \
84 --bare \
85 --no-setup \
86 --disable-shell-hook \
87 --disable-sandboxing \
88 --shell=bash \
89 --reinit
90 fi
91
92 if ! opam switch list --short 2>/dev/null | grep -qx build-switch; then
93 opam switch create build-switch --packages=ocaml-system --no-install
94 fi
95
96 eval "$(opam env --switch=build-switch --set-switch)"
97
98 # Pin local liquidsoap-* opam packages from this source tree so opam
99 # resolves deps against this version and doesn't pull liquidsoap-lang
100 # from opam-repository.
101 cd opam
102 for f in liquidsoap-lang.opam liquidsoap.opam; do
103 opam pin add --no-action --kind=path "${f%.opam}" "${srcdir}/${pkgname}-${pkgver}"
104 done
105}
106
107build() {
108 cd "${srcdir}/${pkgname}-${pkgver}"
109
110 _opam_env
111 eval "$(opam env --switch=build-switch --set-switch)"
112
113 opam install --yes "${_opam_packages[@]}"
114 opam install --yes --deps-only liquidsoap-lang liquidsoap
115
116 dune build --release --profile=release
117}
118
119package() {
120 cd "${srcdir}/${pkgname}-${pkgver}"
121
122 _opam_env
123 eval "$(opam env --switch=build-switch --set-switch)"
124
125 # dune install lays out bin/, share/liquidsoap/, share/man/, etc.
126 # --docdir is required because dune's default doc target is /usr/doc on Arch.
127 dune install --release \
128 --destdir="${pkgdir}" \
129 --prefix=/usr \
130 --docdir=/usr/share/doc \
131 liquidsoap-lang liquidsoap
132
133 install -Dm644 COPYING "${pkgdir}/usr/share/licenses/${pkgname}/COPYING"
134
135 # OCaml source files leak into the installed lib dir; only the compiled
136 # .cmxs/.cmi are needed at runtime.
137 find "${pkgdir}/usr/lib/liquidsoap-lang" \( -name '*.ml' -o -name '*.mli' \) -delete
138
139 # Camomile (Unicode lib) uses dune-site to encode its data directory at
140 # link time, pointing into the opam build switch. Ship the data under our
141 # own namespace (a future Arch camomile package would own /usr/share/camomile)
142 # and patch the encoded path in the binary in place.
143 local cam_src="${OPAMROOT}/build-switch/share/camomile"
144 install -d "${pkgdir}/usr/share/liquidsoap/camomile"
145 cp -a "${cam_src}/." "${pkgdir}/usr/share/liquidsoap/camomile/"
146
147 # dune-site encodes "=<len>:<path><padding>" with a fixed total field
148 # width. Replace the srcdir path with /usr/share/liquidsoap/camomile,
149 # preserving the total byte count by adjusting length prefix and padding.
150 python3 - "${pkgdir}/usr/bin/liquidsoap" <<'PY'
151import sys, re
152path = sys.argv[1]
153with open(path, 'rb') as f:
154 data = f.read()
155# Match =<len>:<srcdir>/.opam/build-switch/share/camomile<spaces>
156pat = re.compile(rb'=(\d+):(/[^\x00]*?\.opam/build-switch/share/camomile)( +)', re.DOTALL)
157def sub(m):
158 new = b'/usr/share/liquidsoap/camomile'
159 orig_total = len(m.group(0))
160 new_prefix = b'=%d:%s' % (len(new), new)
161 pad = orig_total - len(new_prefix)
162 assert pad >= 0, f"camomile path replacement overflow: {orig_total} vs {len(new_prefix)}"
163 return new_prefix + b' ' * pad
164new_data, n = pat.subn(sub, data)
165if n == 0:
166 sys.exit("camomile encoded path not found in binary")
167with open(path, 'wb') as f:
168 f.write(new_data)
169print(f"patched {n} camomile path(s)")
170PY
171
172 # Two more residual srcdir paths embedded in the binary:
173 # - a ctypes -I include flag (NUL-terminated string) used by runtime FFI
174 # stub compilation in Ctypes.Foreign, almost never invoked by scripts;
175 # - the OCaml library search path that dune-site bakes into an `=N:hardcoded
176 # \0/usr/lib/ocaml\0<srcdir>/lib<padding>` block used by Dynlink for
177 # plugin discovery. /usr/lib/ocaml is already in that list, so blanking
178 # the srcdir entry leaves a working search path on the user system.
179 # Blank both to space-padded empty fields so any caller sees a no-op rather
180 # than a stale build-host path.
181 python3 - "${pkgdir}/usr/bin/liquidsoap" "${srcdir}" <<'PY'
182import sys, re
183binpath, srcdir = sys.argv[1], sys.argv[2].encode()
184with open(binpath, 'rb') as f:
185 data = f.read()
186escaped = re.escape(srcdir + b'/.opam/build-switch/lib')
187# Match the path followed by trailing C-string NULs OR dune-site padding spaces.
188pat = re.compile(escaped + rb'(/ctypes)?( +|\x00+)')
189def sub(m):
190 return b' ' * len(m.group(0)) if m.group(2).startswith(b' ') else b'\x00' * len(m.group(0))
191data, n = pat.subn(sub, data)
192if n == 0:
193 sys.exit("expected residual lib/ctypes srcdir paths in binary, found none")
194with open(binpath, 'wb') as f:
195 f.write(data)
196print(f"nulled {n} residual path(s)")
197PY
198 # Remaining $srcdir hits at this point live in DWARF debug sections (OCaml
199 # _build/default paths). makepkg's default strip pass removes them after
200 # package() returns. A final check would have to run post-strip, which is
201 # outside this hook's reach; rely on makepkg's own "reference to $srcdir"
202 # check for that final assertion.
203}
204

Scan history

Scanned at (UTC)SeverityRules
2026-08-03 00:08:14 LOW 2
2026-08-02 00:16:08 LOW 2
2026-08-01 00:11:18 LOW 2
2026-07-31 00:14:10 LOW 2
2026-07-30 00:17:23 LOW 2
2026-07-29 00:25:53 LOW 2
2026-07-28 00:07:28 LOW 2
2026-07-27 00:24:32 LOW 2
2026-07-26 00:07:32 LOW 2
2026-07-25 00:13:44 LOW 2
2026-07-24 00:02:28 LOW 2
2026-07-23 00:14:47 LOW 2
2026-07-22 00:29:32 LOW 2
2026-07-21 00:24:15 LOW 2
2026-07-20 00:19:49 LOW 2
2026-07-19 00:17:08 LOW 2
2026-07-18 00:14:48 LOW 2
2026-07-17 00:06:16 LOW 2
2026-07-16 00:05:41 LOW 2
2026-07-15 00:09:25 LOW 2

Report a package

Reports go to the AURWatch maintainer (one person) and are read by hand. No login required.

0 / 4000
Your suggestion