Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/scripts/cloud-run-simulation-entry-smoke.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash

set -euo pipefail

base_url="${1:?Simulation Entrypoint base URL is required}"
base_url="${base_url%/}"

curl --fail --silent --show-error "${base_url}/health" |
jq -e '.status == "healthy"' >/dev/null
curl --fail --silent --show-error "${base_url}/ready" |
jq -e '.status == "ready"' >/dev/null
curl --fail --silent --show-error "${base_url}/versions" >/dev/null
curl --fail --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--data '{"value": 1}' \
"${base_url}/ping" |
jq -e '.incremented == 2' >/dev/null
49 changes: 49 additions & 0 deletions .github/scripts/configure-cloud-run-simulation-entry-domains.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env bash

set -euo pipefail

gcloud_bin="${GCLOUD_BIN:-gcloud}"
project_id="${SIMULATION_ENTRYPOINT_GCP_PROJECT_ID:?SIMULATION_ENTRYPOINT_GCP_PROJECT_ID is required}"
region="${SIMULATION_ENTRYPOINT_GCP_REGION:-us-central1}"
production_domain="${SIMULATION_ENTRYPOINT_PRODUCTION_DOMAIN:-simulation.api.policyengine.org}"
staging_domain="${SIMULATION_ENTRYPOINT_STAGING_DOMAIN:-staging.simulation.api.policyengine.org}"
dry_run="${SIMULATION_ENTRYPOINT_DOMAINS_DRY_RUN:-0}"

run() {
if [ "${dry_run}" = "1" ]; then
printf '+'
printf ' %q' "$@"
printf '\n'
return 0
fi
"$@"
}

exists() {
if [ "${dry_run}" = "1" ]; then
return 1
fi
"$@" >/dev/null 2>&1
}

ensure_mapping() {
local service="${1:?service is required}"
local domain="${2:?domain is required}"

if ! exists "${gcloud_bin}" beta run domain-mappings describe \
--project "${project_id}" \
--region "${region}" \
--domain "${domain}"; then
run "${gcloud_bin}" beta run domain-mappings create \
--project "${project_id}" \
--region "${region}" \
--service "${service}" \
--domain "${domain}"
fi
}

ensure_mapping policyengine-simulation-entry-staging "${staging_domain}"
ensure_mapping policyengine-simulation-entry "${production_domain}"

printf '\nInspect the mappings for the DNS records that must be published:\n'
printf ' %s\n' "${staging_domain}" "${production_domain}"
70 changes: 0 additions & 70 deletions .github/scripts/modal-deploy-app.sh

This file was deleted.

62 changes: 62 additions & 0 deletions .github/scripts/set-cloud-run-simulation-entry-revision.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env bash

# Operator-run production/staging command. GitHub Actions intentionally never
# invokes this script or changes Cloud Run traffic.

set -euo pipefail

gcloud_bin="${GCLOUD_BIN:-gcloud}"
project_id="${SIMULATION_ENTRYPOINT_GCP_PROJECT_ID:?SIMULATION_ENTRYPOINT_GCP_PROJECT_ID is required}"
region="${SIMULATION_ENTRYPOINT_GCP_REGION:-us-central1}"
environment="${SIMULATION_ENTRYPOINT_DEPLOYMENT_ENVIRONMENT:?SIMULATION_ENTRYPOINT_DEPLOYMENT_ENVIRONMENT is required}"
revision="${SIMULATION_ENTRYPOINT_TARGET_REVISION:?SIMULATION_ENTRYPOINT_TARGET_REVISION is required}"
dry_run="${SIMULATION_ENTRYPOINT_TRAFFIC_DRY_RUN:-0}"

case "${environment}" in
staging)
service="policyengine-simulation-entry-staging"
;;
production)
service="policyengine-simulation-entry"
;;
*)
printf 'SIMULATION_ENTRYPOINT_DEPLOYMENT_ENVIRONMENT must be staging or production\n' >&2
exit 2
;;
esac

if [ "${dry_run}" = "1" ]; then
printf '+ %q' "${gcloud_bin}"
printf ' %q' run services update-traffic "${service}" \
--project "${project_id}" \
--region "${region}" \
--to-revisions "${revision}=100"
printf '\n'
exit 0
fi

revision_json="$("${gcloud_bin}" run revisions describe "${revision}" \
--project "${project_id}" \
--region "${region}" \
--format=json)"
revision_service="$(jq -r \
'.metadata.labels["serving.knative.dev/service"] // empty' \
<<<"${revision_json}")"

if [ "${revision_service}" != "${service}" ]; then
printf 'Revision %s belongs to %s, not %s\n' \
"${revision}" "${revision_service:-an unknown service}" "${service}" >&2
exit 2
fi

if ! jq -e \
'.status.conditions[]? | select(.type == "Ready" and .status == "True")' \
>/dev/null <<<"${revision_json}"; then
printf 'Revision %s is not Ready\n' "${revision}" >&2
exit 2
fi

"${gcloud_bin}" run services update-traffic "${service}" \
--project "${project_id}" \
--region "${region}" \
--to-revisions "${revision}=100"
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash
# Generate deployment summary for GitHub Actions
# Usage: ./modal-deployment-summary.sh <beta-result> <beta-url> <prod-result> <prod-url>
# Usage: ./simulation-deployment-summary.sh <beta-result> <beta-url> <prod-result> <prod-url>

set -euo pipefail

Expand All @@ -10,13 +10,13 @@ PROD_RESULT="${3:-skipped}"
PROD_URL="${4:-}"

{
echo "## Modal Deployment Summary"
echo "## Simulation API Deployment Summary"
echo ""

case "$BETA_RESULT" in
success)
echo "✅ **Beta deployment**: Success"
[ -n "$BETA_URL" ] && echo " - URL: $BETA_URL"
[ -n "$BETA_URL" ] && echo " - Candidate URL: $BETA_URL"
;;
skipped)
echo "⏭️ **Beta deployment**: Skipped"
Expand All @@ -30,14 +30,14 @@ PROD_URL="${4:-}"

case "$PROD_RESULT" in
success)
echo "✅ **Production deployment**: Success"
[ -n "$PROD_URL" ] && echo " - URL: $PROD_URL"
echo "✅ **Prod deployment**: Success"
[ -n "$PROD_URL" ] && echo " - Candidate URL: $PROD_URL"
;;
skipped)
echo "⏭️ **Production deployment**: Skipped"
echo "⏭️ **Prod deployment**: Skipped"
;;
*)
echo "❌ **Production deployment**: $PROD_RESULT"
echo "❌ **Prod deployment**: $PROD_RESULT"
;;
esac
} >> "$GITHUB_STEP_SUMMARY"
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash
# Run simulation integration tests
# Usage: ./modal-run-integ-tests.sh <environment> <base-url> [us-version] [uk-version]
# Run integration tests through the deployed Simulation Entrypoint.
# Usage: ./simulation-run-integ-tests.sh <environment> <base-url> [us-version] [uk-version]
# Environment: beta runs all tests, prod excludes beta_only tests

set -euo pipefail
Expand All @@ -17,15 +17,15 @@ truthy() {
esac
}

GATEWAY_AUTH_VARS=(
GATEWAY_AUTH_ISSUER
GATEWAY_AUTH_AUDIENCE
GATEWAY_AUTH_CLIENT_ID
GATEWAY_AUTH_CLIENT_SECRET
TEST_AUTH_VARS=(
SIMULATION_TEST_AUTH_ISSUER
SIMULATION_TEST_AUTH_AUDIENCE
SIMULATION_TEST_AUTH_CLIENT_ID
SIMULATION_TEST_AUTH_CLIENT_SECRET
)
present=()
missing=()
for var in "${GATEWAY_AUTH_VARS[@]}"; do
for var in "${TEST_AUTH_VARS[@]}"; do
if [ -n "${!var:-}" ]; then
present+=("$var")
else
Expand All @@ -34,36 +34,36 @@ for var in "${GATEWAY_AUTH_VARS[@]}"; do
done

if [ ${#present[@]} -gt 0 ] && [ ${#missing[@]} -gt 0 ]; then
echo "Gateway auth integration-test config is partial." >&2
echo "Simulation integration-test auth config is partial." >&2
echo " Present: ${present[*]-}" >&2
echo " Missing: ${missing[*]-}" >&2
exit 1
fi

SHOULD_MINT_TOKEN=0
if truthy "${GATEWAY_AUTH_REQUIRED:-}"; then
if truthy "${SIMULATION_TEST_AUTH_REQUIRED:-}"; then
if [ ${#missing[@]} -gt 0 ]; then
echo "GATEWAY_AUTH_REQUIRED is enabled but integration-test auth secrets are missing." >&2
echo "SIMULATION_TEST_AUTH_REQUIRED is enabled but auth secrets are missing." >&2
echo " Missing: ${missing[*]-}" >&2
exit 1
fi
SHOULD_MINT_TOKEN=1
elif [ ${#present[@]} -eq ${#GATEWAY_AUTH_VARS[@]} ]; then
elif [ ${#present[@]} -eq ${#TEST_AUTH_VARS[@]} ]; then
SHOULD_MINT_TOKEN=1
fi

ACCESS_TOKEN=""
if [ "$SHOULD_MINT_TOKEN" -eq 1 ]; then
ISSUER="${GATEWAY_AUTH_ISSUER%/}"
ISSUER="${SIMULATION_TEST_AUTH_ISSUER%/}"
TOKEN_URL="$ISSUER/oauth/token"

# Build the token-request JSON with Python so that any ", \, or newline in
# the client secret is encoded correctly (Auth0-generated secrets are random
# strings that routinely contain characters that break a shell heredoc).
TOKEN_REQUEST_JSON=$(
CLIENT_ID="$GATEWAY_AUTH_CLIENT_ID" \
CLIENT_SECRET="$GATEWAY_AUTH_CLIENT_SECRET" \
AUDIENCE="$GATEWAY_AUTH_AUDIENCE" \
CLIENT_ID="$SIMULATION_TEST_AUTH_CLIENT_ID" \
CLIENT_SECRET="$SIMULATION_TEST_AUTH_CLIENT_SECRET" \
AUDIENCE="$SIMULATION_TEST_AUTH_AUDIENCE" \
python3 -c '
import json, os
print(json.dumps({
Expand Down Expand Up @@ -100,12 +100,12 @@ print(token)
fi

cd projects/policyengine-apis-integ
uv sync --extra test
uv sync --extra test --frozen

export simulation_integ_test_base_url="$BASE_URL"

if [ -n "${GATEWAY_AUTH_REQUIRED:-}" ]; then
export simulation_integ_test_gateway_auth_required="$GATEWAY_AUTH_REQUIRED"
if [ -n "${SIMULATION_TEST_AUTH_REQUIRED:-}" ]; then
export simulation_integ_test_gateway_auth_required="$SIMULATION_TEST_AUTH_REQUIRED"
fi

if [ -n "$ACCESS_TOKEN" ]; then
Expand Down
Loading