Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

43 linesCodeBlameRaw
1// Read-only live configuration check. Never installs secrets or creates charges.
2import assert from 'node:assert/strict';
3import { readFileSync } from 'node:fs';
4
5const key = readFileSync('.secrets/stripe-live-key.txt', 'utf8').trim();
6const signingSecret = readFileSync('.secrets/stripe-live-webhook.txt', 'utf8').trim();
7assert.ok(/^(sk|rk)_live_/.test(key), 'Expected a live API key');
8assert.ok(/^whsec_\S+$/.test(signingSecret), 'Expected a webhook signing secret');
9const source = readFileSync('services/billing/src/webhooks.rs', 'utf8');
10const url = source.match(/WEBHOOK_URL: &str = "([^"]+)"/)[1];
11const required = [...source.match(/const EVENTS: &\[&str\] = &\[([\s\S]*?)\];/)[1].matchAll(/"([a-z_.]+)"/g)].map(m => m[1]);
12const version = readFileSync('services/billing/src/stripe.rs', 'utf8').match(/STRIPE_VERSION: &str = "([^"]+)"/)[1];
13async 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}
20const [account, tax] = await Promise.all([get('/account'), get('/tax/settings')]);
21const endpoints = [];
22let after;
23do {
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);
29const 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}));
33const 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);
35console.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));
43if (!ready) process.exitCode = 1;