| 1 | // Read-only live configuration check. Never installs secrets or creates charges. |
| 2 | import assert from 'node:assert/strict'; |
| 3 | import { readFileSync } from 'node:fs'; |
| 4 | |
| 5 | const key = readFileSync('.secrets/stripe-live-key.txt', 'utf8').trim(); |
| 6 | const signingSecret = readFileSync('.secrets/stripe-live-webhook.txt', 'utf8').trim(); |
| 7 | assert.ok(/^(sk|rk)_live_/.test(key), 'Expected a live API key'); |
| 8 | assert.ok(/^whsec_\S+$/.test(signingSecret), 'Expected a webhook signing secret'); |
| 9 | const source = readFileSync('services/billing/src/webhooks.rs', 'utf8'); |
| 10 | const url = source.match(/WEBHOOK_URL: &str = "([^"]+)"/)[1]; |
| 11 | const required = [...source.match(/const EVENTS: &\[&str\] = &\[([\s\S]*?)\];/)[1].matchAll(/"([a-z_.]+)"/g)].map(m => m[1]); |
| 12 | const version = readFileSync('services/billing/src/stripe.rs', 'utf8').match(/STRIPE_VERSION: &str = "([^"]+)"/)[1]; |
| 13 | async function get(path) { |
| 14 | const response = await fetch(`https://api.stripe.com/v1${path}`, { |
| 15 | headers: { Authorization: `Bearer ${key}`, 'Stripe-Version': version }, |
| 16 | }); |
| 17 | if (!response.ok) throw Error(`Stripe read failed: HTTP ${response.status}`); |
| 18 | return response.json(); |
| 19 | } |
| 20 | const [account, tax] = await Promise.all([get('/account'), get('/tax/settings')]); |
| 21 | const endpoints = []; |
| 22 | let after; |
| 23 | do { |
| 24 | const page = await get(`/webhook_endpoints?limit=100${after ? `&starting_after=${encodeURIComponent(after)}` : ''}`); |
| 25 | endpoints.push(...page.data.filter(e => e.url === url)); |
| 26 | after = page.has_more ? page.data.at(-1)?.id : undefined; |
| 27 | assert.ok(!page.has_more || after, 'Malformed endpoint pagination'); |
| 28 | } while (after); |
| 29 | const matching = endpoints.map(e => ({ |
| 30 | id: e.id, url: e.url, status: e.status, live: e.livemode, apiVersion: e.api_version, |
| 31 | missingEvents: e.enabled_events.includes('*') ? [] : required.filter(t => !e.enabled_events.includes(t)), |
| 32 | })); |
| 33 | const ready = account.charges_enabled && tax.status === 'active' |
| 34 | && matching.some(e => e.live && e.status === 'enabled' && e.apiVersion === '2026-08-26.dahlia' && !e.missingEvents.length); |
| 35 | console.log(JSON.stringify({ |
| 36 | checkedAt: new Date().toISOString(), account: account.id, |
| 37 | chargesEnabled: account.charges_enabled, payoutsEnabled: account.payouts_enabled, |
| 38 | taxStatus: tax.status, endpoints: matching, configurationReady: ready, |
| 39 | signingSecretFilePresent: true, |
| 40 | limitations: ['Stored signing secret cannot be matched to an existing endpoint through the read API', |
| 41 | 'Does not verify deployed secrets, delivery, application readiness, or settlement'], |
| 42 | }, null, 2)); |
| 43 | if (!ready) process.exitCode = 1; |