Files
OpenShell/deploy/docker/Dockerfile.supervisor
Emilien MacchiandMrunal Patel 3e191558b3 feat(build): add glibc-static supervisor libc variant (#2682)
The supervisor binary runs inside sandbox images whose libc and glibc
version are unknown at build time, so it must be statically linked. Add
SUPERVISOR_LIBC to select between the default musl variant and a new
glibc-static variant that builds the GNU target with +crt-static.

glibc-static has no cross-compile path: zig cc accepts -static for
*-linux-gnu targets and emits a dynamically linked binary anyway. The
staging script therefore refuses a cross-arch request for that variant
rather than silently degrading linkage, and requires a native
per-architecture build.

Add verify-static-binary.sh, run after every supervisor build in both the
staging script and CI so linkage cannot regress unnoticed for either
variant. It inspects via readelf (or greadelf/llvm-readelf) and fails closed
rather than trusting the tool's exit status: every inspection must produce no
diagnostics, the input must be an executable ELF (ET_EXEC, or ET_DYN with
DF_1_PIE) whose PT_LOAD segments all lie within the file, whose dynamic table
agrees with PT_DYNAMIC, and which carries no PT_INTERP and no DT_NEEDED. That
rejects a dynamically linked, truncated, corrupt, non-ELF, or shared-object
input that naive parsing would misread as static. Hosts without any inspector
(e.g. macOS, which ships no binutils) skip with a warning; Linux, including
CI, requires one and fails closed.

No image or release workflow builds the glibc-static variant, so add a
dedicated supervisor-static-validate workflow that builds it on both
architectures and runs the verifier. rust-native-build.yml uses self-hosted
runners, which reject pull_request-triggered jobs, so it validates in the merge
queue and on pushes to main that touch the build inputs, plus a nightly
schedule, so the GNU + crt-static build branch cannot regress unnoticed.

The default is unchanged, so image, release, and CI behavior is identical.
Selecting glibc-static statically links LGPL glibc into a redistributed
binary, which is why it is opt-in.

Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
Co-authored-by: Mrunal Patel <mrunalp@gmail.com>
2026-08-11 17:43:09 +00:00

38 lines
1.6 KiB
Docker

# syntax=docker/dockerfile:1.4
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
# Supervisor image build.
#
# The final image carries the static `openshell-sandbox` binary used by Docker
# extraction, Podman image volumes, and the Kubernetes init container copy-self
# path. It also includes nftables so the Kubernetes supervisor sidecar can
# install pod-namespace egress enforcement rules.
#
# The Rust binary is built natively before this image build runs and staged at:
# deploy/docker/.build/prebuilt-binaries/<arch>/openshell-sandbox
#
# Use tasks/scripts/docker-build-image.sh supervisor (or `mise run build:docker:supervisor`)
# to stage the binary and build the image in one step. CI builds the binary
# per-architecture via the `rust-native-build.yml` workflow and uploads it as an
# artifact, which is downloaded into the same staging directory before the image
# build job runs.
#
# The binary is static under either supported libc variant (`SUPERVISOR_LIBC`:
# musl by default, or glibc-static), so this Alpine base runs it unchanged.
FROM alpine:3.22 AS supervisor
ARG TARGETARCH
RUN apk add --no-cache nftables iptables iptables-legacy
# --chmod=0555 restores execute bits after the actions/upload-artifact +
# download-artifact roundtrip strips them. Ownership stays root (0:0) for
# Podman image-volume mounts, while world-execute lets the Kubernetes
# network sidecar run this binary as the dedicated non-root proxy UID.
COPY --chmod=0555 deploy/docker/.build/prebuilt-binaries/${TARGETARCH}/openshell-sandbox /openshell-sandbox
ENTRYPOINT ["/openshell-sandbox"]