Skip to content

Commit 2c4a3a7

Browse files
CI: build boringssl-static and the FIPS profile on Debian 13, verify both jars on Alpine
Motivation: CI builds boringssl-static only on the two release images and never builds the FIPS profile. #997 could add the musl check to that profile without the matching link changes, and nothing failed until a downstream build did (#1008). Modifications: - docker/Dockerfile.debian13 + docker-compose.debian-13.yaml, services `build` and `build-fips`. Every input is pinned: base image by digest, Debian archive by snapshot.debian.org timestamp, clang by version, Go by version and checksum (BoringSSL's go.mod is ahead of trixie's Go). trixie has no JDK 8, so the build runs on JDK 21 with the pom's --release 8. - ci-pr.yml / ci-build.yml: legs debian13-x86_64 and debian13-x86_64-fips, plus bare-Alpine musl-verify legs on their jars. The FIPS module's integrity check runs in an ELF constructor at dlopen, so only a real load proves the post-link patchelf left it intact. Result: A change to the FIPS profile, or one to the release profiles that is not ported to it, fails on the PR. Not a release image: glibc 2.34 floor.
1 parent e30baa6 commit 2c4a3a7

6 files changed

Lines changed: 212 additions & 0 deletions

File tree

‎.github/workflows/ci-build.yml‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ jobs:
4040
- setup: al2023-x86_64-aws_lc
4141
docker-compose-run: "-f docker/docker-compose.al2023.yaml run build"
4242
docker-bake-args: "-f docker-compose.al2023.yaml"
43+
# boringssl-static on a current toolchain, and the only CI leg that builds the FIPS
44+
# profile (it needs clang; see docker/Dockerfile.debian13). Neither is a release
45+
# artifact. Before these legs the FIPS profile had no CI at all, so a change to the
46+
# release profiles that was not ported to it went unnoticed until a downstream build.
47+
- setup: debian13-x86_64
48+
docker-compose-run: "-f docker/docker-compose.debian-13.yaml run build"
49+
docker-bake-args: "-f docker-compose.debian-13.yaml"
50+
- setup: debian13-x86_64-fips
51+
docker-compose-run: "-f docker/docker-compose.debian-13.yaml run build-fips"
52+
docker-bake-args: "-f docker-compose.debian-13.yaml"
4353

4454
name: ${{ matrix.setup }}
4555
permissions:
@@ -219,6 +229,28 @@ jobs:
219229
drop-elftools: "0"
220230
build-service: runtime-setup
221231
run-service: verify
232+
# The Debian 13-built jars: the FIPS artifact is the one that matters (its power-on
233+
# self-test and integrity check run inside an ELF constructor at dlopen, so only a
234+
# real load proves the patchelf'd library is still intact), and the default-profile
235+
# one shows what a modern-gcc build looks like on musl. bare x86_64 only: aarch64
236+
# would need an arm64 FIPS build leg, and the gcompat/nolibgcc variants add nothing
237+
# the CentOS 6 legs do not already establish.
238+
- setup: alpine-x86_64-fips
239+
os: ubuntu-24.04
240+
jars: build-debian13-x86_64-fips-jars
241+
variant: bare
242+
extra-pkgs: ""
243+
drop-elftools: "1"
244+
build-service: runtime-setup
245+
run-service: verify
246+
- setup: alpine-x86_64-debian13
247+
os: ubuntu-24.04
248+
jars: build-debian13-x86_64-jars
249+
variant: bare
250+
extra-pkgs: ""
251+
drop-elftools: "1"
252+
build-service: runtime-setup
253+
run-service: verify
222254
- setup: glibc-control-x86_64
223255
os: ubuntu-24.04
224256
jars: build-centos6-x86_64-jars

‎.github/workflows/ci-pr.yml‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ jobs:
3838
- setup: al2023-x86_64-aws_lc
3939
docker-compose-run: "-f docker/docker-compose.al2023.yaml run build"
4040
docker-bake-args: "-f docker-compose.al2023.yaml"
41+
# boringssl-static on a current toolchain, and the only CI leg that builds the FIPS
42+
# profile (it needs clang; see docker/Dockerfile.debian13). Neither is a release
43+
# artifact. Before these legs the FIPS profile had no CI at all, so a change to the
44+
# release profiles that was not ported to it went unnoticed until a downstream build.
45+
- setup: debian13-x86_64
46+
docker-compose-run: "-f docker/docker-compose.debian-13.yaml run build"
47+
docker-bake-args: "-f docker-compose.debian-13.yaml"
48+
- setup: debian13-x86_64-fips
49+
docker-compose-run: "-f docker/docker-compose.debian-13.yaml run build-fips"
50+
docker-bake-args: "-f docker-compose.debian-13.yaml"
4151

4252
name: ${{ matrix.setup }}
4353
permissions:
@@ -280,6 +290,28 @@ jobs:
280290
drop-elftools: "0"
281291
build-service: runtime-setup
282292
run-service: verify
293+
# The Debian 13-built jars: the FIPS artifact is the one that matters (its power-on
294+
# self-test and integrity check run inside an ELF constructor at dlopen, so only a
295+
# real load proves the patchelf'd library is still intact), and the default-profile
296+
# one shows what a modern-gcc build looks like on musl. bare x86_64 only: aarch64
297+
# would need an arm64 FIPS build leg, and the gcompat/nolibgcc variants add nothing
298+
# the CentOS 6 legs do not already establish.
299+
- setup: alpine-x86_64-fips
300+
os: ubuntu-24.04
301+
jars: build-pr-debian13-x86_64-fips-jars
302+
variant: bare
303+
extra-pkgs: ""
304+
drop-elftools: "1"
305+
build-service: runtime-setup
306+
run-service: verify
307+
- setup: alpine-x86_64-debian13
308+
os: ubuntu-24.04
309+
jars: build-pr-debian13-x86_64-jars
310+
variant: bare
311+
extra-pkgs: ""
312+
drop-elftools: "1"
313+
build-service: runtime-setup
314+
run-service: verify
283315
# Control: anything failing on Alpine must pass here, or the check is at fault rather
284316
# than the artifact.
285317
- setup: glibc-control-x86_64

‎docker/Dockerfile.debian13‎

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Everything in this image is pinned: the base by digest, the Debian archive by a
2+
# snapshot.debian.org timestamp, clang by version, Go by version and checksum. To refresh it,
3+
# bump the four values below together and rebuild.
4+
ARG debian_image=debian:13.7@sha256:9cc080028c43b27d2074d63a5f9caf7166d731494965616c1a6d2827a004585c
5+
FROM $debian_image
6+
ARG debian_snapshot=20260915T000000Z
7+
ARG clang_version=19
8+
ARG go_version=1.27.1
9+
ARG go_sha256_amd64=63d339f0da5ab53635a56f2490a7984dfe12dfcff22ad749f63edaf590168445
10+
ARG go_sha256_arm64=3450b45a3f9ee8568792736a5c5e70a1f2e9b36c35a8f74958c03e51d7d92bec
11+
ENV DEBIAN_FRONTEND noninteractive
12+
13+
# A modern glibc builder for boringssl-static, and the only in-tree image that can build the
14+
# fips-boringssl-static profile, which compiles BoringSSL with clang. Google's FIPS.md asks for
15+
# recent stable Clang, Go, Ninja and CMake: clang, ninja and cmake are Debian 13's own. Go is
16+
# not: BoringSSL's go.mod floor (1.25.8 on the pinned fips-20260721) is ahead of trixie's 1.24,
17+
# so it comes from go.dev, checksum-verified. patchelf 0.18 has --remove-needed; APR's
18+
# buildconf wants the `libtool` script, which is in libtool-bin.
19+
#
20+
# No JDK 8 in trixie: the build runs on JDK 21. The pom compiles with --release 8, so the
21+
# class files are still Java 8.
22+
#
23+
# Not pinned to linux/amd64 like the older images, so it can also be built natively on an
24+
# arm64 host for a quick local run. CI builds it on amd64 runners.
25+
#
26+
# Unlike the CentOS 6 image this is NOT a release builder: its artifact has a glibc 2.34 floor.
27+
# It exists to give the boringssl-static and FIPS builds CI coverage on a current toolchain.
28+
29+
# Freeze the archive. snapshot.debian.org serves the archive as it was at that instant, so the
30+
# same package versions install no matter when the image is built; Valid-Until has long passed
31+
# by then, hence check-valid-until=no.
32+
RUN rm -f /etc/apt/sources.list.d/debian.sources \
33+
&& echo "deb [check-valid-until=no] http://snapshot.debian.org/archive/debian/$debian_snapshot trixie main" > /etc/apt/sources.list \
34+
&& echo "deb [check-valid-until=no] http://snapshot.debian.org/archive/debian/$debian_snapshot trixie-updates main" >> /etc/apt/sources.list \
35+
&& echo "deb [check-valid-until=no] http://snapshot.debian.org/archive/debian-security/$debian_snapshot trixie-security main" >> /etc/apt/sources.list
36+
37+
RUN apt-get update && apt-get install -y --no-install-recommends \
38+
autoconf \
39+
automake \
40+
bzip2 \
41+
ca-certificates \
42+
clang-$clang_version \
43+
cmake \
44+
curl \
45+
g++ \
46+
gcc \
47+
git \
48+
gnupg \
49+
libapr1-dev \
50+
libtool \
51+
libtool-bin \
52+
make \
53+
ninja-build \
54+
openjdk-21-jdk-headless \
55+
patch \
56+
patchelf \
57+
perl \
58+
pkg-config \
59+
tar \
60+
unzip \
61+
wget \
62+
xz-utils \
63+
zip \
64+
&& rm -rf /var/lib/apt/lists/* \
65+
&& ln -s clang-$clang_version /usr/bin/clang && ln -s clang++-$clang_version /usr/bin/clang++
66+
67+
# dpkg's amd64/arm64 spelling matches go.dev's and the JVM directory name.
68+
RUN ARCH=$(dpkg --print-architecture) \
69+
&& case $ARCH in amd64) GO_SHA256=$go_sha256_amd64;; arm64) GO_SHA256=$go_sha256_arm64;; esac \
70+
&& wget -q https://go.dev/dl/go$go_version.linux-$ARCH.tar.gz \
71+
&& echo "$GO_SHA256 go$go_version.linux-$ARCH.tar.gz" | sha256sum -c - \
72+
&& tar -C /opt -xzf go$go_version.linux-$ARCH.tar.gz && rm go$go_version.linux-$ARCH.tar.gz \
73+
&& ln -s /opt/go/bin/go /usr/local/bin/go && ln -s /opt/go/bin/gofmt /usr/local/bin/gofmt \
74+
&& ln -s /usr/lib/jvm/java-21-openjdk-$ARCH /usr/lib/jvm/java-21 \
75+
&& go version && clang --version && ninja --version && cmake --version
76+
ENV JAVA_HOME /usr/lib/jvm/java-21
77+
# Use exactly the pinned Go; never let it fetch another toolchain.
78+
ENV GOTOOLCHAIN local
79+
80+
# /code is a bind mount owned by the host user; newer git refuses to touch it otherwise.
81+
RUN git config --global --add safe.directory '*'

‎docker/README.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,19 @@ docker compose -f docker/docker-compose.opensuse.yaml -f docker/docker-compose.o
3939
docker compose -f docker/docker-compose.centos-7.yaml run cross-compile-aarch64-build
4040
```
4141

42+
## Debian 13 with java 21: boringssl-static on a current toolchain, and the FIPS profile
43+
44+
Not a release builder (glibc 2.34 floor). It is the one image that can build the
45+
`fips-boringssl-static` profile, which compiles BoringSSL with clang. Everything is pinned: the
46+
base image by digest, the Debian archive by a snapshot.debian.org timestamp, clang by version,
47+
Go by version and checksum. Both services stop at `package`, which is where the musl
48+
compatibility check runs. Not pinned to amd64, so on an arm64 host it builds natively.
49+
50+
```
51+
docker compose -f docker/docker-compose.debian-13.yaml run build
52+
docker compose -f docker/docker-compose.debian-13.yaml run build-fips
53+
```
54+
4255
etc, etc
4356

4457

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
version: "3"
2+
3+
# Debian 13 builder. Two things run here that no other image covers, see Dockerfile.debian13:
4+
# build boringssl-static (default profile) on a current gcc, so the Linux native
5+
# build is exercised somewhere other than the CentOS 6 release image
6+
# build-fips the fips-boringssl-static profile, which needs clang
7+
# Both stop at `package`, which is where the native-jar musl check runs.
8+
9+
services:
10+
11+
runtime-setup:
12+
image: netty-tcnative-debian:13
13+
build:
14+
context: ../
15+
dockerfile: docker/Dockerfile.debian13
16+
cache_from:
17+
- type=registry,ref=ghcr.io/netty/netty-tcnative-build-cache:debian13
18+
cache_to:
19+
- type=registry,ref=ghcr.io/netty/netty-tcnative-build-cache:debian13,mode=max,ignore-error=true
20+
21+
common: &common
22+
image: netty-tcnative-debian:13
23+
depends_on: [runtime-setup]
24+
environment:
25+
- MAVEN_OPTS
26+
volumes:
27+
- ~/.m2/repository:/root/.m2/repository
28+
- ..:/code:delegated
29+
working_dir: /code
30+
31+
build:
32+
<<: *common
33+
command: /bin/bash -cl "./mvnw -am -pl boringssl-static clean package"
34+
35+
build-fips:
36+
<<: *common
37+
command: /bin/bash -cl "./mvnw -Pfips-boringssl-static -am -pl boringssl-static clean package"
38+
39+
shell:
40+
<<: *common
41+
volumes:
42+
- ~/.m2/repository:/root/.m2/repository
43+
- ~/.gitconfig:/root/.gitconfig:delegated
44+
- ~/.gitignore:/root/.gitignore:delegated
45+
- ..:/code:delegated
46+
entrypoint: /bin/bash

‎docs/musl-compatibility.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,14 @@ The check must go further than loading. Minimum bar, in order of strength:
223223

224224
Only (3) would catch a library that loads but whose crypto is broken.
225225

226+
In CI this is the `musl-verify` job. It runs against the CentOS 6 and CentOS 7 release jars on
227+
several Alpine variants, and, bare x86_64 only, against the two Debian 13 jars: the
228+
default-profile one and the **FIPS** one (`debian13-x86_64-fips`, see `docker/Dockerfile.debian13`).
229+
The FIPS leg is the one with no substitute: its power-on self-test and integrity check run in an
230+
ELF constructor during `dlopen`, so only a real load shows that the post-link `patchelf` left the
231+
module intact. Before that leg existed the FIPS profile was built by nobody but downstream users,
232+
and a change made to the release profiles and not ported to it surfaced only there.
233+
226234
Two TLS 1.3 behaviours will make a naive handshake test report false failures:
227235
- the client reaches `NOT_HANDSHAKING` while the server still sits in `NEED_UNWRAP` waiting
228236
for optional post-handshake traffic — treat an idle `NEED_UNWRAP` as settled;

0 commit comments

Comments
 (0)