Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
2bf255c
Add user identities and v1-anchored association schema
anth-volk Oct 12, 2026
6868fc9
Add Auth0 bearer authentication for user-owned routes
anth-volk Oct 12, 2026
98e27cc
Lock user associations to the signed-in user and add v1-anchored saves
anth-volk Oct 12, 2026
7b0cf1d
Register signed-in user route contracts and Postgres identity tests
anth-volk Oct 12, 2026
e909054
Add read-only qualification for the user-association reshape
anth-volk Oct 12, 2026
04fa436
Wire user auth settings into deploys and gate staging on signed-in ro…
anth-volk Oct 12, 2026
d92bffc
Document Stage 12A user login and propose Cloud Armor throttles
anth-volk Oct 12, 2026
292665a
Describe owner-from-token association queries in the routes skill
anth-volk Oct 12, 2026
89be2b0
Keep release-test unsets inline-short and update household reassignme…
anth-volk Oct 12, 2026
5864f9d
Pass the optional staging Auth0 realm to the live signed-in probe
anth-volk Oct 12, 2026
41c4af7
Keep retired association columns so the previous revision still loads…
anth-volk Oct 13, 2026
29c5ea8
Scope account imports to one country through shared association helpers
anth-volk Oct 13, 2026
a496e72
Bound single user-route writes and their free-text fields
anth-volk Oct 13, 2026
ed55f78
Type report and policy snapshots in user-route responses
anth-volk Oct 13, 2026
8b66fb0
Log every signed-in user route as Supabase traffic
anth-volk Oct 13, 2026
ee8f47d
Defer v1 reference checks, log unexpected user-route failures, share …
anth-volk Oct 13, 2026
c656ea1
Keep Auth0 Management deletion out of staging deploys
anth-volk Oct 13, 2026
76baf1a
Cover every signed-in operation with the fail-closed 401 test
anth-volk Oct 13, 2026
e0839f3
Keep the failure-logging test independent of Alembic's logging config
anth-volk Oct 13, 2026
361a709
Reject NaN and Infinity in user-route floats and JSON values
anth-volk Oct 13, 2026
0b72a24
Log persistence failures and publish stored snapshots through lenient…
anth-volk Oct 13, 2026
91d4669
Obtain Auth0 credentials before deleting an account, and retry a reje…
anth-volk Oct 13, 2026
4edf9bf
Keep compute labels off saved-work requests and describe the size che…
anth-volk Oct 13, 2026
9c00c18
Require an edge guard before any application rollback with signed-in …
anth-volk Oct 13, 2026
57553ed
Exercise the previous revision's table usage against the Stage 12A sc…
anth-volk Oct 13, 2026
fd6b9b9
Report account_created on /v2/me so app v3 imports only for new accounts
anth-volk Oct 13, 2026
7bd6814
Drop account_created from /v2/me now that app v3 imports at every sig…
anth-volk Oct 13, 2026
bb02660
Remove the unused ResolvedUser.provisioned flag
anth-volk Oct 13, 2026
466b803
Store no import item whose client_ref repeats in the request
anth-volk Oct 13, 2026
76c294c
Size the proposed import throttle for imports at every sign-in
anth-volk Oct 13, 2026
4f45745
Warn that the auth issuer must be final before the first sign-in
anth-volk Oct 13, 2026
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
13 changes: 13 additions & 0 deletions .github/scripts/deploy_cloud_run_candidate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,21 @@ env_vars=(
"V2_SUPABASE_PROJECT_REF=${V2_SUPABASE_PROJECT_REF}"
"V2_SUPABASE_ENVIRONMENT=${V2_SUPABASE_ENVIRONMENT}"
"V2_RUNTIME_DATABASE_URL_SECRET_RESOURCE=${V2_RUNTIME_DATABASE_URL_SECRET_RESOURCE}"
"PUBLIC_API_AUTH_REQUIRED=${PUBLIC_API_AUTH_REQUIRED}"
"PUBLIC_API_AUTH_ISSUER=${PUBLIC_API_AUTH_ISSUER:-}"
"PUBLIC_API_AUTH_AUDIENCE=${PUBLIC_API_AUTH_AUDIENCE:-}"
)

# Optional: account deletion removes the Auth0 user only when the Management
# API client is configured. Validation requires all three values or none.
if [[ -n "${AUTH0_MANAGEMENT_DOMAIN:-}" ]]; then
env_vars+=(
"AUTH0_MANAGEMENT_DOMAIN=${AUTH0_MANAGEMENT_DOMAIN}"
"AUTH0_MANAGEMENT_CLIENT_ID=${AUTH0_MANAGEMENT_CLIENT_ID}"
"AUTH0_MANAGEMENT_CLIENT_SECRET_RESOURCE=${AUTH0_MANAGEMENT_CLIENT_SECRET_RESOURCE}"
)
fi

if [[ -n "${OLD_SIMULATION_GATEWAY_URL:-}" ]]; then
env_vars+=("OLD_SIMULATION_GATEWAY_URL=${OLD_SIMULATION_GATEWAY_URL}")
fi
Expand Down
48 changes: 47 additions & 1 deletion .github/scripts/validate_cloud_run_deploy_env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ cloud_run_require_env \
GATEWAY_AUTH_ISSUER \
GATEWAY_AUTH_AUDIENCE \
GATEWAY_AUTH_CLIENT_ID \
GATEWAY_AUTH_CLIENT_SECRET_RESOURCE
GATEWAY_AUTH_CLIENT_SECRET_RESOURCE \
PUBLIC_API_AUTH_REQUIRED

for selector in \
ROUTE_IMPL_HEALTH \
Expand Down Expand Up @@ -110,6 +111,51 @@ case "${DB_WRITE_HOUSEHOLD}" in
;;
esac

# Signed-in user routes fail closed without Auth0 settings. When required,
# the issuer and audience must be present; otherwise they are set together
# or not at all.
case "${PUBLIC_API_AUTH_REQUIRED}" in
0|1) ;;
*)
printf '%s=%s is invalid; expected 0 or 1\n' \
"PUBLIC_API_AUTH_REQUIRED" "${PUBLIC_API_AUTH_REQUIRED}" >&2
exit 1
;;
esac
if [[ "${PUBLIC_API_AUTH_REQUIRED}" == "1" ]]; then
cloud_run_require_env PUBLIC_API_AUTH_ISSUER PUBLIC_API_AUTH_AUDIENCE
fi
if [[ -n "${PUBLIC_API_AUTH_ISSUER:-}" && -z "${PUBLIC_API_AUTH_AUDIENCE:-}" ]] \
|| [[ -z "${PUBLIC_API_AUTH_ISSUER:-}" && -n "${PUBLIC_API_AUTH_AUDIENCE:-}" ]]; then
echo "Set both PUBLIC_API_AUTH_ISSUER and PUBLIC_API_AUTH_AUDIENCE, or neither" >&2
exit 1
fi
if [[ -n "${PUBLIC_API_AUTH_ISSUER:-}" && "${PUBLIC_API_AUTH_ISSUER}" != https://* ]]; then
echo "PUBLIC_API_AUTH_ISSUER must be an absolute HTTPS URL" >&2
exit 1
fi

auth0_management_count=0
for name in \
AUTH0_MANAGEMENT_DOMAIN \
AUTH0_MANAGEMENT_CLIENT_ID \
AUTH0_MANAGEMENT_CLIENT_SECRET_RESOURCE; do
if [[ -n "${!name:-}" ]]; then
auth0_management_count=$((auth0_management_count + 1))
fi
done
if (( auth0_management_count != 0 && auth0_management_count != 3 )); then
echo "Set AUTH0_MANAGEMENT_DOMAIN, AUTH0_MANAGEMENT_CLIENT_ID, and AUTH0_MANAGEMENT_CLIENT_SECRET_RESOURCE together, or none" >&2
exit 1
fi
# The staging live test deletes its own account through DELETE /v2/me. With
# Management API deletion configured, that would delete the CI user from
# Auth0, so only production may configure it.
if (( auth0_management_count != 0 )) && [[ "${DEPLOYMENT_ENVIRONMENT}" != "production" ]]; then
echo "AUTH0_MANAGEMENT_* settings are production-only; unset them for ${DEPLOYMENT_ENVIRONMENT}" >&2
exit 1
fi

selected_url_env="$(
simulation_entrypoint_url_env_name "${SIM_ENTRYPOINT}"
)"
Expand Down
19 changes: 18 additions & 1 deletion .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ jobs:
DB_WRITE_POLICY: ${{ vars.DB_WRITE_POLICY }}
DB_READ_HOUSEHOLD: ${{ vars.DB_READ_HOUSEHOLD }}
DB_WRITE_HOUSEHOLD: ${{ vars.DB_WRITE_HOUSEHOLD }}
PUBLIC_API_AUTH_REQUIRED: ${{ vars.PUBLIC_API_AUTH_REQUIRED }}
PUBLIC_API_AUTH_ISSUER: ${{ vars.PUBLIC_API_AUTH_ISSUER }}
PUBLIC_API_AUTH_AUDIENCE: ${{ vars.PUBLIC_API_AUTH_AUDIENCE }}
CLOUD_RUN_SERVICE: policyengine-api-staging
CLOUD_RUN_RUNTIME_CACHE_ENVIRONMENT: staging
CLOUD_RUN_RUNTIME_CACHE_URL_SECRET: policyengine-api-staging-runtime-cache-url:latest
Expand Down Expand Up @@ -233,7 +236,7 @@ jobs:
run: >-
env -u DEPLOYMENT_ENVIRONMENT -u ROUTE_IMPL_HEALTH -u ROUTE_IMPL_SPECIFICATION -u ROUTE_IMPL_METADATA -u ROUTE_IMPL_POLICY -u ROUTE_IMPL_HOUSEHOLD -u DB_READ_POLICY -u DB_WRITE_POLICY -u DB_READ_HOUSEHOLD -u DB_WRITE_HOUSEHOLD
-u CLOUD_RUN_SERVICE -u CLOUD_RUN_RUNTIME_CACHE_ENVIRONMENT -u CLOUD_RUN_RUNTIME_CACHE_URL_SECRET -u CLOUD_RUN_RUNTIME_CACHE_CA_CERT_SECRET -u CLOUD_RUN_POLICYENGINE_DB_PASSWORD_SECRET -u CLOUD_RUN_MIN_INSTANCES -u CLOUD_RUN_SERVICE_MIN_INSTANCES -u CLOUD_RUN_MAX_INSTANCES
-u V2_SUPABASE_PROJECT_REF -u V2_SUPABASE_ENVIRONMENT -u V2_RUNTIME_DATABASE_URL_SECRET_RESOURCE -u PRODUCTION_V2_SUPABASE_PROJECT_REF -u PRODUCTION_V2_RUNTIME_DATABASE_URL_SECRET_RESOURCE -u PRODUCTION_POLICYENGINE_DB_INSTANCE_CONNECTION_NAME make test
-u V2_SUPABASE_PROJECT_REF -u V2_SUPABASE_ENVIRONMENT -u V2_RUNTIME_DATABASE_URL_SECRET_RESOURCE -u PRODUCTION_V2_SUPABASE_PROJECT_REF -u PRODUCTION_V2_RUNTIME_DATABASE_URL_SECRET_RESOURCE -u PRODUCTION_POLICYENGINE_DB_INSTANCE_CONNECTION_NAME -u PUBLIC_API_AUTH_REQUIRED -u PUBLIC_API_AUTH_ISSUER -u PUBLIC_API_AUTH_AUDIENCE make test
env:
RUNTIME_CACHE_MODE: local
RUNTIME_CACHE_URL: redis://127.0.0.1:6379/0
Expand Down Expand Up @@ -308,6 +311,14 @@ jobs:
API_BASE_URL: ${{ steps.candidate.outputs.url }}
STAGING_API_TEST_PROBE_ID: cloud-run-${{ steps.cloud_run.outputs.revision_tag }}
V2_MIGRATION_DATABASE_URL: ${{ secrets.V2_MIGRATION_DATABASE_URL }}
# Staging-only Auth0 CI application (password grant) and test user.
STAGING_AUTH0_TEST_DOMAIN: ${{ vars.STAGING_AUTH0_TEST_DOMAIN }}
STAGING_AUTH0_TEST_AUDIENCE: ${{ vars.STAGING_AUTH0_TEST_AUDIENCE }}
STAGING_AUTH0_TEST_CLIENT_ID: ${{ secrets.STAGING_AUTH0_TEST_CLIENT_ID }}
STAGING_AUTH0_TEST_CLIENT_SECRET: ${{ secrets.STAGING_AUTH0_TEST_CLIENT_SECRET }}
STAGING_AUTH0_TEST_USERNAME: ${{ secrets.STAGING_AUTH0_TEST_USERNAME }}
STAGING_AUTH0_TEST_PASSWORD: ${{ secrets.STAGING_AUTH0_TEST_PASSWORD }}
STAGING_AUTH0_TEST_REALM: ${{ vars.STAGING_AUTH0_TEST_REALM }}

parallel-live-simulation-tests-staging-cloud-run:
name: Run live simulations against the staging candidate
Expand Down Expand Up @@ -473,6 +484,12 @@ jobs:
DB_WRITE_POLICY: ${{ vars.DB_WRITE_POLICY }}
DB_READ_HOUSEHOLD: ${{ vars.DB_READ_HOUSEHOLD }}
DB_WRITE_HOUSEHOLD: ${{ vars.DB_WRITE_HOUSEHOLD }}
PUBLIC_API_AUTH_REQUIRED: ${{ vars.PUBLIC_API_AUTH_REQUIRED }}
PUBLIC_API_AUTH_ISSUER: ${{ vars.PUBLIC_API_AUTH_ISSUER }}
PUBLIC_API_AUTH_AUDIENCE: ${{ vars.PUBLIC_API_AUTH_AUDIENCE }}
AUTH0_MANAGEMENT_DOMAIN: ${{ vars.AUTH0_MANAGEMENT_DOMAIN }}
AUTH0_MANAGEMENT_CLIENT_ID: ${{ vars.AUTH0_MANAGEMENT_CLIENT_ID }}
AUTH0_MANAGEMENT_CLIENT_SECRET_RESOURCE: ${{ secrets.AUTH0_MANAGEMENT_CLIENT_SECRET_RESOURCE }}
CLOUD_RUN_SERVICE: policyengine-api
CLOUD_RUN_RUNTIME_CACHE_ENVIRONMENT: production
CLOUD_RUN_RUNTIME_CACHE_URL_SECRET: policyengine-api-prod-runtime-cache-url:latest
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/seed-v2-database.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ jobs:
run: uv run python scripts/qualify_v2_household_migration.py
env:
V2_MIGRATION_DATABASE_URL: ${{ secrets.V2_MIGRATION_DATABASE_URL }}
- name: Qualify the pending user-association reshape
run: uv run python scripts/qualify_v2_user_association_migration.py
env:
V2_MIGRATION_DATABASE_URL: ${{ secrets.V2_MIGRATION_DATABASE_URL }}
- name: Upgrade and verify the v2 schema
run: bash .github/scripts/migrate_v2_metadata_schema.sh
env:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/v2-integration-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ jobs:
run: uv run coverage run -a --branch -m pytest -q tests/integration/test_v2_catalog_publication.py tests/integration/test_v2_metadata_routes.py
- name: Test v2 policy persistence and immediate v1 mirroring
run: uv run coverage run -a --branch -m pytest -q tests/integration/test_v2_policy_persistence.py tests/integration/test_v1_policy_dual_write.py tests/integration/test_mysql_policy_dual_write.py tests/integration/test_v2_user_policy_mirroring.py tests/integration/test_v1_user_policy_dual_write.py
- name: Test signed-in identity provisioning and user associations
run: uv run coverage run -a --branch -m pytest -q tests/integration/test_v2_user_identity_persistence.py
- name: Test v2 household persistence and immediate v1 copying
run: uv run coverage run -a --branch -m pytest -q tests/integration/test_v2_household_persistence.py tests/integration/test_v1_household_dual_write.py tests/integration/test_mysql_household_spm_dual_write.py
- name: Qualify production-scale v2 metadata publication
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add Auth0 user login for app v3: /v2/me (provisioning, profile, export, idempotent imports, account deletion), owner-scoped v1-anchored user associations for policies, households, simulations, and reports, and the user_identities schema.
Loading