fix(ci): isolate deployment smoke client (#1)
This commit is contained in:
+27
-16
@@ -144,18 +144,19 @@ jobs:
|
||||
set -euo pipefail
|
||||
compose_file="deploy/compose/compose.yaml"
|
||||
secret="deploy/compose/secrets/signing-key"
|
||||
compose_network=""
|
||||
cleanup() {
|
||||
if [[ -n "$compose_network" ]]; then
|
||||
docker network disconnect "$compose_network" "$HOSTNAME" >/dev/null 2>&1 || true
|
||||
fi
|
||||
RENDEZVOUS_UID=1654 RENDEZVOUS_GID=1654 \
|
||||
docker compose -f "$compose_file" down --volumes >/dev/null 2>&1 || true
|
||||
rm -f "$secret"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
umask 077
|
||||
install -d -m 0700 deploy/compose/secrets
|
||||
openssl rand -out "$secret" 32
|
||||
chmod 0600 "$secret"
|
||||
publisher_credential="$(RENDEZVOUS_SMOKE_LOCAL_KEY="$secret" \
|
||||
./scripts/mint-local-publisher-credential.sh)"
|
||||
export RENDEZVOUS_PUBLISHER_CREDENTIAL="$publisher_credential"
|
||||
chmod 0444 "$secret"
|
||||
export RENDEZVOUS_UID=1654
|
||||
export RENDEZVOUS_GID=1654
|
||||
@@ -168,6 +169,10 @@ jobs:
|
||||
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 SOURCE_REVISION_ID="$GITHUB_SHA"
|
||||
smoke_client_image="rendezvous-smoke-client:${GITHUB_SHA}"
|
||||
docker build --file eng/release-builder.Dockerfile \
|
||||
--target release-builder \
|
||||
--tag "$smoke_client_image" .
|
||||
docker compose -f "$compose_file" build \
|
||||
--build-arg SOURCE_REVISION_ID="$SOURCE_REVISION_ID"
|
||||
docker compose -f "$compose_file" up --no-build --detach
|
||||
@@ -175,27 +180,33 @@ jobs:
|
||||
test -n "$container_id"
|
||||
compose_network="$(docker inspect "$container_id" | jq -er \
|
||||
'.[0].NetworkSettings.Networks | keys[0]')"
|
||||
docker network connect "$compose_network" "$HOSTNAME"
|
||||
service_ip="$(docker inspect "$container_id" | jq -er \
|
||||
--arg network "$compose_network" \
|
||||
'.[0].NetworkSettings.Networks[$network].IPAddress')"
|
||||
export RENDEZVOUS_SMOKE_HTTP_URL="http://${service_ip}:8080/"
|
||||
export RENDEZVOUS_SMOKE_UDP_ENDPOINT="${service_ip}:9050"
|
||||
test "$(docker inspect --format '{{.Config.User}}' "$container_id")" = "1654:1654"
|
||||
test "$(docker inspect --format '{{.HostConfig.ReadonlyRootfs}}' "$container_id")" = "true"
|
||||
test "$(docker inspect --format '{{range .Mounts}}{{if eq .Destination "/app/appsettings.Production.json"}}{{.RW}}{{end}}{{end}}' "$container_id")" = "false"
|
||||
test "$(docker inspect --format '{{range .Mounts}}{{if eq .Destination "/run/secrets/rendezvous-signing-key"}}{{.RW}}{{end}}{{end}}' "$container_id")" = "false"
|
||||
for attempt in {1..100}; do
|
||||
if curl --fail --silent "${RENDEZVOUS_SMOKE_HTTP_URL%/}/health/ready" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
if (( attempt == 100 )); then
|
||||
docker compose -f "$compose_file" logs rendezvous
|
||||
exit 1
|
||||
fi
|
||||
docker run --rm \
|
||||
--network "$compose_network" \
|
||||
--user "$(id -u):$(id -g)" \
|
||||
--env HOME=/tmp \
|
||||
--env RENDEZVOUS_SMOKE_HTTP_URL="http://${service_ip}:8080/" \
|
||||
--env RENDEZVOUS_SMOKE_UDP_ENDPOINT="${service_ip}:9050" \
|
||||
--env RENDEZVOUS_PUBLISHER_CREDENTIAL \
|
||||
--volume "$runner_workspace_source:/source:ro" \
|
||||
--workdir /source \
|
||||
"$smoke_client_image" \
|
||||
bash -lc '
|
||||
for attempt in {1..300}; do
|
||||
curl --fail --silent "${RENDEZVOUS_SMOKE_HTTP_URL%/}/health/ready" >/dev/null 2>&1 && exec ./scripts/smoke-deployment.sh
|
||||
sleep 0.1
|
||||
done
|
||||
./scripts/smoke-deployment.sh
|
||||
exit 1
|
||||
' || {
|
||||
docker compose -f "$compose_file" logs rendezvous
|
||||
exit 1
|
||||
}
|
||||
docker compose -f "$compose_file" stop --timeout 40 rendezvous
|
||||
test "$(docker inspect --format '{{.State.Running}}' "$container_id")" = "false"
|
||||
test "$(docker inspect --format '{{.State.ExitCode}}' "$container_id")" = "0"
|
||||
|
||||
@@ -112,18 +112,19 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
secret="deploy/compose/secrets/signing-key"
|
||||
compose_network=""
|
||||
cleanup() {
|
||||
if [[ -n "$compose_network" ]]; then
|
||||
docker network disconnect "$compose_network" "$HOSTNAME" >/dev/null 2>&1 || true
|
||||
fi
|
||||
RENDEZVOUS_UID=1654 RENDEZVOUS_GID=1654 RENDEZVOUS_IMAGE="git.finalfactory.de/heikyu/rendezvous:${RENDEZVOUS_VERSION}" \
|
||||
docker compose -f deploy/compose/compose.yaml down --volumes >/dev/null 2>&1 || true
|
||||
rm -f "$secret"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
umask 077
|
||||
install -d -m 0700 deploy/compose/secrets
|
||||
openssl rand -out "$secret" 32
|
||||
chmod 0600 "$secret"
|
||||
publisher_credential="$(RENDEZVOUS_SMOKE_LOCAL_KEY="$secret" \
|
||||
./scripts/mint-local-publisher-credential.sh)"
|
||||
export RENDEZVOUS_PUBLISHER_CREDENTIAL="$publisher_credential"
|
||||
chmod 0444 "$secret"
|
||||
export RENDEZVOUS_UID=1654
|
||||
export RENDEZVOUS_GID=1654
|
||||
@@ -141,21 +142,29 @@ jobs:
|
||||
test -n "$container_id"
|
||||
compose_network="$(docker inspect "$container_id" | jq -er \
|
||||
'.[0].NetworkSettings.Networks | keys[0]')"
|
||||
docker network connect "$compose_network" "$HOSTNAME"
|
||||
service_ip="$(docker inspect "$container_id" | jq -er \
|
||||
--arg network "$compose_network" \
|
||||
'.[0].NetworkSettings.Networks[$network].IPAddress')"
|
||||
export RENDEZVOUS_SMOKE_HTTP_URL="http://${service_ip}:8080/"
|
||||
export RENDEZVOUS_SMOKE_UDP_ENDPOINT="${service_ip}:9050"
|
||||
for attempt in {1..100}; do
|
||||
curl --fail --silent "${RENDEZVOUS_SMOKE_HTTP_URL%/}/health/ready" >/dev/null 2>&1 && break
|
||||
if (( attempt == 100 )); then
|
||||
docker compose -f deploy/compose/compose.yaml logs rendezvous
|
||||
exit 1
|
||||
fi
|
||||
docker run --rm \
|
||||
--network "$compose_network" \
|
||||
--user "$(id -u):$(id -g)" \
|
||||
--env HOME=/tmp \
|
||||
--env RENDEZVOUS_SMOKE_HTTP_URL="http://${service_ip}:8080/" \
|
||||
--env RENDEZVOUS_SMOKE_UDP_ENDPOINT="${service_ip}:9050" \
|
||||
--env RENDEZVOUS_PUBLISHER_CREDENTIAL \
|
||||
--volume "$runner_workspace_source:/source:ro" \
|
||||
--workdir /source \
|
||||
"$RENDEZVOUS_RELEASE_BUILDER" \
|
||||
bash -lc '
|
||||
for attempt in {1..300}; do
|
||||
curl --fail --silent "${RENDEZVOUS_SMOKE_HTTP_URL%/}/health/ready" >/dev/null 2>&1 && exec ./scripts/smoke-deployment.sh
|
||||
sleep 0.1
|
||||
done
|
||||
./scripts/smoke-deployment.sh
|
||||
exit 1
|
||||
' || {
|
||||
docker compose -f deploy/compose/compose.yaml logs rendezvous
|
||||
exit 1
|
||||
}
|
||||
|
||||
- name: Scan candidate for high and critical vulnerabilities
|
||||
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0, post-incident safe SHA
|
||||
|
||||
@@ -49,9 +49,11 @@ Compose, then point `RENDEZVOUS_SMOKE_HTTP_URL` and
|
||||
and production-advertised service ports remain 8080/9050. Sibling-container CI
|
||||
runners may also set `RENDEZVOUS_CONFIG_SOURCE` and
|
||||
`RENDEZVOUS_SECRET_SOURCE` to host-visible absolute bind-source paths; local
|
||||
operators should normally keep the checked-in relative defaults. CI attaches
|
||||
its ephemeral job container to the isolated Compose network for smoke traffic;
|
||||
it does not widen the default loopback HTTP publication.
|
||||
operators should normally keep the checked-in relative defaults. CI starts its
|
||||
ephemeral smoke client directly on the isolated Compose network; it does not
|
||||
widen the default loopback HTTP publication. It mints the disposable publisher
|
||||
credential while the generated key is still owner-private, then makes the key
|
||||
read-only for the non-root service container.
|
||||
|
||||
`deploy/compose/appsettings.Production.json` is a local/private-bridge smoke
|
||||
profile, not an Internet template: TCP is published only on host loopback, the
|
||||
|
||||
@@ -179,10 +179,13 @@ public sealed class ReleaseCompatibilityTests
|
||||
string workflow = File.ReadAllText(Path.Combine(root, ".gitea/workflows", workflowName));
|
||||
Assert.Contains("GITHUB_RUN_ID", workflow, StringComparison.Ordinal);
|
||||
Assert.Contains("compose_network", workflow, StringComparison.Ordinal);
|
||||
Assert.Contains("docker network connect", workflow, StringComparison.Ordinal);
|
||||
Assert.Contains("docker network disconnect", workflow, StringComparison.Ordinal);
|
||||
Assert.Contains("\"$compose_network\" \"$HOSTNAME\"", workflow, StringComparison.Ordinal);
|
||||
Assert.Contains("--network \"$compose_network\"", workflow, StringComparison.Ordinal);
|
||||
Assert.Contains("publisher_credential", workflow, StringComparison.Ordinal);
|
||||
Assert.Contains("RENDEZVOUS_PUBLISHER_CREDENTIAL", workflow, StringComparison.Ordinal);
|
||||
Assert.Contains("for attempt in {1..300}", workflow, StringComparison.Ordinal);
|
||||
Assert.Contains("service_ip", workflow, StringComparison.Ordinal);
|
||||
Assert.Contains("http://${service_ip}:8080/", workflow, StringComparison.Ordinal);
|
||||
Assert.Contains("${service_ip}:9050", workflow, StringComparison.Ordinal);
|
||||
Assert.Contains("RENDEZVOUS_HTTP_HOST_PORT", workflow, StringComparison.Ordinal);
|
||||
Assert.Contains("RENDEZVOUS_UDP_HOST_PORT", workflow, StringComparison.Ordinal);
|
||||
Assert.Contains("RENDEZVOUS_SMOKE_HTTP_URL", workflow, StringComparison.Ordinal);
|
||||
|
||||
Reference in New Issue
Block a user