2026-09-22 18:41:17 +02:00
|
|
|
# The linux-x64 development loop for the CultMesh native QUIC bridge: build it
|
|
|
|
|
# and run its runtime-lifetime scenarios directly. Not a release builder — the
|
|
|
|
|
# shipped Linux artifact comes from the workflow (see
|
Commit the container the linux-x64 entries are honest in
The image the bridge is built and mutated in existed nowhere in the repository,
and the recipe that stood in for it installed a C++ toolchain and no JavaScript
runtime — so the container could not run the harness that checks the bridge it
had just built. It is a file now, pinned to the same debian:13 digest as the
release workflow, carrying ninja, Node, setarch and MsQuic's four runtime
dependencies.
The harness configures with `-G Ninja` on linux-x64, which is what
scripts/build-quic-native.sh uses. CMake's Linux default is Makefiles, the image
carries ninja rather than make, and the default configured nothing at all: the
first run in the committed container died in cmake. It said so, because the
control now prints what the child said, which is the whole point of that change.
The seccomp requirement is stated where someone hitting it will read it — the
bridge's README, beside the recipe — rather than being knowledge the runner
assumes its caller already has.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 00:37:16 +02:00
|
|
|
# docs/typescript-quic-realtime-cut.md).
|
|
|
|
|
#
|
2026-09-22 18:41:17 +02:00
|
|
|
# See native/GameCult.Mesh.Quic.Native/README.md for the build and run commands
|
|
|
|
|
# (CULTMESH_QUIC_BUILD_TESTS, CULTMESH_QUIC_DEBUG_ASSERTS, and the scenario
|
|
|
|
|
# names the built binary takes as its first argument).
|
Commit the container the linux-x64 entries are honest in
The image the bridge is built and mutated in existed nowhere in the repository,
and the recipe that stood in for it installed a C++ toolchain and no JavaScript
runtime — so the container could not run the harness that checks the bridge it
had just built. It is a file now, pinned to the same debian:13 digest as the
release workflow, carrying ninja, Node, setarch and MsQuic's four runtime
dependencies.
The harness configures with `-G Ninja` on linux-x64, which is what
scripts/build-quic-native.sh uses. CMake's Linux default is Makefiles, the image
carries ninja rather than make, and the default configured nothing at all: the
first run in the committed container died in cmake. It said so, because the
control now prints what the child said, which is the whole point of that change.
The seccomp requirement is stated where someone hitting it will read it — the
bridge's README, beside the recipe — rather than being knowledge the runner
assumes its caller already has.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 00:37:16 +02:00
|
|
|
#
|
|
|
|
|
# docker build -t cultlib-quic-native-dev -f scripts/quic-native-linux-dev.Dockerfile scripts
|
2026-09-17 02:44:47 +02:00
|
|
|
#
|
2026-09-22 18:41:17 +02:00
|
|
|
# From the repository root; the mount for `docker run` is that root wherever it
|
|
|
|
|
# is: `${PWD}` in PowerShell, `$(pwd)` in a POSIX shell.
|
Commit the container the linux-x64 entries are honest in
The image the bridge is built and mutated in existed nowhere in the repository,
and the recipe that stood in for it installed a C++ toolchain and no JavaScript
runtime — so the container could not run the harness that checks the bridge it
had just built. It is a file now, pinned to the same debian:13 digest as the
release workflow, carrying ninja, Node, setarch and MsQuic's four runtime
dependencies.
The harness configures with `-G Ninja` on linux-x64, which is what
scripts/build-quic-native.sh uses. CMake's Linux default is Makefiles, the image
carries ninja rather than make, and the default configured nothing at all: the
first run in the committed container died in cmake. It said so, because the
control now prints what the child said, which is the whole point of that change.
The seccomp requirement is stated where someone hitting it will read it — the
bridge's README, beside the recipe — rather than being knowledge the runner
assumes its caller already has.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 00:37:16 +02:00
|
|
|
#
|
2026-09-22 18:41:17 +02:00
|
|
|
# `--security-opt seccomp=unconfined` is not optional and not caution. A
|
Commit the container the linux-x64 entries are honest in
The image the bridge is built and mutated in existed nowhere in the repository,
and the recipe that stood in for it installed a C++ toolchain and no JavaScript
runtime — so the container could not run the harness that checks the bridge it
had just built. It is a file now, pinned to the same debian:13 digest as the
release workflow, carrying ninja, Node, setarch and MsQuic's four runtime
dependencies.
The harness configures with `-G Ninja` on linux-x64, which is what
scripts/build-quic-native.sh uses. CMake's Linux default is Makefiles, the image
carries ninja rather than make, and the default configured nothing at all: the
first run in the committed container died in cmake. It said so, because the
control now prints what the child said, which is the whole point of that change.
The seccomp requirement is stated where someone hitting it will read it — the
bridge's README, beside the recipe — rather than being knowledge the runner
assumes its caller already has.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 00:37:16 +02:00
|
|
|
# ThreadSanitizer configuration needs the process's address space where it
|
2026-09-22 18:41:17 +02:00
|
|
|
# expects it, so a TSan run is re-executed under `setarch -R`, which asks the
|
Commit the container the linux-x64 entries are honest in
The image the bridge is built and mutated in existed nowhere in the repository,
and the recipe that stood in for it installed a C++ toolchain and no JavaScript
runtime — so the container could not run the harness that checks the bridge it
had just built. It is a file now, pinned to the same debian:13 digest as the
release workflow, carrying ninja, Node, setarch and MsQuic's four runtime
dependencies.
The harness configures with `-G Ninja` on linux-x64, which is what
scripts/build-quic-native.sh uses. CMake's Linux default is Makefiles, the image
carries ninja rather than make, and the default configured nothing at all: the
first run in the committed container died in cmake. It said so, because the
control now prints what the child said, which is the whole point of that change.
The seccomp requirement is stated where someone hitting it will read it — the
bridge's README, beside the recipe — rather than being knowledge the runner
assumes its caller already has.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 00:37:16 +02:00
|
|
|
# kernel for personality(ADDR_NO_RANDOMIZE). Docker's default seccomp profile
|
|
|
|
|
# denies that call, and without it ThreadSanitizer dies before main with
|
2026-09-22 18:41:17 +02:00
|
|
|
# "unexpected memory mapping" — a configuration that never starts, not a
|
|
|
|
|
# scenario that passed.
|
Commit the container the linux-x64 entries are honest in
The image the bridge is built and mutated in existed nowhere in the repository,
and the recipe that stood in for it installed a C++ toolchain and no JavaScript
runtime — so the container could not run the harness that checks the bridge it
had just built. It is a file now, pinned to the same debian:13 digest as the
release workflow, carrying ninja, Node, setarch and MsQuic's four runtime
dependencies.
The harness configures with `-G Ninja` on linux-x64, which is what
scripts/build-quic-native.sh uses. CMake's Linux default is Makefiles, the image
carries ninja rather than make, and the default configured nothing at all: the
first run in the committed container died in cmake. It said so, because the
control now prints what the child said, which is the whole point of that change.
The seccomp requirement is stated where someone hitting it will read it — the
bridge's README, beside the recipe — rather than being knowledge the runner
assumes its caller already has.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 00:37:16 +02:00
|
|
|
#
|
|
|
|
|
# Pinned by digest, not by the moving tag: the artifact is the toolchain that
|
|
|
|
|
# made it.
|
|
|
|
|
FROM debian:13@sha256:f324c7ff54321e8d9c588493a20244965938ce0aa50bbd1022d38010e9ffc4b1
|
|
|
|
|
|
|
|
|
|
# cmake, ninja and g++ build the bridge and its scenario runner; curl,
|
|
|
|
|
# ca-certificates and dpkg fetch and unpack the pinned libmsquic deb;
|
2026-09-22 18:41:17 +02:00
|
|
|
# util-linux carries setarch, needed to re-execute the TSan scenarios under
|
|
|
|
|
# ADDR_NO_RANDOMIZE. The four libraries are MsQuic's own runtime dependencies,
|
2026-09-23 12:33:12 +02:00
|
|
|
# which the bridge does not vendor. gnupg is needed only to fetch the NodeSource
|
|
|
|
|
# key below.
|
Commit the container the linux-x64 entries are honest in
The image the bridge is built and mutated in existed nowhere in the repository,
and the recipe that stood in for it installed a C++ toolchain and no JavaScript
runtime — so the container could not run the harness that checks the bridge it
had just built. It is a file now, pinned to the same debian:13 digest as the
release workflow, carrying ninja, Node, setarch and MsQuic's four runtime
dependencies.
The harness configures with `-G Ninja` on linux-x64, which is what
scripts/build-quic-native.sh uses. CMake's Linux default is Makefiles, the image
carries ninja rather than make, and the default configured nothing at all: the
first run in the committed container died in cmake. It said so, because the
control now prints what the child said, which is the whole point of that change.
The seccomp requirement is stated where someone hitting it will read it — the
bridge's README, beside the recipe — rather than being knowledge the runner
assumes its caller already has.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 00:37:16 +02:00
|
|
|
RUN apt-get update \
|
|
|
|
|
&& apt-get install -y --no-install-recommends \
|
2026-09-23 12:33:12 +02:00
|
|
|
bash ca-certificates cmake curl dpkg g++ ninja-build util-linux gnupg \
|
Commit the container the linux-x64 entries are honest in
The image the bridge is built and mutated in existed nowhere in the repository,
and the recipe that stood in for it installed a C++ toolchain and no JavaScript
runtime — so the container could not run the harness that checks the bridge it
had just built. It is a file now, pinned to the same debian:13 digest as the
release workflow, carrying ninja, Node, setarch and MsQuic's four runtime
dependencies.
The harness configures with `-G Ninja` on linux-x64, which is what
scripts/build-quic-native.sh uses. CMake's Linux default is Makefiles, the image
carries ninja rather than make, and the default configured nothing at all: the
first run in the committed container died in cmake. It said so, because the
control now prints what the child said, which is the whole point of that change.
The seccomp requirement is stated where someone hitting it will read it — the
bridge's README, beside the recipe — rather than being knowledge the runner
assumes its caller already has.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 00:37:16 +02:00
|
|
|
libssl3t64 libnuma1 libxdp1 libnl-route-3-200 \
|
|
|
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
|
|
2026-09-23 12:33:12 +02:00
|
|
|
# Node 24 and the .NET 10 SDK: the Cut 4 QUIC realtime plane's own npm tests
|
|
|
|
|
# and the C#-to-TS interop lane run in this image too, so it needs to build the
|
|
|
|
|
# bridge and then exercise it from both runtimes without a second image.
|
|
|
|
|
RUN curl -fsSL https://deb.nodesource.com/setup_24.x | bash - \
|
|
|
|
|
&& apt-get install -y --no-install-recommends nodejs \
|
|
|
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
|
|
|
|
|
|
RUN curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh \
|
|
|
|
|
&& bash /tmp/dotnet-install.sh --channel 10.0 --install-dir /usr/share/dotnet \
|
|
|
|
|
&& rm /tmp/dotnet-install.sh \
|
|
|
|
|
&& ln -s /usr/share/dotnet/dotnet /usr/local/bin/dotnet
|
|
|
|
|
ENV DOTNET_ROOT=/usr/share/dotnet
|
|
|
|
|
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
2026-09-23 14:39:05 +02:00
|
|
|
|
|
|
|
|
# .NET's own System.Net.Quic P/Invokes into "libmsquic" and resolves it
|
|
|
|
|
# through the loader's normal search path, not through this repo's
|
|
|
|
|
# CULTMESH_QUIC_NATIVE_DIR (that is the Node bridge's own binary directory,
|
|
|
|
|
# never the system loader path). Without this, the interop lane's C# peer
|
|
|
|
|
# fails QuicListener.IsSupported with PlatformNotSupportedException. `dpkg -i`
|
|
|
|
|
# (rather than the build script's `dpkg-deb -x` into a build-local directory)
|
|
|
|
|
# installs the same pinned package into /usr/lib/x86_64-linux-gnu and runs
|
|
|
|
|
# ldconfig, so it is resolvable process-wide. Same version, same digest as
|
|
|
|
|
# scripts/build-quic-native.sh.
|
|
|
|
|
RUN curl -fsSL -o /tmp/libmsquic.deb \
|
|
|
|
|
https://packages.microsoft.com/debian/13/prod/pool/main/libm/libmsquic/libmsquic_2.5.9_amd64.deb \
|
|
|
|
|
&& echo "1baa61ade0b7b4a99f6dcb6b00d9aedb12b5566d00918a325be7425e878e51ba /tmp/libmsquic.deb" | sha256sum -c - \
|
|
|
|
|
&& dpkg -i /tmp/libmsquic.deb \
|
|
|
|
|
&& rm /tmp/libmsquic.deb \
|
|
|
|
|
&& ldconfig
|
2026-09-23 13:14:44 +02:00
|
|
|
# This minimal Debian image carries no ICU package, and .NET's runtime
|
|
|
|
|
# FailFasts on startup without one. The interop peer already parses every
|
|
|
|
|
# argument through CultureInfo.InvariantCulture, so globalization-invariant
|
|
|
|
|
# mode costs it nothing; installing an ICU package would be the alternative,
|
|
|
|
|
# but Microsoft's own guidance for a minimal container is this flag.
|
|
|
|
|
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
|
2026-09-23 12:33:12 +02:00
|
|
|
|
Commit the container the linux-x64 entries are honest in
The image the bridge is built and mutated in existed nowhere in the repository,
and the recipe that stood in for it installed a C++ toolchain and no JavaScript
runtime — so the container could not run the harness that checks the bridge it
had just built. It is a file now, pinned to the same debian:13 digest as the
release workflow, carrying ninja, Node, setarch and MsQuic's four runtime
dependencies.
The harness configures with `-G Ninja` on linux-x64, which is what
scripts/build-quic-native.sh uses. CMake's Linux default is Makefiles, the image
carries ninja rather than make, and the default configured nothing at all: the
first run in the committed container died in cmake. It said so, because the
control now prints what the child said, which is the whole point of that change.
The seccomp requirement is stated where someone hitting it will read it — the
bridge's README, beside the recipe — rather than being knowledge the runner
assumes its caller already has.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 00:37:16 +02:00
|
|
|
WORKDIR /src
|