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
2 changes: 1 addition & 1 deletion .github/request-simulation-model-versions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ set -euo pipefail
# versions are optional compatibility checks that should resolve to the same
# gateway app as the .py bundle route.

GATEWAY_URL="${SIMULATION_API_URL:-https://policyengine--policyengine-simulation-gateway-web-app.modal.run}"
GATEWAY_URL="${SIMULATION_ENTRYPOINT_URL:-https://policyengine--policyengine-simulation-gateway-web-app.modal.run}"

usage() {
echo "Usage: $0 -py <policyengine_version> [-us <us_version>] [-uk <uk_version>]"
Expand Down
5 changes: 3 additions & 2 deletions .github/scripts/deploy_cloud_run_candidate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ env_vars=(
"POLICYENGINE_DB_INSTANCE_CONNECTION_NAME=${CLOUD_RUN_CLOUD_SQL_INSTANCE}"
"POLICYENGINE_DB_USER=${POLICYENGINE_DB_USER:-policyengine}"
"POLICYENGINE_DB_NAME=${POLICYENGINE_DB_NAME:-policyengine}"
"SIMULATION_API_URL=${SIMULATION_API_URL}"
"SIMULATION_ENTRYPOINT_URL=${SIMULATION_ENTRYPOINT_URL}"
"OLD_SIMULATION_GATEWAY_URL=${OLD_SIMULATION_GATEWAY_URL}"
"GATEWAY_AUTH_REQUIRED=1"
"GATEWAY_AUTH_ISSUER=${GATEWAY_AUTH_ISSUER}"
"GATEWAY_AUTH_AUDIENCE=${GATEWAY_AUTH_AUDIENCE}"
"GATEWAY_AUTH_CLIENT_ID=${GATEWAY_AUTH_CLIENT_ID}"
"GATEWAY_AUTH_CLIENT_SECRET_RESOURCE=${GATEWAY_AUTH_CLIENT_SECRET_RESOURCE}"
"API_HOST_BACKEND=cloud_run"
"SIM_FRONT_DOOR=old_gateway_direct"
"SIM_ENTRYPOINT=${SIM_ENTRYPOINT:-old_gateway_direct}"
"SIM_COMPUTE_ECONOMY=old_gateway"
"CLOUD_RUN_REVISION_TAG=${CLOUD_RUN_TAG}"
"WEB_CONCURRENCY=${CLOUD_RUN_WEB_CONCURRENCY}"
Expand Down
69 changes: 69 additions & 0 deletions .github/scripts/ramp_simulation_entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env bash

# Operator-run production command. This script is intentionally not called by a
# GitHub Actions workflow: traffic percentages are changed manually after the
# corresponding observation gate has been reviewed.

set -euo pipefail

source .github/scripts/cloud_run_env.sh
cloud_run_set_defaults

new_revision="${SIMULATION_NEW_ENTRYPOINT_REVISION:?SIMULATION_NEW_ENTRYPOINT_REVISION is required}"
direct_revision="${SIMULATION_DIRECT_GATEWAY_REVISION:?SIMULATION_DIRECT_GATEWAY_REVISION is required}"
new_percent="${SIMULATION_NEW_ENTRYPOINT_PERCENT:?SIMULATION_NEW_ENTRYPOINT_PERCENT is required}"

case "${new_percent}" in
0|5|25|50|100) ;;
*)
echo "SIMULATION_NEW_ENTRYPOINT_PERCENT must be one of 0, 5, 25, 50, or 100" >&2
exit 1
;;
esac

if [ "${new_revision}" = "${direct_revision}" ]; then
echo "New-entrypoint and direct-gateway revisions must be different" >&2
exit 1
fi

validate_revision_entrypoint() {
local revision="${1:?revision is required}"
local expected="${2:?expected entrypoint is required}"

if [[ "${CLOUD_RUN_DRY_RUN:-0}" == "1" ]]; then
cloud_run_run gcloud run revisions describe "${revision}" \
--project "${CLOUD_RUN_PROJECT}" \
--region "${CLOUD_RUN_REGION}" \
--format=json
return
fi

local revision_json actual
revision_json="$(gcloud run revisions describe "${revision}" \
--project "${CLOUD_RUN_PROJECT}" \
--region "${CLOUD_RUN_REGION}" \
--format=json)"
actual="$(jq -er '.spec.containers[0].env[] | select(.name == "SIM_ENTRYPOINT") | .value' <<<"${revision_json}")"
if [[ "${actual}" != "${expected}" ]]; then
echo "Revision ${revision} has SIM_ENTRYPOINT=${actual}; expected ${expected}" >&2
exit 1
fi
}

validate_revision_entrypoint "${new_revision}" cloud_run_simulation_entrypoint
validate_revision_entrypoint "${direct_revision}" old_gateway_direct

if [ "${new_percent}" = "0" ]; then
traffic="${direct_revision}=100"
elif [ "${new_percent}" = "100" ]; then
traffic="${new_revision}=100"
else
direct_percent=$((100 - new_percent))
traffic="${new_revision}=${new_percent},${direct_revision}=${direct_percent}"
fi

cloud_run_run gcloud run services update-traffic "${CLOUD_RUN_SERVICE}" \
--project "${CLOUD_RUN_PROJECT}" \
--region "${CLOUD_RUN_REGION}" \
--platform managed \
--to-revisions "${traffic}"
2 changes: 1 addition & 1 deletion .github/scripts/validate_app_engine_deploy_env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
set -euo pipefail

required=(
SIMULATION_API_URL
SIMULATION_ENTRYPOINT_URL
GATEWAY_AUTH_ISSUER
GATEWAY_AUTH_AUDIENCE
GATEWAY_AUTH_CLIENT_ID
Expand Down
3 changes: 2 additions & 1 deletion .github/scripts/validate_cloud_run_deploy_env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ cloud_run_require_env \
CLOUD_RUN_ANTHROPIC_API_KEY_SECRET \
CLOUD_RUN_OPENAI_API_KEY_SECRET \
CLOUD_RUN_HUGGING_FACE_TOKEN_SECRET \
SIMULATION_API_URL \
SIMULATION_ENTRYPOINT_URL \
OLD_SIMULATION_GATEWAY_URL \
GATEWAY_AUTH_ISSUER \
GATEWAY_AUTH_AUDIENCE \
GATEWAY_AUTH_CLIENT_ID \
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
run: sudo apt-get install -y jq
- name: Check simulation API supports updated PolicyEngine bundle
env:
SIMULATION_API_URL: ${{ secrets.SIMULATION_API_URL }}
SIMULATION_ENTRYPOINT_URL: ${{ secrets.SIMULATION_ENTRYPOINT_URL }}
run: bash .github/check-policyengine-bundle-supported.sh --if-changed-from-base "${{ github.base_ref }}"

lint:
Expand Down
23 changes: 14 additions & 9 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
run: sudo apt-get install -y jq
- name: Check simulation API supports PolicyEngine bundle
env:
SIMULATION_API_URL: ${{ secrets.SIMULATION_API_URL }}
SIMULATION_ENTRYPOINT_URL: ${{ secrets.SIMULATION_ENTRYPOINT_URL }}
run: bash .github/check-policyengine-bundle-supported.sh

versioning:
Expand Down Expand Up @@ -151,7 +151,7 @@ jobs:
# Transitional: these values are still passed into the deploy bundle
# by gcp/export.py. Long-term target is a generic image plus runtime
# config / Secret Manager lookups instead of image bake-in.
SIMULATION_API_URL: ${{ secrets.SIMULATION_API_URL }}
SIMULATION_ENTRYPOINT_URL: ${{ secrets.SIMULATION_ENTRYPOINT_URL }}
GATEWAY_AUTH_ISSUER: ${{ secrets.GATEWAY_AUTH_ISSUER }}
GATEWAY_AUTH_AUDIENCE: ${{ secrets.GATEWAY_AUTH_AUDIENCE }}
GATEWAY_AUTH_CLIENT_ID: ${{ secrets.GATEWAY_AUTH_CLIENT_ID }}
Expand All @@ -168,7 +168,7 @@ jobs:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }}
SIMULATION_API_URL: ${{ secrets.SIMULATION_API_URL }}
SIMULATION_ENTRYPOINT_URL: ${{ secrets.SIMULATION_ENTRYPOINT_URL }}
GATEWAY_AUTH_ISSUER: ${{ secrets.GATEWAY_AUTH_ISSUER }}
GATEWAY_AUTH_AUDIENCE: ${{ secrets.GATEWAY_AUTH_AUDIENCE }}
GATEWAY_AUTH_CLIENT_ID: ${{ secrets.GATEWAY_AUTH_CLIENT_ID }}
Expand All @@ -186,7 +186,7 @@ jobs:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }}
SIMULATION_API_URL: ${{ secrets.SIMULATION_API_URL }}
SIMULATION_ENTRYPOINT_URL: ${{ secrets.SIMULATION_ENTRYPOINT_URL }}
GATEWAY_AUTH_ISSUER: ${{ secrets.GATEWAY_AUTH_ISSUER }}
GATEWAY_AUTH_AUDIENCE: ${{ secrets.GATEWAY_AUTH_AUDIENCE }}
GATEWAY_AUTH_CLIENT_ID: ${{ secrets.GATEWAY_AUTH_CLIENT_ID }}
Expand Down Expand Up @@ -252,7 +252,9 @@ jobs:
CLOUD_RUN_RUNTIME_SERVICE_ACCOUNT: ${{ secrets.GCP_CLOUD_RUN_RUNTIME_SERVICE_ACCOUNT }}
POLICYENGINE_DB_USER: ${{ vars.POLICYENGINE_DB_USER }}
POLICYENGINE_DB_NAME: ${{ vars.POLICYENGINE_DB_NAME }}
SIMULATION_API_URL: ${{ secrets.SIMULATION_API_URL }}
SIMULATION_ENTRYPOINT_URL: ${{ secrets.SIMULATION_ENTRYPOINT_URL }}
OLD_SIMULATION_GATEWAY_URL: ${{ secrets.OLD_SIMULATION_GATEWAY_URL }}
SIM_ENTRYPOINT: ${{ vars.SIM_ENTRYPOINT || 'old_gateway_direct' }}
GATEWAY_AUTH_ISSUER: ${{ secrets.GATEWAY_AUTH_ISSUER }}
GATEWAY_AUTH_AUDIENCE: ${{ secrets.GATEWAY_AUTH_AUDIENCE }}
GATEWAY_AUTH_CLIENT_ID: ${{ secrets.GATEWAY_AUTH_CLIENT_ID }}
Expand Down Expand Up @@ -401,7 +403,7 @@ jobs:
run: sudo apt-get install -y jq
- name: Check simulation API supports PolicyEngine bundle
env:
SIMULATION_API_URL: ${{ secrets.SIMULATION_API_URL }}
SIMULATION_ENTRYPOINT_URL: ${{ secrets.SIMULATION_ENTRYPOINT_URL }}
run: bash .github/check-policyengine-bundle-supported.sh

deploy-production-candidate:
Expand Down Expand Up @@ -442,7 +444,7 @@ jobs:
# Transitional: these values are still passed into the deploy bundle
# by gcp/export.py. Long-term target is a generic image plus runtime
# config / Secret Manager lookups instead of image bake-in.
SIMULATION_API_URL: ${{ secrets.SIMULATION_API_URL }}
SIMULATION_ENTRYPOINT_URL: ${{ secrets.SIMULATION_ENTRYPOINT_URL }}
GATEWAY_AUTH_ISSUER: ${{ secrets.GATEWAY_AUTH_ISSUER }}
GATEWAY_AUTH_AUDIENCE: ${{ secrets.GATEWAY_AUTH_AUDIENCE }}
GATEWAY_AUTH_CLIENT_ID: ${{ secrets.GATEWAY_AUTH_CLIENT_ID }}
Expand All @@ -460,7 +462,7 @@ jobs:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }}
SIMULATION_API_URL: ${{ secrets.SIMULATION_API_URL }}
SIMULATION_ENTRYPOINT_URL: ${{ secrets.SIMULATION_ENTRYPOINT_URL }}
GATEWAY_AUTH_ISSUER: ${{ secrets.GATEWAY_AUTH_ISSUER }}
GATEWAY_AUTH_AUDIENCE: ${{ secrets.GATEWAY_AUTH_AUDIENCE }}
GATEWAY_AUTH_CLIENT_ID: ${{ secrets.GATEWAY_AUTH_CLIENT_ID }}
Expand Down Expand Up @@ -572,7 +574,9 @@ jobs:
CLOUD_RUN_RUNTIME_SERVICE_ACCOUNT: ${{ secrets.GCP_CLOUD_RUN_RUNTIME_SERVICE_ACCOUNT }}
POLICYENGINE_DB_USER: ${{ vars.POLICYENGINE_DB_USER }}
POLICYENGINE_DB_NAME: ${{ vars.POLICYENGINE_DB_NAME }}
SIMULATION_API_URL: ${{ secrets.SIMULATION_API_URL }}
SIMULATION_ENTRYPOINT_URL: ${{ secrets.SIMULATION_ENTRYPOINT_URL }}
OLD_SIMULATION_GATEWAY_URL: ${{ secrets.OLD_SIMULATION_GATEWAY_URL }}
SIM_ENTRYPOINT: ${{ vars.SIM_ENTRYPOINT || 'old_gateway_direct' }}
GATEWAY_AUTH_ISSUER: ${{ secrets.GATEWAY_AUTH_ISSUER }}
GATEWAY_AUTH_AUDIENCE: ${{ secrets.GATEWAY_AUTH_AUDIENCE }}
GATEWAY_AUTH_CLIENT_ID: ${{ secrets.GATEWAY_AUTH_CLIENT_ID }}
Expand All @@ -595,6 +599,7 @@ jobs:
API_BASE_URL: ${{ steps.cloud_run_url.outputs.url }}
STAGING_API_TEST_PROBE_ID: cloud-run-${{ steps.cloud_run.outputs.revision_tag }}
- name: Promote Cloud Run production candidate
if: ${{ vars.SIM_ENTRYPOINT != 'cloud_run_simulation_entrypoint' }}
run: bash .github/scripts/promote_cloud_run_tag.sh
env:
CLOUD_RUN_TAG: ${{ steps.cloud_run.outputs.revision_tag }}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Keep that commented unless you are pointing at a real local credential file. The

If you are running against an auth-protected simulation gateway outside the managed deploy path, you may also need:

- `SIMULATION_API_URL`
- `SIMULATION_ENTRYPOINT_URL`
- `GATEWAY_AUTH_REQUIRED`
- `GATEWAY_AUTH_ISSUER`
- `GATEWAY_AUTH_AUDIENCE`
Expand Down
2 changes: 1 addition & 1 deletion docs/migration/history/migration-pr1-baseline-runbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ representative economy-comparison payload:

```bash
API_BASE_URL=https://example-dot-policyengine-api.appspot.com \
SIMULATION_API_URL=https://policyengine--policyengine-simulation-gateway-web-app.modal.run \
SIMULATION_ENTRYPOINT_URL=https://policyengine--policyengine-simulation-gateway-web-app.modal.run \
SIMULATION_PAYLOAD_FILE=/path/to/representative-simulation-payload.json \
python scripts/capture_migration_baseline.py --repetitions 5
```
Expand Down
6 changes: 4 additions & 2 deletions gcp/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
ANTHROPIC_API_KEY = os.environ["ANTHROPIC_API_KEY"]
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
HUGGING_FACE_TOKEN = os.environ["HUGGING_FACE_TOKEN"]
SIMULATION_API_URL = os.environ["SIMULATION_API_URL"]
SIMULATION_ENTRYPOINT_URL = os.environ["SIMULATION_ENTRYPOINT_URL"]
GATEWAY_AUTH_ISSUER = os.environ["GATEWAY_AUTH_ISSUER"]
GATEWAY_AUTH_AUDIENCE = os.environ["GATEWAY_AUTH_AUDIENCE"]
GATEWAY_AUTH_CLIENT_ID = os.environ["GATEWAY_AUTH_CLIENT_ID"]
Expand All @@ -28,7 +28,9 @@
dockerfile = dockerfile.replace(".anthropic_api_key", ANTHROPIC_API_KEY)
dockerfile = dockerfile.replace(".openai_api_key", OPENAI_API_KEY)
dockerfile = dockerfile.replace(".hugging_face_token", HUGGING_FACE_TOKEN)
dockerfile = dockerfile.replace(".simulation_api_url", SIMULATION_API_URL)
dockerfile = dockerfile.replace(
".simulation_entrypoint_url", SIMULATION_ENTRYPOINT_URL
)
dockerfile = dockerfile.replace(".gateway_auth_issuer", GATEWAY_AUTH_ISSUER)
dockerfile = dockerfile.replace(".gateway_auth_audience", GATEWAY_AUTH_AUDIENCE)
dockerfile = dockerfile.replace(
Expand Down
2 changes: 1 addition & 1 deletion gcp/policyengine_api/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ENV POLICYENGINE_GITHUB_MICRODATA_AUTH_TOKEN .github_microdata_token
ENV ANTHROPIC_API_KEY .anthropic_api_key
ENV OPENAI_API_KEY .openai_api_key
ENV HUGGING_FACE_TOKEN .hugging_face_token
ENV SIMULATION_API_URL .simulation_api_url
ENV SIMULATION_ENTRYPOINT_URL .simulation_entrypoint_url
ENV CREDENTIALS_JSON_API_V2 .credentials_json_api_v2
ENV GATEWAY_AUTH_REQUIRED 1
ENV GATEWAY_AUTH_ISSUER .gateway_auth_issuer
Expand Down
6 changes: 4 additions & 2 deletions policyengine_api/asgi_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,12 @@ def health() -> HealthResponse:
include_in_schema=False,
)
def simulation_gateway_health() -> SimulationGatewayHealthResponse:
from policyengine_api.libs.simulation_api_modal import SimulationAPIModal
from policyengine_api.libs.simulation_entrypoint import (
SimulationEntrypointClient,
)

try:
gateway_healthy = SimulationAPIModal().health_check()
gateway_healthy = SimulationEntrypointClient().health_check()
except Exception as error:
raise HTTPException(
status_code=503,
Expand Down
30 changes: 30 additions & 0 deletions policyengine_api/libs/simulation_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Compatibility exports for the Simulation Entrypoint client.

New code should import from :mod:`policyengine_api.libs.simulation_entrypoint`.
"""

from policyengine_api.libs.simulation_entrypoint import (
ModalBudgetWindowBatchExecution,
ModalSimulationExecution,
SimulationAPIClient,
SimulationEntrypointClient,
SimulationAPIModal,
resolve_simulation_api_url,
resolve_simulation_entrypoint_url,
simulation_api,
simulation_api_modal,
simulation_entrypoint,
)

__all__ = [
"ModalBudgetWindowBatchExecution",
"ModalSimulationExecution",
"SimulationAPIClient",
"SimulationEntrypointClient",
"SimulationAPIModal",
"resolve_simulation_api_url",
"resolve_simulation_entrypoint_url",
"simulation_api",
"simulation_api_modal",
"simulation_entrypoint",
]
Loading
Loading