Stripe Database Monitor #217
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Stripe Database Monitor | |
| on: | |
| push: | |
| branches: [fix-e2e, webhook-e2e] | |
| schedule: | |
| - cron: '0 * * * *' # Every hour | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| # Each matrix leg gets its own concurrency slot so runs don't cancel each other. | |
| concurrency: | |
| group: e2e-monitor-${{ github.ref }}-${{ github.event_name }} | |
| cancel-in-progress: false | |
| jobs: | |
| monitor: | |
| name: E2E — ${{ matrix.env }} | |
| runs-on: ubuntu-24.04-arm | |
| timeout-minutes: 75 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - env: prod | |
| api_key: STRIPE_SK_GOLDILOCKS_PROD | |
| api_base: https://api.stripe.com | |
| - env: qa | |
| api_key: STRIPE_SK_GOLDILOCKS_QA | |
| api_base: https://qa-api.stripe.com | |
| env: | |
| STRIPE_API_KEY: ${{ secrets[matrix.api_key] }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| - name: Install Stripe CLI | |
| run: | | |
| curl -s https://packages.stripe.dev/api/security/keypair/stripe-cli-gpg/public | gpg --dearmor -o /usr/share/keyrings/stripe.gpg | |
| echo "deb [signed-by=/usr/share/keyrings/stripe.gpg] https://packages.stripe.dev/stripe-cli-debian-local stable main" \ | |
| | sudo tee /etc/apt/sources.list.d/stripe.list | |
| sudo apt-get update -qq && sudo apt-get install -y -qq stripe | |
| - name: Validate API key | |
| run: | | |
| if [ -z "$STRIPE_API_KEY" ]; then | |
| echo "::error::STRIPE_API_KEY is empty — check that the ${{ matrix.api_key }} secret is set" | |
| exit 1 | |
| fi | |
| if ! stripe customers list --limit 1 --api-base ${{ matrix.api_base }} >/dev/null 2>&1; then | |
| echo "::error::STRIPE_API_KEY (${{ matrix.api_key }}) is invalid or expired — rotate it in the Stripe Dashboard and update the GitHub secret" | |
| exit 1 | |
| fi | |
| - name: Create Stripe database | |
| id: create-db | |
| run: | | |
| echo "Creating Stripe database..." | |
| RESULT=$(stripe databases create --live --api-base ${{ matrix.api_base }}) | |
| DB_ID=$(echo "$RESULT" | grep -oE 'db_[A-Za-z0-9]+' | head -1) | |
| DB_STRING=$(echo "$RESULT" | grep -oE 'postgresql://[^[:space:]]+') | |
| if [ -z "$DB_ID" ]; then | |
| echo "::error::Could not extract database ID from output (connection string redacted)" | |
| exit 1 | |
| fi | |
| if [ -z "$DB_STRING" ]; then | |
| echo "::error::Could not extract connection string from output" | |
| exit 1 | |
| fi | |
| # Mask the full connection string and its password component before any further output. | |
| echo "::add-mask::$DB_STRING" | |
| DB_PASSWORD=$(printf '%s' "$DB_STRING" | sed -nE 's#^postgresql://[^:]+:([^@]+)@.*$#\1#p') | |
| if [ -n "$DB_PASSWORD" ]; then | |
| echo "::add-mask::$DB_PASSWORD" | |
| fi | |
| echo "db_id=$DB_ID" >> "$GITHUB_OUTPUT" | |
| echo "db_string=$DB_STRING" >> "$GITHUB_OUTPUT" | |
| echo "Database $DB_ID created successfully" | |
| - name: Install psql | |
| run: sudo apt-get install -y -qq postgresql-client | |
| - name: Verify backfill | |
| if: always() && steps.create-db.outputs.db_id != '' | |
| env: | |
| DB_STRING: ${{ steps.create-db.outputs.db_string }} | |
| DB_ID: ${{ steps.create-db.outputs.db_id }} | |
| STRIPE_API_BASE: ${{ matrix.api_base }} | |
| run: bash scripts/verify-backfill.sh | |
| - name: Verify live sync | |
| if: always() && steps.create-db.outputs.db_id != '' | |
| env: | |
| DB_STRING: ${{ steps.create-db.outputs.db_string }} | |
| DB_ID: ${{ steps.create-db.outputs.db_id }} | |
| STRIPE_API_BASE: ${{ matrix.api_base }} | |
| run: bash scripts/verify-live-sync.sh | |
| # TODO: Make Sigma validation a hard failure once selective sync is available | |
| # and the DB consistently reaches ready state. | |
| - name: Sigma validation | |
| env: | |
| DATABASE_URL: ${{ steps.create-db.outputs.db_string }} | |
| run: | | |
| set +e | |
| bun scripts/reconcile-sigma-vs-postgres.ts | |
| STATUS=$? | |
| if [ "$STATUS" -ne 0 ]; then | |
| echo "::warning title=Sigma reconciliation::Postgres is missing rows that exist in Sigma. See the job log for the per-table diff and the list of missing IDs with their created timestamps." | |
| fi | |
| - name: Delete Stripe database | |
| if: always() && steps.create-db.outputs.db_id | |
| run: | | |
| echo "Deleting database ${{ steps.create-db.outputs.db_id }}..." | |
| stripe databases delete ${{ steps.create-db.outputs.db_id }} --yes --api-base ${{ matrix.api_base }} |