fix(release): share sibling paths through the workspace (#1)
The release job stopped at the bind-source gate. RUNNER_TEMP is container-internal on this runner and no runner mount exposes it on the Docker host, so no sibling container could ever share it; only the workspace is host-mounted. Move every path shared between the runner's shell steps and its sibling containers under $GITHUB_WORKSPACE/.release-work: the release directory, the release builder's HOME and NuGet cache, both candidate image tars, and the container SPDX inventory. Resolution now maps the workspace alone to its host path, and each sibling binds that source at $GITHUB_WORKSPACE and works from there instead of /source, so a shared path is the same string on both sides of the boundary. publish-release.sh follows with a single bind and requires the release directory to sit inside the workspace. Ignore .release-work in Git so the tag gate's cleanliness check stays true while artifacts accumulate, and in Docker so artifacts written between the two candidate builds cannot alter the build context the byte-comparison gate depends on. Skip it in the dependency inventory as well, keeping the restored package cache out of the license policy scan.
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
.agents
|
.agents
|
||||||
**/bin
|
**/bin
|
||||||
**/obj
|
**/obj
|
||||||
|
.release-work
|
||||||
TestResults
|
TestResults
|
||||||
deploy/compose/secrets
|
deploy/compose/secrets
|
||||||
deploy/compose/.smoke.env
|
deploy/compose/.smoke.env
|
||||||
|
|||||||
@@ -20,38 +20,36 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Resolve host bind sources for sibling containers
|
- name: Resolve the host bind source for sibling containers
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
# This job's steps run inside the runner container while every
|
# This job's steps run inside the runner container while every
|
||||||
# `docker run` starts a sibling container on the host daemon, so bind
|
# `docker run` starts a sibling container on the host daemon, so bind
|
||||||
# sources must be host paths. Resolve them once from the runner's own
|
# sources must be host paths. The workspace is the only runner mount
|
||||||
# mounts and reuse them in every later step.
|
# backed by the host, so every path shared with a sibling lives under
|
||||||
|
# it and a single bind source is resolved once here. Siblings mount
|
||||||
|
# that source at $GITHUB_WORKSPACE, which keeps every shared path the
|
||||||
|
# same string on both sides of the boundary.
|
||||||
|
echo "RENDEZVOUS_WORK_DIR=$GITHUB_WORKSPACE/.release-work" >>"$GITHUB_ENV"
|
||||||
if ! mounts="$(docker inspect "$HOSTNAME" 2>/dev/null | jq -c '.[0].Mounts')"; then
|
if ! mounts="$(docker inspect "$HOSTNAME" 2>/dev/null | jq -c '.[0].Mounts')"; then
|
||||||
echo "Runner is not containerized; using workspace and temp paths as host paths."
|
echo "Runner is not containerized; using the workspace path as its own host path."
|
||||||
echo "RENDEZVOUS_WORKSPACE_SOURCE=$GITHUB_WORKSPACE" >>"$GITHUB_ENV"
|
echo "RENDEZVOUS_WORKSPACE_SOURCE=$GITHUB_WORKSPACE" >>"$GITHUB_ENV"
|
||||||
echo "RENDEZVOUS_TEMP_SOURCE=$RUNNER_TEMP" >>"$GITHUB_ENV"
|
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
resolve_host_path() {
|
workspace_source="$(jq -er --arg path "$GITHUB_WORKSPACE" '
|
||||||
jq -er --arg path "$1" '
|
[ .[]
|
||||||
[ .[]
|
| .Destination as $destination
|
||||||
| .Destination as $destination
|
| select($path == $destination
|
||||||
| select($path == $destination
|
or ($path | startswith($destination + "/"))) ]
|
||||||
or ($path | startswith($destination + "/"))) ]
|
| if length == 0 then
|
||||||
| if length == 0 then
|
error("No runner mount exposes \($path) on the Docker host.")
|
||||||
error("No runner mount exposes \($path) on the Docker host.")
|
else
|
||||||
else
|
sort_by(.Destination | length) | last
|
||||||
sort_by(.Destination | length) | last
|
end
|
||||||
end
|
| (.Destination | length) as $prefix
|
||||||
| (.Destination | length) as $prefix
|
| .Source + $path[$prefix:]' <<<"$mounts")"
|
||||||
| .Source + $path[$prefix:]' <<<"$mounts"
|
|
||||||
}
|
|
||||||
workspace_source="$(resolve_host_path "$GITHUB_WORKSPACE")"
|
|
||||||
temp_source="$(resolve_host_path "$RUNNER_TEMP")"
|
|
||||||
echo "RENDEZVOUS_WORKSPACE_SOURCE=$workspace_source" >>"$GITHUB_ENV"
|
echo "RENDEZVOUS_WORKSPACE_SOURCE=$workspace_source" >>"$GITHUB_ENV"
|
||||||
echo "RENDEZVOUS_TEMP_SOURCE=$temp_source" >>"$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Install pinned .NET SDKs
|
- name: Install pinned .NET SDKs
|
||||||
uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
|
uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
|
||||||
@@ -94,20 +92,19 @@ jobs:
|
|||||||
--target release-builder \
|
--target release-builder \
|
||||||
--load \
|
--load \
|
||||||
--tag "$release_builder" .
|
--tag "$release_builder" .
|
||||||
mkdir -p "${RUNNER_TEMP}/release-home" "${RUNNER_TEMP}/nuget"
|
release_dir="$RENDEZVOUS_WORK_DIR/release/$version"
|
||||||
|
mkdir -p "$RENDEZVOUS_WORK_DIR/release-home" "$RENDEZVOUS_WORK_DIR/nuget"
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
--user "$(id -u):$(id -g)" \
|
--user "$(id -u):$(id -g)" \
|
||||||
--env HOME="${RUNNER_TEMP}/release-home" \
|
--env HOME="$RENDEZVOUS_WORK_DIR/release-home" \
|
||||||
--env NUGET_PACKAGES="${RUNNER_TEMP}/nuget" \
|
--env NUGET_PACKAGES="$RENDEZVOUS_WORK_DIR/nuget" \
|
||||||
--volume "$RENDEZVOUS_WORKSPACE_SOURCE:/source" \
|
--volume "$RENDEZVOUS_WORKSPACE_SOURCE:$GITHUB_WORKSPACE" \
|
||||||
--volume "$RENDEZVOUS_TEMP_SOURCE:${RUNNER_TEMP}" \
|
--workdir "$GITHUB_WORKSPACE" \
|
||||||
--workdir /source \
|
|
||||||
"$release_builder" \
|
"$release_builder" \
|
||||||
./scripts/build-release.sh "$version" "${RUNNER_TEMP}/release/$version"
|
./scripts/build-release.sh "$version" "$release_dir"
|
||||||
./scripts/verify-real-consumers.sh "$version" "${RUNNER_TEMP}/release/$version"
|
./scripts/verify-real-consumers.sh "$version" "$release_dir"
|
||||||
echo "RENDEZVOUS_VERSION=$version" >>"$GITHUB_ENV"
|
echo "RENDEZVOUS_VERSION=$version" >>"$GITHUB_ENV"
|
||||||
echo "RENDEZVOUS_RELEASE_DIR=${RUNNER_TEMP}/release/$version" >>"$GITHUB_ENV"
|
echo "RENDEZVOUS_RELEASE_DIR=$release_dir" >>"$GITHUB_ENV"
|
||||||
echo "RENDEZVOUS_RELEASE_DIR_SOURCE=${RENDEZVOUS_TEMP_SOURCE}/release/$version" >>"$GITHUB_ENV"
|
|
||||||
echo "RENDEZVOUS_RELEASE_BUILDER=$release_builder" >>"$GITHUB_ENV"
|
echo "RENDEZVOUS_RELEASE_BUILDER=$release_builder" >>"$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Build exact container candidate
|
- name: Build exact container candidate
|
||||||
@@ -124,8 +121,10 @@ jobs:
|
|||||||
--build-arg SOURCE_REVISION_ID="$GITHUB_SHA"
|
--build-arg SOURCE_REVISION_ID="$GITHUB_SHA"
|
||||||
)
|
)
|
||||||
release_tag="git.finalfactory.de/heikyu/rendezvous:${RENDEZVOUS_VERSION}"
|
release_tag="git.finalfactory.de/heikyu/rendezvous:${RENDEZVOUS_VERSION}"
|
||||||
image_one="${RUNNER_TEMP}/rendezvous-image-1.tar"
|
# .release-work is excluded from the build context, so the tar written
|
||||||
image_two="${RUNNER_TEMP}/rendezvous-image-2.tar"
|
# by the first build cannot change the context the second one sees.
|
||||||
|
image_one="$RENDEZVOUS_WORK_DIR/rendezvous-image-1.tar"
|
||||||
|
image_two="$RENDEZVOUS_WORK_DIR/rendezvous-image-2.tar"
|
||||||
docker buildx build "${common[@]}" --tag "$release_tag" \
|
docker buildx build "${common[@]}" --tag "$release_tag" \
|
||||||
--output "type=docker,dest=$image_one,rewrite-timestamp=true" .
|
--output "type=docker,dest=$image_one,rewrite-timestamp=true" .
|
||||||
docker buildx build "${common[@]}" --tag "$release_tag" \
|
docker buildx build "${common[@]}" --tag "$release_tag" \
|
||||||
@@ -136,9 +135,8 @@ jobs:
|
|||||||
buildkit_version="$(docker buildx inspect --bootstrap | sed -n 's/.*BuildKit version: *//p' | sed -n '1p')"
|
buildkit_version="$(docker buildx inspect --bootstrap | sed -n 's/.*BuildKit version: *//p' | sed -n '1p')"
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
--user "$(id -u):$(id -g)" \
|
--user "$(id -u):$(id -g)" \
|
||||||
--volume "$RENDEZVOUS_WORKSPACE_SOURCE:/source" \
|
--volume "$RENDEZVOUS_WORKSPACE_SOURCE:$GITHUB_WORKSPACE" \
|
||||||
--volume "$RENDEZVOUS_TEMP_SOURCE:${RUNNER_TEMP}" \
|
--workdir "$GITHUB_WORKSPACE" \
|
||||||
--workdir /source \
|
|
||||||
"$RENDEZVOUS_RELEASE_BUILDER" \
|
"$RENDEZVOUS_RELEASE_BUILDER" \
|
||||||
python3 eng/release_artifacts.py record-container-build \
|
python3 eng/release_artifacts.py record-container-build \
|
||||||
--provenance "$RENDEZVOUS_RELEASE_DIR/release-provenance.json" \
|
--provenance "$RENDEZVOUS_RELEASE_DIR/release-provenance.json" \
|
||||||
@@ -184,8 +182,8 @@ jobs:
|
|||||||
--env RENDEZVOUS_SMOKE_HTTP_URL=http://127.0.0.1:8080/ \
|
--env RENDEZVOUS_SMOKE_HTTP_URL=http://127.0.0.1:8080/ \
|
||||||
--env RENDEZVOUS_SMOKE_UDP_ENDPOINT=127.0.0.1:9050 \
|
--env RENDEZVOUS_SMOKE_UDP_ENDPOINT=127.0.0.1:9050 \
|
||||||
--env RENDEZVOUS_PUBLISHER_CREDENTIAL \
|
--env RENDEZVOUS_PUBLISHER_CREDENTIAL \
|
||||||
--volume "$runner_workspace_source:/source:ro" \
|
--volume "$runner_workspace_source:$GITHUB_WORKSPACE:ro" \
|
||||||
--workdir /source \
|
--workdir "$GITHUB_WORKSPACE" \
|
||||||
"$RENDEZVOUS_RELEASE_BUILDER" \
|
"$RENDEZVOUS_RELEASE_BUILDER" \
|
||||||
bash -lc '
|
bash -lc '
|
||||||
for attempt in {1..180}; do
|
for attempt in {1..180}; do
|
||||||
@@ -223,9 +221,8 @@ jobs:
|
|||||||
source_date_epoch="$(git show -s --format=%ct HEAD)"
|
source_date_epoch="$(git show -s --format=%ct HEAD)"
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
--user "$(id -u):$(id -g)" \
|
--user "$(id -u):$(id -g)" \
|
||||||
--volume "$RENDEZVOUS_WORKSPACE_SOURCE:/source" \
|
--volume "$RENDEZVOUS_WORKSPACE_SOURCE:$GITHUB_WORKSPACE" \
|
||||||
--volume "$RENDEZVOUS_TEMP_SOURCE:${RUNNER_TEMP}" \
|
--workdir "$GITHUB_WORKSPACE" \
|
||||||
--workdir /source \
|
|
||||||
"$RENDEZVOUS_RELEASE_BUILDER" \
|
"$RENDEZVOUS_RELEASE_BUILDER" \
|
||||||
bash -c 'python3 eng/release_artifacts.py normalize-container-sbom \
|
bash -c 'python3 eng/release_artifacts.py normalize-container-sbom \
|
||||||
--file "$1/FinalFactory.Rendezvous.Container.$2.spdx.json" \
|
--file "$1/FinalFactory.Rendezvous.Container.$2.spdx.json" \
|
||||||
@@ -256,5 +253,4 @@ jobs:
|
|||||||
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
|
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
|
||||||
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
|
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
|
||||||
RENDEZVOUS_WORKSPACE_SOURCE: ${{ env.RENDEZVOUS_WORKSPACE_SOURCE }}
|
RENDEZVOUS_WORKSPACE_SOURCE: ${{ env.RENDEZVOUS_WORKSPACE_SOURCE }}
|
||||||
RENDEZVOUS_RELEASE_DIR_SOURCE: ${{ env.RENDEZVOUS_RELEASE_DIR_SOURCE }}
|
|
||||||
run: ./scripts/publish-release.sh "$RENDEZVOUS_VERSION" "$RENDEZVOUS_RELEASE_DIR"
|
run: ./scripts/publish-release.sh "$RENDEZVOUS_VERSION" "$RENDEZVOUS_RELEASE_DIR"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ TestResults/
|
|||||||
*.userosscache
|
*.userosscache
|
||||||
deploy/compose/.smoke.env
|
deploy/compose/.smoke.env
|
||||||
artifacts/
|
artifacts/
|
||||||
|
.release-work/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
deploy/compose/secrets/*
|
deploy/compose/secrets/*
|
||||||
|
|||||||
@@ -30,7 +30,10 @@ def load_json(path: pathlib.Path):
|
|||||||
def dependency_inventory(root: pathlib.Path):
|
def dependency_inventory(root: pathlib.Path):
|
||||||
dependencies = {}
|
dependencies = {}
|
||||||
for lock_path in sorted(root.glob("**/packages.lock.json")):
|
for lock_path in sorted(root.glob("**/packages.lock.json")):
|
||||||
if any(part in {"bin", "obj", "artifacts"} for part in lock_path.parts):
|
if any(
|
||||||
|
part in {"bin", "obj", "artifacts", ".release-work"}
|
||||||
|
for part in lock_path.parts
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
lock = load_json(lock_path)
|
lock = load_json(lock_path)
|
||||||
for framework in lock.get("dependencies", {}).values():
|
for framework in lock.get("dependencies", {}).values():
|
||||||
|
|||||||
@@ -11,11 +11,21 @@ token="${RENDEZVOUS_RELEASE_TOKEN:?RENDEZVOUS_RELEASE_TOKEN is required}"
|
|||||||
username="${RENDEZVOUS_RELEASE_USERNAME:?RENDEZVOUS_RELEASE_USERNAME is required}"
|
username="${RENDEZVOUS_RELEASE_USERNAME:?RENDEZVOUS_RELEASE_USERNAME is required}"
|
||||||
release_builder="${RENDEZVOUS_RELEASE_BUILDER:?RENDEZVOUS_RELEASE_BUILDER is required}"
|
release_builder="${RENDEZVOUS_RELEASE_BUILDER:?RENDEZVOUS_RELEASE_BUILDER is required}"
|
||||||
# Sibling-container runners execute this script inside a container while
|
# Sibling-container runners execute this script inside a container while
|
||||||
# `docker run` starts containers on the host daemon, so bind sources must be
|
# `docker run` starts containers on the host daemon, so the bind source must be
|
||||||
# host paths. The workflow resolves them once and exports them; a direct host
|
# a host path. The workflow resolves the workspace once and exports it; a direct
|
||||||
# run keeps the local paths.
|
# host run keeps the local path. Only the workspace is bound, so the release
|
||||||
|
# directory has to live inside it, and binding it back onto its own path keeps
|
||||||
|
# every shared path identical on both sides of the boundary.
|
||||||
workspace_source="${RENDEZVOUS_WORKSPACE_SOURCE:-$root}"
|
workspace_source="${RENDEZVOUS_WORKSPACE_SOURCE:-$root}"
|
||||||
release_dir_source="${RENDEZVOUS_RELEASE_DIR_SOURCE:-$release_dir}"
|
[[ -d "$release_dir" ]] || {
|
||||||
|
echo "Release directory does not exist: $release_dir" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
release_dir="$(cd "$release_dir" && pwd)"
|
||||||
|
if [[ "$release_dir" != "$root"/* ]]; then
|
||||||
|
echo "Release directory must live inside the workspace: $release_dir" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
docker_config="$(mktemp -d)"
|
docker_config="$(mktemp -d)"
|
||||||
curl_config="$(mktemp)"
|
curl_config="$(mktemp)"
|
||||||
release_request=""
|
release_request=""
|
||||||
@@ -52,9 +62,8 @@ cosign public-key --key env://COSIGN_PRIVATE_KEY >/dev/null || {
|
|||||||
run_release_builder() {
|
run_release_builder() {
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
--user "$(id -u):$(id -g)" \
|
--user "$(id -u):$(id -g)" \
|
||||||
--volume "$workspace_source:/source:ro" \
|
--volume "$workspace_source:$root" \
|
||||||
--volume "$release_dir_source:$release_dir" \
|
--workdir "$root" \
|
||||||
--workdir /source \
|
|
||||||
"$release_builder" "$@"
|
"$release_builder" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user