192 lines
6.8 KiB
Bash
Executable File
192 lines
6.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
umask 077
|
|
|
|
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
|
|
LABEL=${1:-"external-boundaries-$(date -u +%Y%m%d%H%M%S)"}
|
|
|
|
if [[ ! "$LABEL" =~ ^[a-z0-9][a-z0-9-]{0,39}$ ]]; then
|
|
echo "Run label must be 1-40 lowercase letters, numbers, or dashes." >&2
|
|
exit 1
|
|
fi
|
|
|
|
for command in chmod docker grep id jq openssl stat tr unlink; do
|
|
if ! command -v "$command" >/dev/null 2>&1; then
|
|
echo "Required command is unavailable: $command" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
run_id="${LABEL}-$$"
|
|
project="wnh_boundaries_$(printf '%s' "$run_id" | tr '-' '_')"
|
|
runtime_dir="$ROOT/tmp/external-boundaries/$run_id"
|
|
output_dir="$ROOT/output/external-boundaries/$LABEL"
|
|
env_file="$runtime_dir/.env"
|
|
|
|
if [[ -e "$output_dir" ]]; then
|
|
echo "Refusing to replace existing evidence directory: $output_dir" >&2
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "$runtime_dir" "$output_dir"
|
|
chmod 700 "$ROOT/tmp" "$ROOT/tmp/external-boundaries" "$runtime_dir" \
|
|
"$ROOT/output" "$ROOT/output/external-boundaries" "$output_dir"
|
|
|
|
oauth_client_id="local-$(openssl rand -hex 12)"
|
|
oauth_client_secret=$(openssl rand -hex 32)
|
|
push_bearer_token=$(openssl rand -hex 32)
|
|
metrics_token=$(openssl rand -hex 32)
|
|
database_password=$(openssl rand -hex 24)
|
|
secret_key_base=$(openssl rand -hex 64)
|
|
handover_secret=$(openssl rand -hex 32)
|
|
|
|
external_boundary_app_image="who-need-help:boundary-app-$run_id"
|
|
external_boundary_mock_image="who-need-help:boundary-mock-$run_id"
|
|
|
|
{
|
|
printf 'EXTERNAL_BOUNDARY_APP_IMAGE=%s\n' "$external_boundary_app_image"
|
|
printf 'EXTERNAL_BOUNDARY_MOCK_IMAGE=%s\n' "$external_boundary_mock_image"
|
|
printf 'EXTERNAL_BOUNDARY_OUTPUT_DIR=%s\n' "$output_dir"
|
|
printf 'EXTERNAL_BOUNDARY_HOST_UID=%s\n' "$(id -u)"
|
|
printf 'EXTERNAL_BOUNDARY_HOST_GID=%s\n' "$(id -g)"
|
|
printf 'EXTERNAL_OAUTH_CLIENT_ID=%s\n' "$oauth_client_id"
|
|
printf 'EXTERNAL_OAUTH_CLIENT_SECRET=%s\n' "$oauth_client_secret"
|
|
printf 'EXTERNAL_PUSH_BEARER_TOKEN=%s\n' "$push_bearer_token"
|
|
printf 'EXTERNAL_METRICS_TOKEN=%s\n' "$metrics_token"
|
|
printf 'EXTERNAL_POSTGRES_PASSWORD=%s\n' "$database_password"
|
|
printf 'EXTERNAL_DATABASE_URL=ecto://boundary:%s@boundary-db/boundary\n' "$database_password"
|
|
printf 'EXTERNAL_SECRET_KEY_BASE=%s\n' "$secret_key_base"
|
|
printf 'EXTERNAL_HANDOVER_SECRET=%s\n' "$handover_secret"
|
|
} >"$env_file"
|
|
chmod 600 "$env_file"
|
|
|
|
compose=(
|
|
docker compose
|
|
--env-file "$env_file"
|
|
-p "$project"
|
|
-f "$ROOT/compose.external-boundaries.yaml"
|
|
)
|
|
|
|
assert_project_scope() {
|
|
local container_id=$1
|
|
local observed_project
|
|
|
|
observed_project=$(
|
|
docker inspect --format '{{index .Config.Labels "com.docker.compose.project"}}' \
|
|
"$container_id"
|
|
)
|
|
|
|
if [[ "$observed_project" != "$project" ]]; then
|
|
echo "Container scope mismatch for $container_id." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
cleanup() {
|
|
local status=$?
|
|
trap - EXIT HUP INT TERM
|
|
|
|
if ((status != 0)); then
|
|
"${compose[@]}" logs --no-color >"$output_dir/compose.log" 2>&1 || true
|
|
fi
|
|
|
|
while IFS= read -r container_id; do
|
|
[[ -n "$container_id" ]] && assert_project_scope "$container_id"
|
|
done < <("${compose[@]}" ps --all --quiet 2>/dev/null || true)
|
|
|
|
"${compose[@]}" down --volumes >/dev/null 2>&1 || true
|
|
docker image rm "$external_boundary_app_image" "$external_boundary_mock_image" \
|
|
>/dev/null 2>&1 || true
|
|
|
|
if [[ -f "$env_file" ]]; then
|
|
unlink "$env_file"
|
|
fi
|
|
|
|
rmdir "$runtime_dir" >/dev/null 2>&1 || true
|
|
rmdir "$ROOT/tmp/external-boundaries" >/dev/null 2>&1 || true
|
|
|
|
exit "$status"
|
|
}
|
|
|
|
trap cleanup EXIT HUP INT TERM
|
|
|
|
"${compose[@]}" config --quiet
|
|
"${compose[@]}" build external-mock boundary-check >"$output_dir/build.log"
|
|
"${compose[@]}" up --detach --wait external-mock boundary-db boundary-migrate \
|
|
>"$output_dir/dependencies-up.log"
|
|
"${compose[@]}" up --detach --wait --scale boundary-worker=2 boundary-worker \
|
|
>"$output_dir/workers-up.log"
|
|
|
|
mapfile -t worker_ids < <("${compose[@]}" ps --quiet boundary-worker)
|
|
|
|
if ((${#worker_ids[@]} != 2)); then
|
|
echo "Expected two running boundary worker replicas; observed ${#worker_ids[@]}." >&2
|
|
exit 1
|
|
fi
|
|
|
|
for worker_id in "${worker_ids[@]}"; do
|
|
assert_project_scope "$worker_id"
|
|
test "$(docker inspect --format '{{.State.Running}}' "$worker_id")" = "true"
|
|
done
|
|
|
|
"${compose[@]}" run --rm --no-deps -T boundary-check \
|
|
>"$output_dir/drill.log" 2>&1
|
|
|
|
"${compose[@]}" exec -T external-mock \
|
|
python -c \
|
|
'import json, urllib.request; print(json.dumps(json.load(urllib.request.urlopen("http://127.0.0.1:8080/state")), sort_keys=True))' \
|
|
>"$output_dir/final-mock-state.json"
|
|
|
|
jq -e '
|
|
.status == "passed" and
|
|
.oauth.success == "passed" and
|
|
.oauth.state_mismatch_blocked_before_token == true and
|
|
.oauth.provider_rejection_blocked_before_token == true and
|
|
.oauth.one_time_code_replay_rejected == true and
|
|
.oauth.fresh_flow_retry_after_temporary_failure == "passed" and
|
|
.oauth.timeout_failed_closed == true and
|
|
.oauth.access_token_returned_to_application == false and
|
|
.google_oidc.success == "passed" and
|
|
.google_oidc.state_mismatch_blocked_before_token == true and
|
|
.google_oidc.one_time_code_replay_rejected == true and
|
|
.google_oidc.nonce_mismatch_rejected_after_signature_verification == true and
|
|
.google_oidc.unverified_email_rejected == true and
|
|
.google_oidc.access_token_returned_to_application == false and
|
|
.smtp.success == "passed" and
|
|
.smtp.permanent_rejection_not_retried == true and
|
|
.smtp.temporary_greeting_retried_once == true and
|
|
.smtp.timeout_failed_closed == true and
|
|
.smtp.repeated_submission_count == 2 and
|
|
.smtp.exactly_once_delivery_claimed == false and
|
|
.push.default_adapter_disabled == true and
|
|
.push.success == "passed" and
|
|
.push.permanent_rejection_not_retried == true and
|
|
.push.temporary_failure_retried_once == true and
|
|
.push.replay_deduplicated == true and
|
|
.push.timeout_after_accept_deduplicated == true and
|
|
.push.domain_workflow_integration == "passed" and
|
|
.push_product_integration.status == "passed" and
|
|
.push_product_integration.acceptance_delivery == "passed" and
|
|
.push_product_integration.chat_delivery == "passed" and
|
|
.push_product_integration.oban_retry_observed == true and
|
|
.push_product_integration.replay_deduplicated_before_transport == true and
|
|
.push_product_integration.message_content_excluded == true and
|
|
.push_product_integration.expected_worker_replicas == 2 and
|
|
.push_product_integration.database_scope == "isolated_ephemeral_volume"
|
|
' "$output_dir/summary.json" >/dev/null
|
|
|
|
for secret in "$oauth_client_secret" "$push_bearer_token" "$metrics_token" \
|
|
"$database_password" "$secret_key_base" "$handover_secret"; do
|
|
if grep -R -F -q -- "$secret" "$output_dir"; then
|
|
echo "Generated secret appeared in retained boundary evidence." >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
test "$(stat -c '%a' "$output_dir/summary.json")" = "600"
|
|
|
|
unset oauth_client_id oauth_client_secret push_bearer_token metrics_token \
|
|
database_password secret_key_base handover_secret
|
|
|
|
printf 'External boundary evidence: %s\n' "$output_dir"
|