Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5bc9651e5 | ||
|
|
d41fa0c7e9 |
@@ -20,6 +20,39 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Resolve host bind sources for sibling containers
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
# This job's steps run inside the runner container while every
|
||||||
|
# `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
|
||||||
|
# mounts and reuse them in every later step.
|
||||||
|
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 "RENDEZVOUS_WORKSPACE_SOURCE=$GITHUB_WORKSPACE" >>"$GITHUB_ENV"
|
||||||
|
echo "RENDEZVOUS_TEMP_SOURCE=$RUNNER_TEMP" >>"$GITHUB_ENV"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
resolve_host_path() {
|
||||||
|
jq -er --arg path "$1" '
|
||||||
|
[ .[]
|
||||||
|
| .Destination as $destination
|
||||||
|
| select($path == $destination
|
||||||
|
or ($path | startswith($destination + "/"))) ]
|
||||||
|
| if length == 0 then
|
||||||
|
error("No runner mount exposes \($path) on the Docker host.")
|
||||||
|
else
|
||||||
|
sort_by(.Destination | length) | last
|
||||||
|
end
|
||||||
|
| (.Destination | length) as $prefix
|
||||||
|
| .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_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
|
||||||
with:
|
with:
|
||||||
@@ -36,14 +69,19 @@ jobs:
|
|||||||
|
|
||||||
- name: Validate tag and produce reproducible artifacts
|
- name: Validate tag and produce reproducible artifacts
|
||||||
shell: bash
|
shell: bash
|
||||||
|
env:
|
||||||
|
RENDEZVOUS_RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
version="${GITHUB_REF_NAME#v}"
|
version="${GITHUB_REF_NAME#v}"
|
||||||
./scripts/check-release-tag.sh "$GITHUB_REF_NAME"
|
./scripts/check-release-tag.sh "$GITHUB_REF_NAME"
|
||||||
previous_tag="$(git tag --merged HEAD^ --list 'v*.*.*' --sort=-version:refname | sed -n '1p')"
|
previous_tag="$(git tag --merged HEAD^ --list 'v*.*.*' --sort=-version:refname | sed -n '1p')"
|
||||||
|
# check-release-tag.sh already required this tag to point at HEAD, so
|
||||||
|
# it must be excluded before asking whether any earlier release exists.
|
||||||
|
unrelated_tag="$(git tag --list 'v*.*.*' | grep -vFx "$GITHUB_REF_NAME" | sed -n '1p' || true)"
|
||||||
if [[ -n "$previous_tag" ]]; then
|
if [[ -n "$previous_tag" ]]; then
|
||||||
./scripts/check-compatibility.sh "$previous_tag"
|
./scripts/check-compatibility.sh "$previous_tag"
|
||||||
elif [[ -n "$(git tag --list 'v*.*.*' | sed -n '1p')" ]]; then
|
elif [[ -n "$unrelated_tag" ]]; then
|
||||||
echo "No prior release tag is an ancestor of $GITHUB_REF_NAME." >&2
|
echo "No prior release tag is an ancestor of $GITHUB_REF_NAME." >&2
|
||||||
exit 1
|
exit 1
|
||||||
else
|
else
|
||||||
@@ -61,14 +99,15 @@ jobs:
|
|||||||
--user "$(id -u):$(id -g)" \
|
--user "$(id -u):$(id -g)" \
|
||||||
--env HOME="${RUNNER_TEMP}/release-home" \
|
--env HOME="${RUNNER_TEMP}/release-home" \
|
||||||
--env NUGET_PACKAGES="${RUNNER_TEMP}/nuget" \
|
--env NUGET_PACKAGES="${RUNNER_TEMP}/nuget" \
|
||||||
--volume "$GITHUB_WORKSPACE:/source" \
|
--volume "$RENDEZVOUS_WORKSPACE_SOURCE:/source" \
|
||||||
--volume "${RUNNER_TEMP}:${RUNNER_TEMP}" \
|
--volume "$RENDEZVOUS_TEMP_SOURCE:${RUNNER_TEMP}" \
|
||||||
--workdir /source \
|
--workdir /source \
|
||||||
"$release_builder" \
|
"$release_builder" \
|
||||||
./scripts/build-release.sh "$version" "${RUNNER_TEMP}/release/$version"
|
./scripts/build-release.sh "$version" "${RUNNER_TEMP}/release/$version"
|
||||||
./scripts/verify-real-consumers.sh "$version" "${RUNNER_TEMP}/release/$version"
|
./scripts/verify-real-consumers.sh "$version" "${RUNNER_TEMP}/release/$version"
|
||||||
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=${RUNNER_TEMP}/release/$version" >>"$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
|
||||||
@@ -97,8 +136,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 "$GITHUB_WORKSPACE:/source" \
|
--volume "$RENDEZVOUS_WORKSPACE_SOURCE:/source" \
|
||||||
--volume "${RUNNER_TEMP}:${RUNNER_TEMP}" \
|
--volume "$RENDEZVOUS_TEMP_SOURCE:${RUNNER_TEMP}" \
|
||||||
--workdir /source \
|
--workdir /source \
|
||||||
"$RENDEZVOUS_RELEASE_BUILDER" \
|
"$RENDEZVOUS_RELEASE_BUILDER" \
|
||||||
python3 eng/release_artifacts.py record-container-build \
|
python3 eng/release_artifacts.py record-container-build \
|
||||||
@@ -131,9 +170,7 @@ jobs:
|
|||||||
port_suffix="$(( ${GITHUB_RUN_ID:-$$} % 10000 ))"
|
port_suffix="$(( ${GITHUB_RUN_ID:-$$} % 10000 ))"
|
||||||
export RENDEZVOUS_HTTP_HOST_PORT="$(( 20000 + port_suffix ))"
|
export RENDEZVOUS_HTTP_HOST_PORT="$(( 20000 + port_suffix ))"
|
||||||
export RENDEZVOUS_UDP_HOST_PORT="$(( 40000 + port_suffix ))"
|
export RENDEZVOUS_UDP_HOST_PORT="$(( 40000 + port_suffix ))"
|
||||||
runner_workspace_source="$(docker inspect "$HOSTNAME" | jq -er \
|
runner_workspace_source="${RENDEZVOUS_WORKSPACE_SOURCE:?host workspace bind source was not resolved}"
|
||||||
--arg destination "$GITHUB_WORKSPACE" \
|
|
||||||
'.[0].Mounts[] | select(.Destination == $destination) | .Source')"
|
|
||||||
export RENDEZVOUS_CONFIG_SOURCE="$runner_workspace_source/deploy/compose/appsettings.Production.json"
|
export RENDEZVOUS_CONFIG_SOURCE="$runner_workspace_source/deploy/compose/appsettings.Production.json"
|
||||||
export RENDEZVOUS_SECRET_SOURCE="$runner_workspace_source/deploy/compose/secrets/signing-key"
|
export RENDEZVOUS_SECRET_SOURCE="$runner_workspace_source/deploy/compose/secrets/signing-key"
|
||||||
export RENDEZVOUS_IMAGE="git.finalfactory.de/heikyu/rendezvous:${RENDEZVOUS_VERSION}"
|
export RENDEZVOUS_IMAGE="git.finalfactory.de/heikyu/rendezvous:${RENDEZVOUS_VERSION}"
|
||||||
@@ -186,8 +223,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 "$GITHUB_WORKSPACE:/source" \
|
--volume "$RENDEZVOUS_WORKSPACE_SOURCE:/source" \
|
||||||
--volume "${RUNNER_TEMP}:${RUNNER_TEMP}" \
|
--volume "$RENDEZVOUS_TEMP_SOURCE:${RUNNER_TEMP}" \
|
||||||
--workdir /source \
|
--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 \
|
||||||
@@ -218,4 +255,6 @@ jobs:
|
|||||||
RENDEZVOUS_RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
RENDEZVOUS_RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
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_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"
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ All notable Rendezvous release changes are recorded here. Versions follow
|
|||||||
Semantic Versioning; HTTP, UDP, and connection-ticket format compatibility is
|
Semantic Versioning; HTTP, UDP, and connection-ticket format compatibility is
|
||||||
tracked separately and called out for every release.
|
tracked separately and called out for every release.
|
||||||
|
|
||||||
## 1.0.0 - 2026-07-16
|
## 1.0.0 - 2026-08-22
|
||||||
|
|
||||||
### Compatibility
|
### Compatibility
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,12 @@ image="$registry/heikyu/rendezvous:$version"
|
|||||||
token="${RENDEZVOUS_RELEASE_TOKEN:?RENDEZVOUS_RELEASE_TOKEN is required}"
|
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
|
||||||
|
# `docker run` starts containers on the host daemon, so bind sources must be
|
||||||
|
# host paths. The workflow resolves them once and exports them; a direct host
|
||||||
|
# run keeps the local paths.
|
||||||
|
workspace_source="${RENDEZVOUS_WORKSPACE_SOURCE:-$root}"
|
||||||
|
release_dir_source="${RENDEZVOUS_RELEASE_DIR_SOURCE:-$release_dir}"
|
||||||
docker_config="$(mktemp -d)"
|
docker_config="$(mktemp -d)"
|
||||||
curl_config="$(mktemp)"
|
curl_config="$(mktemp)"
|
||||||
release_request=""
|
release_request=""
|
||||||
@@ -33,11 +39,21 @@ for command in cosign curl docker dotnet jq; do
|
|||||||
}
|
}
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Publication is a one-way gate: Gitea package versions are immutable, so the
|
||||||
|
# signing material must be proven usable before anything is pushed. Never print
|
||||||
|
# the key or the probe output.
|
||||||
|
: "${COSIGN_PRIVATE_KEY:?COSIGN_PRIVATE_KEY is required}"
|
||||||
|
: "${COSIGN_PASSWORD:?COSIGN_PASSWORD is required}"
|
||||||
|
cosign public-key --key env://COSIGN_PRIVATE_KEY >/dev/null || {
|
||||||
|
echo "Configured cosign key could not be loaded; refusing to publish." >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
run_release_builder() {
|
run_release_builder() {
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
--user "$(id -u):$(id -g)" \
|
--user "$(id -u):$(id -g)" \
|
||||||
--volume "$root:/source:ro" \
|
--volume "$workspace_source:/source:ro" \
|
||||||
--volume "$release_dir:$release_dir" \
|
--volume "$release_dir_source:$release_dir" \
|
||||||
--workdir /source \
|
--workdir /source \
|
||||||
"$release_builder" "$@"
|
"$release_builder" "$@"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|||||||
version="${1:?usage: verify-real-consumers.sh VERSION RELEASE_DIRECTORY}"
|
version="${1:?usage: verify-real-consumers.sh VERSION RELEASE_DIRECTORY}"
|
||||||
release_dir="${2:?usage: verify-real-consumers.sh VERSION RELEASE_DIRECTORY}"
|
release_dir="${2:?usage: verify-real-consumers.sh VERSION RELEASE_DIRECTORY}"
|
||||||
manifest="$root/eng/consumer-revisions.json"
|
manifest="$root/eng/consumer-revisions.json"
|
||||||
|
# The pinned consumers live in private repositories, so release automation must
|
||||||
|
# authenticate. Keep the token in the environment git reads config from: it must
|
||||||
|
# never reach argv, the remote URL, or on-disk repository configuration.
|
||||||
|
token="${RENDEZVOUS_CONSUMER_TOKEN:-${RENDEZVOUS_RELEASE_TOKEN:-}}"
|
||||||
|
export GIT_TERMINAL_PROMPT=0
|
||||||
work="$(mktemp -d "${TMPDIR:-/tmp}/rendezvous-consumers.XXXXXX")"
|
work="$(mktemp -d "${TMPDIR:-/tmp}/rendezvous-consumers.XXXXXX")"
|
||||||
cleanup() {
|
cleanup() {
|
||||||
rm -rf "$work"
|
rm -rf "$work"
|
||||||
@@ -18,6 +23,20 @@ for command in dotnet git jq python3; do
|
|||||||
}
|
}
|
||||||
done
|
done
|
||||||
|
|
||||||
|
fetch_consumer_revision() {
|
||||||
|
local checkout="$1"
|
||||||
|
local repository="$2"
|
||||||
|
local revision="$3"
|
||||||
|
if [[ -z "$token" ]]; then
|
||||||
|
git -C "$checkout" fetch --quiet --depth 1 origin "$revision"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
GIT_CONFIG_COUNT=1 \
|
||||||
|
GIT_CONFIG_KEY_0="http.${repository}.extraHeader" \
|
||||||
|
GIT_CONFIG_VALUE_0="Authorization: token ${token}" \
|
||||||
|
git -C "$checkout" fetch --quiet --depth 1 origin "$revision"
|
||||||
|
}
|
||||||
|
|
||||||
python3 "$root/eng/release_artifacts.py" consumer-config \
|
python3 "$root/eng/release_artifacts.py" consumer-config \
|
||||||
--local-source "$release_dir" \
|
--local-source "$release_dir" \
|
||||||
--output "$work/NuGet.config"
|
--output "$work/NuGet.config"
|
||||||
@@ -31,7 +50,7 @@ for ((index = 0; index < count; index++)); do
|
|||||||
checkout="$work/$name"
|
checkout="$work/$name"
|
||||||
git -c init.defaultBranch=main init --quiet "$checkout"
|
git -c init.defaultBranch=main init --quiet "$checkout"
|
||||||
git -C "$checkout" remote add origin "$repository"
|
git -C "$checkout" remote add origin "$repository"
|
||||||
git -C "$checkout" fetch --quiet --depth 1 origin "$revision"
|
fetch_consumer_revision "$checkout" "$repository" "$revision"
|
||||||
GIT_LFS_SKIP_SMUDGE=1 git -C "$checkout" checkout --quiet --detach FETCH_HEAD
|
GIT_LFS_SKIP_SMUDGE=1 git -C "$checkout" checkout --quiet --detach FETCH_HEAD
|
||||||
[[ "$(git -C "$checkout" rev-parse HEAD)" == "$revision" ]] || {
|
[[ "$(git -C "$checkout" rev-parse HEAD)" == "$revision" ]] || {
|
||||||
echo "$name did not resolve the pinned consumer revision." >&2
|
echo "$name did not resolve the pinned consumer revision." >&2
|
||||||
|
|||||||
Reference in New Issue
Block a user