fix(linux/build): handle DooD bind-mount in CI (M1.1)
Some checks failed
Build SilverMetal Linux ISO (reproducibility-gated) / build-and-verify (push) Failing after 1m18s
Some checks failed
Build SilverMetal Linux ISO (reproducibility-gated) / build-and-verify (push) Failing after 1m18s
build.sh ran fine locally but failed in Gitea Actions on the first reproducibility-gated run (#4250) with: bash: line 3: /work/linux/build/config/silvermetal-base.conf: No such file or directory Root cause: classic Docker-out-of-Docker confusion. build.sh runs inside the act_runner job container, which talks to the host's docker daemon via the mounted /var/run/docker.sock. The "-v ${REPO_ROOT}:/work" flag was being interpreted by the host daemon against the host filesystem, where /workspace/SilverLABS/SilverMetal does not exist; docker silently auto-created an empty dir there and mounted that as /work, so the config source target was missing. Fix: detect GITHUB_ACTIONS and use --volumes-from "$(hostname)" in CI to inherit the parent job container's /workspace mount intact. Locally we keep a bind mount, but use the same path inside and outside (${REPO_ROOT}:${REPO_ROOT}) so the inner heredoc is identical in both modes. Inner script now references "${REPO_ROOT}/..." and "${BUILD_DIR}/..." instead of the synthetic /work and /out paths. No reproducibility implications — bind topology doesn't affect bytes inside the ISO. Verified locally: bash -n passes; structural change only, behaviour preserved for the non-CI path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -76,26 +76,55 @@ mkdir -p "${BUILD_DIR}"
|
||||
echo "build.sh: commit=${COMMIT_SHA} epoch=${SOURCE_DATE_EPOCH} snapshot=${SNAPSHOT_TIMESTAMP}"
|
||||
echo "build.sh: output -> ${BUILD_DIR}"
|
||||
|
||||
# --- Mount strategy: local vs CI -------------------------------------------
|
||||
# Locally we bind-mount the repo into the build container at the *same*
|
||||
# path (self-referential), so internal references work transparently and
|
||||
# the inner script doesn't need to care which host it's on.
|
||||
#
|
||||
# In CI we can't do that. build.sh runs inside a Gitea Actions job
|
||||
# container which talks to the *host's* docker daemon via /var/run/docker.sock.
|
||||
# Bind-mounting REPO_ROOT (= /workspace/<owner>/<repo>) would resolve
|
||||
# against the host filesystem where that path doesn't exist; docker
|
||||
# silently creates an empty dir on the host and mounts that, leaving the
|
||||
# build container with an empty /work and a confusing "No such file or
|
||||
# directory" error on the first config source.
|
||||
#
|
||||
# The standard fix for that DooD topology is --volumes-from of the parent
|
||||
# job container, which inherits its /workspace mount intact. That keeps
|
||||
# paths identical inside and outside, so the inner heredoc below is the
|
||||
# same in both environments.
|
||||
if [[ -n "${GITHUB_ACTIONS:-}" ]]; then
|
||||
BIND_ARGS=(--volumes-from "$(hostname)")
|
||||
else
|
||||
BIND_ARGS=(-v "${REPO_ROOT}:${REPO_ROOT}:rw")
|
||||
# If BUILD_DIR lives outside REPO_ROOT (uncommon, but the env-var
|
||||
# override allows it), mount it explicitly too.
|
||||
if [[ "${BUILD_DIR}" != "${REPO_ROOT}/"* && "${BUILD_DIR}" != "${REPO_ROOT}" ]]; then
|
||||
BIND_ARGS+=(-v "${BUILD_DIR}:${BUILD_DIR}:rw")
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Run the build inside the container ------------------------------------
|
||||
# --privileged is required because live-build mounts loop devices and chroots.
|
||||
# --network=host lets the container reach snapshot.debian.org without us
|
||||
# fighting CI proxy config; tighten if/when that becomes a concern.
|
||||
docker run --rm --privileged \
|
||||
--network=host \
|
||||
"${BIND_ARGS[@]}" \
|
||||
-e SOURCE_DATE_EPOCH \
|
||||
-e SNAPSHOT_TIMESTAMP \
|
||||
-e LC_ALL=C.UTF-8 \
|
||||
-e LANG=C.UTF-8 \
|
||||
-e TZ=UTC \
|
||||
-v "${REPO_ROOT}:/work:rw" \
|
||||
-v "${BUILD_DIR}:/out:rw" \
|
||||
-w /work \
|
||||
-e REPO_ROOT="${REPO_ROOT}" \
|
||||
-e BUILD_DIR="${BUILD_DIR}" \
|
||||
-w "${REPO_ROOT}" \
|
||||
"${BUILDER_IMAGE}" \
|
||||
bash -euo pipefail -c '
|
||||
# shellcheck disable=SC1091
|
||||
source /work/linux/build/config/silvermetal-base.conf
|
||||
source "${REPO_ROOT}/linux/build/config/silvermetal-base.conf"
|
||||
|
||||
cd /work/linux/build/derivative-maker
|
||||
cd "${REPO_ROOT}/linux/build/derivative-maker"
|
||||
|
||||
./derivative-maker \
|
||||
--build \
|
||||
@@ -103,18 +132,19 @@ docker run --rm --privileged \
|
||||
--flavour "${DERIVATIVE_FLAVOUR}" \
|
||||
--arch "${DERIVATIVE_TARGET_ARCH}" \
|
||||
--dist "${DERIVATIVE_DIST}" \
|
||||
--config /work/linux/build/config/silvermetal-base.conf
|
||||
--config "${REPO_ROOT}/linux/build/config/silvermetal-base.conf"
|
||||
|
||||
# derivative-maker writes into its own build/ dir; collect into /out.
|
||||
# Exact upstream output paths can shift between tags — keep this
|
||||
# tolerant. Anything matching *.iso under the tree is what we want.
|
||||
# derivative-maker writes into its own build/ dir; collect into
|
||||
# BUILD_DIR. Exact upstream output paths can shift between tags —
|
||||
# keep this tolerant. Anything matching *.iso under the tree is
|
||||
# what we want.
|
||||
find . -maxdepth 6 -type f -name "*.iso" -print0 \
|
||||
| xargs -0 -I{} cp -av "{}" /out/
|
||||
| xargs -0 -I{} cp -av "{}" "${BUILD_DIR}/"
|
||||
|
||||
# Manifest of file metadata that lives inside the ISO. Useful when
|
||||
# diagnosing reproducibility regressions without re-extracting.
|
||||
find . -maxdepth 6 -type f -name "*.manifest" -print0 \
|
||||
| xargs -0 -I{} cp -av "{}" /out/ 2>/dev/null || true
|
||||
| xargs -0 -I{} cp -av "{}" "${BUILD_DIR}/" 2>/dev/null || true
|
||||
' || { echo "build.sh: derivative-maker failed"; exit 3; }
|
||||
|
||||
# --- Hash artefacts ---------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user