cln-grpc: vendor protoc as a build-dependency
What changed, and why it matters
This change swaps how the project gets its Protocol Buffers compiler (protoc) for one Rust component. Instead of relying on whatever version the operating system or CI happens to install, it bundles a specific protoc version as a build-time dependency. The goal is to make builds more consistent and avoid mismatches between protoc and the Python/Rust protobuf tooling. It is a build-system hygiene patch, not a fix for an active security flaw.
Treat as a routine build-maintenance commit. Reviewers should verify that the `protoc-bin-vendored` crate is from a trusted publisher and that its bundled protoc version is compatible with the generated gRPC code. No urgent security action is required.
Security signals we found
Build dependency pinning to reduce supply-chain/version-drift risk
Removal of curl/wget-based protoc downloads from CI and Dockerfiles
No runtime code or protocol logic changes
No mention of CVE, vulnerability, or exploit in commit message or diff
Evidence from the diff
The commit vendors protoc via the protoc-bin-vendored crate (version 3.x) for the cln-grpc Rust crate. cln-grpc/build.rs now sets the PROTOC environment variable to the bundled binary path. CI scripts, Dockerfiles, and documentation are updated to remove manual protoc installation steps and OS package dependencies. This reduces version drift between environments (OS packages at 21.12, CI at 29.4, grpcio-tools at 31.1) by standardizing on the vendored protoc. The only noted regression is that arm 32-bit hosts lack a bundled binary and must still provide their own protoc.
Changed components
cln-grpc build.rscln-grpc/Cargo.tomlCargo.lockCI workflows (.github/workflows/*.yml, .github/scripts/setup.sh)Dockerfile and contrib Dockerfilesgetting-started installation documentationInspect captured patch +74 / −75
diff --git a/.github/scripts/setup.sh b/.github/scripts/setup.sh
index 291c4c07..c9414b06 100755
--- a/.github/scripts/setup.sh
+++ b/.github/scripts/setup.sh
@@ -81,39 +81,6 @@ uv sync --all-extras --all-groups
# required for reckless till poetry to uv migration
uv tool install poetry
-# We also need a relatively recent protobuf-compiler, at least 3.12.0,
-# in order to support the experimental `optional` flag.
-
-# BUT WAIT! Gentoo wants this to match the version from the Python protobuf,
-# which comes from the same tree. Makes sense!
-
-# And
-# grpcio-tools-1.69.0` requires `protobuf = ">=5.26.1,<6.0dev"`
-
-# Now, protoc changed to date-based releases, BUT Python protobuf
-# didn't, so Python protobuf 4.21.12 (in Ubuntu 23.04) corresponds to
-# protoc 21.12 (which, FYI, is packaged in Ubuntu as version 3.21.12).
-
-# In general protobuf version x.y.z corresponds to protoc version y.z
-
-# Honorable mention go to Matt Whitlock for spelunking this horror with me!
-
-PROTOC_VERSION=29.4
-PB_REL="https://github.com/protocolbuffers/protobuf/releases"
-PROTOC_ZIP=protoc-${PROTOC_VERSION}-linux-x86_64.zip
-if [ ! -f ~/ci-cache/$PROTOC_ZIP ]; then
- curl -LO $PB_REL/download/v${PROTOC_VERSION}/$PROTOC_ZIP
- # Check it before we commit it to the cache!
- unzip -t $PROTOC_ZIP
- cp $PROTOC_ZIP ~/ci-cache/
-fi
-sudo unzip ~/ci-cache/$PROTOC_ZIP -d /usr/local/
-sudo chmod a+x /usr/local/bin/protoc
-export PROTOC=/usr/local/bin/protoc
-export PATH=$PATH:/usr/local/bin
-env
-ls -lha /usr/local/bin
-
# wireshark-common normally does this, but GH runners are special, so we
# do it explicitly
sudo groupadd -f wireshark
diff --git a/.github/workflows/crate-io.yml b/.github/workflows/crate-io.yml
index b55c392e..51f5e0bf 100644
--- a/.github/workflows/crate-io.yml
+++ b/.github/workflows/crate-io.yml
@@ -12,7 +12,6 @@ jobs:
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- - uses: arduino/setup-protoc@v3
- uses: katyo/publish-crates@v2
with:
path: './cln-rpc'
diff --git a/.github/workflows/macos.yaml b/.github/workflows/macos.yaml
index 7e31bd9c..19af0e0c 100644
--- a/.github/workflows/macos.yaml
+++ b/.github/workflows/macos.yaml
@@ -37,7 +37,7 @@ jobs:
run: |
export PATH="/usr/local/opt:/Users/runner/.local/bin:/opt/homebrew/bin/python3.10/bin:$PATH"
- brew install gnu-sed autoconf automake libtool protobuf openssl lowdown libsodium make
+ brew install gnu-sed autoconf automake libtool openssl lowdown libsodium make
# https://github.com/grpc/grpc/issues/31737#issuecomment-1323796842
export GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1
diff --git a/.github/workflows/rust-msrv.yml b/.github/workflows/rust-msrv.yml
index a1565927..197415e3 100644
--- a/.github/workflows/rust-msrv.yml
+++ b/.github/workflows/rust-msrv.yml
@@ -16,9 +16,6 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
- - name: protoc
- uses: arduino/setup-protoc@v3
-
- name: Install cargo-hack
uses: taiki-e/install-action@cargo-hack
diff --git a/Cargo.lock b/Cargo.lock
index 8523209b..31b0bfb8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -453,6 +453,7 @@ dependencies = [
"hex",
"log",
"prost",
+ "protoc-bin-vendored",
"serde",
"serde_json",
"tokio",
@@ -1999,6 +2000,70 @@ dependencies = [
"prost",
]
+[[package]]
+name = "protoc-bin-vendored"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1c381df33c98266b5f08186583660090a4ffa0889e76c7e9a5e175f645a67fa"
+dependencies = [
+ "protoc-bin-vendored-linux-aarch_64",
+ "protoc-bin-vendored-linux-ppcle_64",
+ "protoc-bin-vendored-linux-s390_64",
+ "protoc-bin-vendored-linux-x86_32",
+ "protoc-bin-vendored-linux-x86_64",
+ "protoc-bin-vendored-macos-aarch_64",
+ "protoc-bin-vendored-macos-x86_64",
+ "protoc-bin-vendored-win32",
+]
+
+[[package]]
+name = "protoc-bin-vendored-linux-aarch_64"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c350df4d49b5b9e3ca79f7e646fde2377b199e13cfa87320308397e1f37e1a4c"
+
+[[package]]
+name = "protoc-bin-vendored-linux-ppcle_64"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a55a63e6c7244f19b5c6393f025017eb5d793fd5467823a099740a7a4222440c"
+
+[[package]]
+name = "protoc-bin-vendored-linux-s390_64"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1dba5565db4288e935d5330a07c264a4ee8e4a5b4a4e6f4e83fad824cc32f3b0"
+
+[[package]]
+name = "protoc-bin-vendored-linux-x86_32"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8854774b24ee28b7868cd71dccaae8e02a2365e67a4a87a6cd11ee6cdbdf9cf5"
+
+[[package]]
+name = "protoc-bin-vendored-linux-x86_64"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b38b07546580df720fa464ce124c4b03630a6fb83e05c336fea2a241df7e5d78"
+
+[[package]]
+name = "protoc-bin-vendored-macos-aarch_64"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89278a9926ce312e51f1d999fee8825d324d603213344a9a706daa009f1d8092"
+
+[[package]]
+name = "protoc-bin-vendored-macos-x86_64"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81745feda7ccfb9471d7a4de888f0652e806d5795b61480605d4943176299756"
+
+[[package]]
+name = "protoc-bin-vendored-win32"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95067976aca6421a523e491fce939a3e65249bac4b977adee0ee9771568e8aa3"
+
[[package]]
name = "pulldown-cmark"
version = "0.13.4"
diff --git a/Dockerfile b/Dockerfile
index 97053739..6714e5f4 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -57,8 +57,7 @@ RUN apt-get update && \
flex \
jq \
libtool \
- gettext \
- protobuf-compiler
+ gettext
WORKDIR /opt
diff --git a/cln-grpc/Cargo.toml b/cln-grpc/Cargo.toml
index 7259df25..febfbbf9 100644
--- a/cln-grpc/Cargo.toml
+++ b/cln-grpc/Cargo.toml
@@ -33,3 +33,4 @@ serde_json = "1.0.72"
[build-dependencies]
tonic-prost-build = "0.14"
+protoc-bin-vendored = "3"
diff --git a/cln-grpc/build.rs b/cln-grpc/build.rs
index ceeda792..9d1a5b10 100644
--- a/cln-grpc/build.rs
+++ b/cln-grpc/build.rs
@@ -1,5 +1,7 @@
fn main() {
let builder = tonic_prost_build::configure();
+ let protoc = protoc_bin_vendored::protoc_bin_path().unwrap();
+ unsafe { std::env::set_var("PROTOC", protoc) };
builder
.type_attribute(".", "#[derive(serde::Serialize,serde::Deserialize)]")
.protoc_arg("--experimental_allow_proto3_optional")
diff --git a/contrib/docker/Dockerfile.builder.fedora b/contrib/docker/Dockerfile.builder.fedora
index 0ee99032..3a51e0f3 100644
--- a/contrib/docker/Dockerfile.builder.fedora
+++ b/contrib/docker/Dockerfile.builder.fedora
@@ -30,9 +30,7 @@ RUN dnf update -y && \
python3-devel \
python3-pip \
python3-poetry \
- postgresql-devel \
- protobuf-compiler \
- protobuf-devel && \
+ postgresql-devel && \
dnf clean all
# Install Rust via rustup (for lockfile v4 support)
diff --git a/contrib/reprobuild/Dockerfile.jammy b/contrib/reprobuild/Dockerfile.jammy
index 56959cb8..398afec0 100644
--- a/contrib/reprobuild/Dockerfile.jammy
+++ b/contrib/reprobuild/Dockerfile.jammy
@@ -5,7 +5,6 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ENV SOURCE_DATE_EPOCH=1672531200
ENV RUST_PROFILE=release
ENV PATH=/root/.pyenv/shims:/root/.pyenv/bin:/root/.cargo/bin:/root/.local/bin:$PATH
-ENV PROTOC_VERSION=29.4
RUN sed -i '/updates/d' /etc/apt/sources.list && \
sed -i '/security/d' /etc/apt/sources.list
@@ -65,14 +64,6 @@ RUN wget https://sh.rustup.rs -O rustup-install.sh && \
rm rustup-install.sh && \
/root/.cargo/bin/rustup install 1.85
-# Download protoc manually, it is in the update repos which we
-# disabled above, so `apt-get` can't find it anymore.
-RUN cd /tmp/ && \
- wget https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip && \
- unzip protoc-${PROTOC_VERSION}-linux-x86_64.zip && \
- mv bin/protoc /usr/local/bin && \
- rm -rf include bin protoc-${PROTOC_VERSION}-linux-x86_64.zip
-
RUN mkdir /build
WORKDIR /build
diff --git a/contrib/reprobuild/Dockerfile.noble b/contrib/reprobuild/Dockerfile.noble
index 5a2fbade..f711c0fc 100644
--- a/contrib/reprobuild/Dockerfile.noble
+++ b/contrib/reprobuild/Dockerfile.noble
@@ -5,7 +5,6 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ENV SOURCE_DATE_EPOCH=1672531200
ENV RUST_PROFILE=release
ENV PATH=/root/.pyenv/shims:/root/.pyenv/bin:/root/.cargo/bin:/root/.local/bin:$PATH
-ENV PROTOC_VERSION=29.4
RUN sed -i '/updates/d' /etc/apt/sources.list && \
sed -i '/security/d' /etc/apt/sources.list && \
@@ -55,14 +54,6 @@ RUN wget https://sh.rustup.rs -O rustup-install.sh && \
rm rustup-install.sh && \
/root/.cargo/bin/rustup install 1.85
-# Download protoc manually, it is in the update repos which we
-# disabled above, so `apt-get` can't find it anymore.
-RUN cd /tmp/ && \
- wget https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip && \
- unzip protoc-${PROTOC_VERSION}-linux-x86_64.zip && \
- mv bin/protoc /usr/local/bin && \
- rm -rf include bin protoc-${PROTOC_VERSION}-linux-x86_64.zip
-
RUN mkdir /build
WORKDIR /build
diff --git a/contrib/reprobuild/Dockerfile.resolute b/contrib/reprobuild/Dockerfile.resolute
index e9b67e15..f72414b9 100644
--- a/contrib/reprobuild/Dockerfile.resolute
+++ b/contrib/reprobuild/Dockerfile.resolute
@@ -5,7 +5,6 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ENV SOURCE_DATE_EPOCH=1672531200
ENV RUST_PROFILE=release
ENV PATH=/root/.pyenv/shims:/root/.pyenv/bin:/root/.cargo/bin:/root/.local/bin:$PATH
-ENV PROTOC_VERSION=29.4
RUN sed -i '/updates/d' /etc/apt/sources.list && \
sed -i '/security/d' /etc/apt/sources.list && \
@@ -55,14 +54,6 @@ RUN wget https://sh.rustup.rs -O rustup-install.sh && \
rm rustup-install.sh && \
/root/.cargo/bin/rustup install 1.85
-# Download protoc manually, it is in the update repos which we
-# disabled above, so `apt-get` can't find it anymore.
-RUN cd /tmp/ && \
- wget https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip && \
- unzip protoc-${PROTOC_VERSION}-linux-x86_64.zip && \
- mv bin/protoc /usr/local/bin && \
- rm -rf include bin protoc-${PROTOC_VERSION}-linux-x86_64.zip
-
RUN mkdir /build
WORKDIR /build
diff --git a/doc/getting-started/getting-started/installation.md b/doc/getting-started/getting-started/installation.md
index 8236c0d1..e2411a87 100644
--- a/doc/getting-started/getting-started/installation.md
+++ b/doc/getting-started/getting-started/installation.md
@@ -112,7 +112,7 @@ sudo apt-get install -y valgrind libpq-dev shellcheck cppcheck \
If you want to build the Rust plugins (cln-grpc, clnrest, cln-bip353 and wss-proxy):
```shell
-sudo apt-get install -y cargo rustfmt protobuf-compiler
+sudo apt-get install -y cargo rustfmt
```
> 📘
@@ -177,8 +177,6 @@ sudo dnf update -y && \
libsodium-devel \
which \
sed \
- protobuf-compiler \
- protobuf-devel \
postgresql-devel \
python3-mako && \
sudo dnf clean all
@@ -352,7 +350,7 @@ You are using brew in Intel compatibility mode. The simplest solution is to remo
Install dependencies:
```shell
-brew install autoconf automake libtool python3 gnu-sed gettext libsodium protobuf lowdown pkgconf openssl make
+brew install autoconf automake libtool python3 gnu-sed gettext libsodium lowdown pkgconf openssl make
export PATH="/opt/homebrew/opt/:$PATH"
export CPATH=/opt/homebrew/include
export LIBRARY_PATH=/opt/homebrew/lib
@@ -429,7 +427,7 @@ Assuming you have Xcode and Homebrew installed.
Install dependencies:
```shell
-brew install autoconf automake libtool python3 gnu-sed gettext libsodium protobuf lowdown pkgconf openssl make
+brew install autoconf automake libtool python3 gnu-sed gettext libsodium lowdown pkgconf openssl make
export PATH="/usr/local/opt/:$PATH"
export CPATH=/usr/local/include
export LIBRARY_PATH=/usr/local/lib
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.