Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion tools/build-packages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,16 @@ therefore shadows the published one in your Docker daemon until you
The build runs inside a hash-tagged **build-env image** (`env-<hash>`) based on
`manylinux_2_28`. `build-dependency-image.sh` resolves it from the local Docker
cache, this repository's GHCR package, or a local build, reusing the cached
image on later runs.
image on later runs. It also accepts `--with-ca-certs`, which applies when the
image is built rather than found or pulled.

`--with-ca-certs` (on either script) propagates the host's CA trust into the
build for corporate TLS gateways, using
[yscope-dev-utils' ca-trust library][ca-trust]. It's off by default and nothing
is baked into any image: the bundle is mounted only for the steps that need the
network, so CI needs no CA configuration at all.

[ca-trust]: ../yscope-dev-utils/exports/docker/ca-trust/README.md

Build state is cached under `.cache/` (`maven/`, `ccache/`,
`fetchcontent/<hash>/`, and `build/<hash>/` for persisted CMake/build state),
Expand Down
30 changes: 28 additions & 2 deletions tools/build-packages/build-dependency-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
# docker run --rm -v "$(pwd):/src" -w /src "${image}" \
# task velox-connector:build-with-installed-deps
#
# Options:
# --with-ca-certs Propagate the host's CA trust into the image build, for
# builds behind a corporate TLS gateway. Only applies when
# the image is built rather than found or pulled. Nothing is
# baked into the image. Off by default.
#
# Requires: docker (with buildx), git, and sha256sum or shasum.

set -o errexit
Expand All @@ -29,6 +35,20 @@ host_platform() {

main() {
local build_env_hash image image_repo platform pull_err
local with_ca_certs=0

while [[ $# -gt 0 ]]; do
case $1 in
--with-ca-certs)
with_ca_certs=1
shift
;;
*)
echo >&2 "ERROR: unknown option: $1"
exit 1
;;
esac
done

echo >&2 "==> Deriving build-env hash..."
build_env_hash="$(derive_build_env_hash)"
Expand All @@ -40,13 +60,19 @@ main() {
echo >&2 " image: ${image}"

if docker image inspect "${image}" &>/dev/null; then
if (( with_ca_certs )); then
echo >&2 " Note: --with-ca-certs applies only when the image is built; reusing cache."
fi
echo >&2 "==> Found in local Docker cache."
echo "${image}"
return
fi

echo >&2 "==> Checking repository registry..."
if pull_err="$(docker pull "${image}" 2>&1)"; then
if (( with_ca_certs )); then
echo >&2 " Note: --with-ca-certs applies only when the image is built; pulled instead."
fi
echo >&2 "==> Pulled from repository registry."
echo "${image}"
return
Expand All @@ -56,9 +82,9 @@ main() {
printf '%s\n' "${pull_err}" | sed 's/^/ /' >&2

echo >&2 "==> Image not available — building from scratch..."
build_image "${image}" "${platform}" "--load"
build_image "${image}" "${platform}" "--load" "${with_ca_certs}"
echo >&2 "==> Built locally."
echo "${image}"
}

main
main "$@"
28 changes: 13 additions & 15 deletions tools/build-packages/build-packages.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ set -o pipefail
src="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." &>/dev/null && pwd)"
# shellcheck source=tools/build-packages/internal/build-cache/host.sh
source "${src}/tools/build-packages/internal/build-cache/host.sh"
# shellcheck source=tools/build-packages/internal/ca-trust/host.sh
source "${src}/tools/build-packages/internal/ca-trust/host.sh"

show_help() {
cat <<'EOF'
Expand Down Expand Up @@ -84,7 +82,11 @@ echo "==> Initializing submodules..."
git -C "${src}" submodule update --init --recursive

echo "==> Resolving build-env image..."
image=$("${src}/tools/build-packages/build-dependency-image.sh")
ca_certs_flag=()
if (( with_ca_certs )); then
ca_certs_flag=(--with-ca-certs)
fi
image=$("${src}/tools/build-packages/build-dependency-image.sh" ${ca_certs_flag[@]+"${ca_certs_flag[@]}"})
# FetchContent build state is compatible only with the image inputs identified
# by this hash.
image_hash="${image##*:env-}"
Expand All @@ -109,19 +111,15 @@ prepare_build_cache "${src}/.cache" "${image_hash}"
trust_mount_args=()
if (( with_ca_certs )); then
readonly TRUST_STAGE="${stage_dir}/trust"
# Sourced here rather than at the top of the script: the submodule is only
# guaranteed to exist after the `submodule update` above, and every
# invocation that doesn't use --with-ca-certs (including --help) must work
# on a fresh clone.
# shellcheck source=tools/yscope-dev-utils/exports/docker/ca-trust/host.sh
source "${src}/tools/yscope-dev-utils/exports/docker/ca-trust/host.sh"
echo "==> Staging temporary container CA trust bundle..."
stage_host_ca_bundle "${TRUST_STAGE}"
if [[ ! -f "${TRUST_STAGE}/ca-bundle.pem" \
|| ! -r "${TRUST_STAGE}/ca-bundle.pem" \
|| ! -s "${TRUST_STAGE}/ca-bundle.pem" ]]; then
echo >&2 "ERROR: --with-ca-certs did not produce a usable host CA bundle"
exit 1
fi
trust_mount_args=(
--mount "type=bind,src=${TRUST_STAGE},dst=${CA_TRUST_CONTAINER_DIR}"
--env "CA_TRUST_DIR=${CA_TRUST_CONTAINER_DIR}"
--env "CA_TRUST_JVM=1"
)
ca_trust_stage_or_fail "${TRUST_STAGE}"
CA_TRUST_JVM=1 ca_trust_add_run_args trust_mount_args "${TRUST_STAGE}"
fi

host_uid=$(id -u)
Expand Down
44 changes: 27 additions & 17 deletions tools/build-packages/dependency-image/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,39 +1,49 @@
# syntax=docker/dockerfile:1

FROM quay.io/pypa/manylinux_2_28:latest
# Empty default for the `ca_trust` build context, so networked RUN steps below
# resolve their mount when no host CA trust is supplied. `build_image` overrides
# this stage with a staged directory when --with-ca-certs is passed; without it
# the mount is empty, the guard falls through, and the image keeps its own
# distro trust store. See yscope-dev-utils exports/docker/ca-trust.
FROM scratch AS ca_trust

ARG HOST_CA_BUNDLE=/run/secrets/host-ca
ARG HOST_CA_ENV=/usr/local/share/clp-plugin-presto-connector/use-host-ca.sh
FROM quay.io/pypa/manylinux_2_28:latest
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# When available, expose the host CA bundle only to networked build steps via
# tool-specific environment variables. This supports local corporate builds
# without baking host CA certificates into the final image.
COPY tools/build-packages/dependency-image/use-host-ca.sh ${HOST_CA_ENV}
# NOTE: these duplicate the ca-trust library's CA_TRUST_CONTAINER_DIR and
# CA_TRUST_BUNDLE_FILENAME, which a Dockerfile can't read; keep them in sync.
# container.sh is sourced directly rather than via container-exec.sh because this
# base image's /bin/sh is bash. A base without that (Debian, Alpine) must switch to
# `bash /run/ca-trust/container-exec.sh <cmd>`.
# Where the ca_trust context is mounted during networked RUN steps. Declared as
# an ARG so container.sh finds the staged bundle; nothing is baked into the
# image and the mount disappears with the step.
ARG CA_TRUST_DIR=/run/ca-trust
ARG CA_TRUST_BUNDLE=/run/ca-trust/ca-bundle.pem
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# Install OS packages missing from the manylinux base image.
# dnf talks to libcurl directly and ignores CURL_CA_BUNDLE/SSL_CERT_FILE, so
# it needs its own --setopt=sslcacert pointed at the host CA bundle.
RUN --mount=type=bind,from=host-ca,source=host-ca,target=${HOST_CA_BUNDLE} \
. "${HOST_CA_ENV}" \
RUN --mount=type=bind,from=ca_trust,target=/run/ca-trust \
if [ -e /run/ca-trust/container.sh ]; then . /run/ca-trust/container.sh; fi \
&& dnf_sslcacert_opt="" \
&& if [ -s "${HOST_CA_BUNDLE}" ]; then \
dnf_sslcacert_opt="--setopt=sslcacert=${HOST_CA_BUNDLE}"; \
&& if [ -s "${CA_TRUST_BUNDLE}" ]; then \
dnf_sslcacert_opt="--setopt=sslcacert=${CA_TRUST_BUNDLE}"; \
fi \
&& dnf install -y --setopt=install_weak_deps=False ${dnf_sslcacert_opt} \
ccache dpkg gettext git java-17-openjdk-devel libcurl-devel libevent-devel \
libunwind-devel ninja-build openssl-devel patchelf python3-pip rpm-build \
&& dnf clean all

RUN --mount=type=bind,from=host-ca,source=host-ca,target=${HOST_CA_BUNDLE} \
. "${HOST_CA_ENV}" \
RUN --mount=type=bind,from=ca_trust,target=/run/ca-trust \
if [ -e /run/ca-trust/container.sh ]; then . /run/ca-trust/container.sh; fi \
&& python3 -m pip install --no-cache-dir 'pip==21.3.1' \
&& python3 -m pip install --no-cache-dir 'cmake==3.28.*'

ARG GO_TASK_VERSION=v3.48.0
ARG TARGETARCH
RUN --mount=type=bind,from=host-ca,source=host-ca,target=${HOST_CA_BUNDLE} \
RUN --mount=type=bind,from=ca_trust,target=/run/ca-trust \
set -euxo pipefail; \
. "${HOST_CA_ENV}"; \
if [ -e /run/ca-trust/container.sh ]; then . /run/ca-trust/container.sh; fi; \
mkdir -p /opt/go-task/bin; \
curl -fsSL "https://github.com/go-task/task/releases/download/${GO_TASK_VERSION}/task_linux_${TARGETARCH}.tar.gz" \
| tar xz -C /opt/go-task/bin task
Expand All @@ -46,6 +56,6 @@ ENV TASK_TEMP_DIR=/opt/clp-plugin-presto-connector/.task

# Build one dependency at a time to avoid excessive memory usage from parallel builds.
RUN --mount=type=bind,source=.,target=/repo,readonly \
--mount=type=bind,from=host-ca,source=host-ca,target=${HOST_CA_BUNDLE} \
. "${HOST_CA_ENV}" \
--mount=type=bind,from=ca_trust,target=/run/ca-trust \
if [ -e /run/ca-trust/container.sh ]; then . /run/ca-trust/container.sh; fi \
&& task --concurrency 1 -d /repo velox-connector:deps:install-all
7 changes: 0 additions & 7 deletions tools/build-packages/dependency-image/use-host-ca.sh

This file was deleted.

85 changes: 38 additions & 47 deletions tools/build-packages/dependency-image/utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -85,65 +85,56 @@ derive_build_env_hash() {
)
}

# Stages the host CA bundle into the temporary Docker build context.
#
# Args: <destination-path>
_stage_host_ca_bundle() {
local dest="${1:?_stage_host_ca_bundle requires a destination path}"
local ca_bundle_candidates=(
"${SSL_CERT_FILE:-}"
/etc/ssl/certs/ca-certificates.crt
/etc/pki/tls/certs/ca-bundle.crt
/etc/ssl/cert.pem
)

local src
for src in "${ca_bundle_candidates[@]}"; do
[[ -f "${src}" && -s "${src}" ]] || continue
echo >&2 "==> Staging host CA bundle: ${src} -> ${dest}"
if ! cp "${src}" "${dest}"; then
echo >&2 "ERROR: failed to stage host CA bundle: ${src}"
return 1
fi
return 0
done

echo >&2 "==> No host CA bundle found; continuing without host CA context."
return 1
}

# ── Docker build ──────────────────────────────────────────────────────────────

# Builds the dependency image.
#
# Args:
# $1 image tag — e.g. ghcr.io/owner/build-env:env-<hash>
# $2 platform — linux/amd64 or linux/arm64
# $3 output flag — --push (registry) or --load (local docker)
# $1 image tag — e.g. ghcr.io/owner/build-env:env-<hash>
# $2 platform — linux/amd64 or linux/arm64
# $3 output flag — --push (registry) or --load (local docker)
# $4 with CA certs — 1 to propagate the host's CA trust (optional, off by
# default). For local builds behind a corporate TLS
# gateway; CI has no such gateway and passes nothing, so
# the Dockerfile's empty `ca_trust` stage applies and the
# image keeps its own distro trust store.
#
# Requires: docker buildx, git
build_image() {
local tag="$1" platform="$2" output="$3"
local tag="$1" platform="$2" output="$3" with_ca_certs="${4:-0}"

# Expose the host CA bundle as a narrow named build context so the Dockerfile
# can bind-mount it during networked RUN steps without baking it into image
# layers. Use a real context instead of a BuildKit secret because corporate CA
# bundles can exceed BuildKit's 500KiB secret limit.
local ca_stage; ca_stage=$(mktemp -d)
# stdout of this function is the caller's image ref; keep git chatter off it.
ensure_yscope_dev_utils_submodule >&2

local build_cmd=(
docker buildx build
--platform "${platform}"
--tag "${tag}"
"${output}"
-f "${_REPO_ROOT}/tools/build-packages/dependency-image/Dockerfile"
)

# String compare, not (( )): an arithmetic context name-resolves a non-numeric
# argument and aborts under `set -u`.
if [[ "${with_ca_certs}" != "1" ]]; then
build_cmd+=("${_REPO_ROOT}")
"${build_cmd[@]}"
return
fi
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# shellcheck source=tools/yscope-dev-utils/exports/docker/ca-trust/host.sh
source "${_REPO_ROOT}/tools/yscope-dev-utils/exports/docker/ca-trust/host.sh"

local ca_stage
ca_stage="$(mktemp -d)"
(
trap 'rm -rf "${ca_stage}"' EXIT

local ca_bundle="${ca_stage}/host-ca"
_stage_host_ca_bundle "${ca_bundle}" || : > "${ca_bundle}"

ensure_yscope_dev_utils_submodule
ca_trust_stage_or_fail "${ca_stage}"
ca_trust_stage_build_context "${ca_stage}"
ca_trust_add_build_args build_cmd "${ca_stage}"

docker buildx build \
--platform "${platform}" \
--build-context "host-ca=${ca_stage}" \
--tag "${tag}" \
"${output}" \
-f "${_REPO_ROOT}/tools/build-packages/dependency-image/Dockerfile" \
"${_REPO_ROOT}"
build_cmd+=("${_REPO_ROOT}")
"${build_cmd[@]}"
)
}
58 changes: 0 additions & 58 deletions tools/build-packages/internal/ca-trust/README.md

This file was deleted.

Loading
Loading