diff --git a/package.json b/package.json index d0aa95bb9..64a5ee006 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "d": "ENV_FILE=.env infisical run --env=dev -- bun scripts/dev.ts", "p": "ENV_FILE=.env.prod infisical run --env=prod -- bun scripts/dev.ts", "setup": "node scripts/setup/setup.js", - "setup:test": "bun scripts/setup/setup-test.ts", + "setup:test": "infisical run --env=dev -- bun scripts/setup/setup-test.ts", "t": "infisical run --env=dev -- bun scripts/test.ts", "migrate-functions": "infisical run --env=dev -- bun scripts/migrations/migrate-functions.ts", "migrate-functions:prod": "infisical run --env=prod -- bun scripts/migrations/migrate-functions.ts", diff --git a/scripts/setup/setup-test.ts b/scripts/setup/setup-test.ts index ef6189001..354d75a91 100644 --- a/scripts/setup/setup-test.ts +++ b/scripts/setup/setup-test.ts @@ -5,16 +5,6 @@ import { createTestOrg, TEST_ORG_CONFIG, } from "../setupTestUtils/createTestOrg.js"; -import { - updateMultipleEnvVars, - updateSingleEnvVar, -} from "../setupTestUtils/incrementalEnvUpdate.js"; -import { - setupStripeTestKey, - setupTunnelUrl, - setupUpstash, -} from "../setupTestUtils/setupPrompts.js"; -import { updateEnvFile } from "../setupTestUtils/updateEnvFile.js"; async function showPreparationChecklist() { console.log( @@ -28,36 +18,35 @@ async function showPreparationChecklist() { ), ); console.log( - chalk.yellowBright("Before you begin, please have the following ready:\n"), - ); - - console.log(chalk.whiteBright("1. Stripe Test API Key (sk_test_...)")); - console.log( - chalk.gray( - " → Used to link Stripe to your test account for payment processing\n", + chalk.yellowBright( + "Before you begin, ensure the following are configured in your environment:\n", ), ); - console.log(chalk.whiteBright("2. Upstash Redis REST URL and Token")); + console.log(chalk.whiteBright("1. Stripe Sandbox Environment Variables")); + console.log(chalk.gray(" Required in your .env file:")); + console.log(chalk.gray(" → STRIPE_SANDBOX_CLIENT_ID")); + console.log(chalk.gray(" → STRIPE_SANDBOX_SECRET_KEY")); + console.log(chalk.gray(" → STRIPE_SANDBOX_WEBHOOK_SECRET\n")); + + console.log(chalk.whiteBright("2. Stripe Webhook URL")); console.log( chalk.gray( - " → Used for caching customer objects and testing race conditions\n", + " → A tunnel URL (e.g., ngrok) pointing to localhost:8080 for webhooks\n", ), ); - console.log(chalk.whiteBright("3. Tunnel URL (e.g., ngrok URL)")); - console.log( - chalk.gray( - " → Points to localhost:8080 so Stripe webhooks can reach your server\n", - ), - ); + console.log(chalk.whiteBright("3. Cache URL")); + console.log(chalk.gray(" → Redis on your machine\n")); // Prompt user to continue const { ready } = await inquirer.prompt([ { type: "confirm", name: "ready", - message: chalk.cyan("Ready to begin setup?"), + message: chalk.cyan( + "Have you configured all the above? Ready to create test org?", + ), default: true, }, ]); @@ -80,48 +69,9 @@ async function main() { // Import db from server const { db } = await import("@server/db/initDrizzle.js"); - // Step 1: Create test organization in database and get API key + // Create test organization in database and get API key const autumnSecretKey = await createTestOrg({ db }); - // Save org details immediately - updateMultipleEnvVars({ - TESTS_ORG: TEST_ORG_CONFIG.slug, - TESTS_ORG_ID: TEST_ORG_CONFIG.id, - ...(autumnSecretKey && { UNIT_TEST_AUTUMN_SECRET_KEY: autumnSecretKey }), - }); - - // Step 2: Get Stripe test key - const stripeTestKey = await setupStripeTestKey(); - - // Save Stripe key immediately - updateSingleEnvVar({ key: "STRIPE_TEST_KEY", value: stripeTestKey }); - - // Step 3: Get Upstash configuration - const { upstashUrl, upstashToken } = await setupUpstash(); - - // Save Upstash credentials immediately - updateMultipleEnvVars({ - UPSTASH_REDIS_REST_URL: upstashUrl, - UPSTASH_REDIS_REST_TOKEN: upstashToken, - }); - - // Step 4: Get tunnel URL - const tunnelUrl = await setupTunnelUrl(); - - // Save tunnel URL immediately - updateSingleEnvVar({ key: "STRIPE_WEBHOOK_URL", value: tunnelUrl }); - - // Step 5: Final update to ensure proper formatting - updateEnvFile({ - testOrgSlug: TEST_ORG_CONFIG.slug, - testOrgId: TEST_ORG_CONFIG.id, - autumnSecretKey, - stripeTestKey, - upstashUrl, - upstashToken, - tunnelUrl, - }); - console.log( chalk.magentaBright( "\n================ Setup Complete! ================\n", @@ -131,14 +81,7 @@ async function main() { console.log(chalk.cyan("Test Organization Details:")); console.log(chalk.whiteBright(` Organization: ${TEST_ORG_CONFIG.slug}`)); console.log(chalk.whiteBright(` ID: ${TEST_ORG_CONFIG.id}`)); - - if (autumnSecretKey) { - console.log(chalk.whiteBright(` Secret Key: ${autumnSecretKey}\n`)); - } else { - console.log( - chalk.whiteBright(" Secret Key: (using existing key from .env)\n"), - ); - } + console.log(chalk.whiteBright(` Secret Key: ${autumnSecretKey}\n`)); console.log(chalk.cyan("Next steps:")); console.log( diff --git a/scripts/setupTestUtils/createTestOrg.ts b/scripts/setupTestUtils/createTestOrg.ts index f2a62e852..a30ff74ad 100644 --- a/scripts/setupTestUtils/createTestOrg.ts +++ b/scripts/setupTestUtils/createTestOrg.ts @@ -1,8 +1,14 @@ -import { type OrgConfig, member, organizations, user } from "@autumn/shared"; +import { + AppEnv, + member, + type OrgConfig, + organizations, + user, +} from "@autumn/shared"; +import type { DrizzleCli } from "@server/db/initDrizzle.js"; +import { createHardcodedKey } from "@server/internal/dev/api-keys/apiKeyUtils.js"; import chalk from "chalk"; import { eq } from "drizzle-orm"; -import type { DrizzleCli } from "@server/db/initDrizzle.js"; -import { createKey } from "@server/internal/dev/api-keys/apiKeyUtils.js"; const TEST_ORG_CONFIG = { id: "org_2sWv2S8LJ9iaTjLI6UtNsfL88Kt", @@ -19,13 +25,20 @@ export async function createTestOrg({ db, }: { db: DrizzleCli; -}): Promise { +}): Promise { console.log( chalk.magentaBright( "\n================ Creating Test Organization ================\n", ), ); + const TEST_API_KEY = process.env.UNIT_TEST_AUTUMN_SECRET_KEY; + if (!TEST_API_KEY) { + throw new Error( + "UNIT_TEST_AUTUMN_SECRET_KEY is not set (is infisical running?)", + ); + } + // Check if org already exists const existingOrg = await db.query.organizations.findFirst({ where: eq(organizations.id, TEST_ORG_CONFIG.id), @@ -34,26 +47,31 @@ export async function createTestOrg({ if (existingOrg) { console.log( chalk.yellowBright( - `Test organization '${TEST_ORG_CONFIG.slug}' already exists. Creating new API key.`, + `Test organization '${TEST_ORG_CONFIG.slug}' already exists.`, ), ); - // Always create a new API key for existing org - const apiKey = await createKey({ + // Create API key for existing org (will skip if already exists) + const { key, alreadyExists } = await createHardcodedKey({ db, - env: "sandbox" as any, + env: AppEnv.Sandbox, name: "Unit Test Key", orgId: TEST_ORG_CONFIG.id, - prefix: "am_sk_test", + hardcodedKey: TEST_API_KEY, meta: { createdBy: "setup-test-script", createdAt: new Date().toISOString(), }, - userId: undefined, }); - console.log(chalk.greenBright("✅ Created API key for existing organization")); - return apiKey; + if (alreadyExists) { + console.log(chalk.greenBright("✅ API key already exists in database")); + } else { + console.log( + chalk.greenBright("✅ Created API key for existing organization"), + ); + } + return key; } // Create the test organization @@ -107,22 +125,25 @@ export async function createTestOrg({ } // Create API key for the new org - const apiKey = await createKey({ + const { key, alreadyExists } = await createHardcodedKey({ db, - env: "sandbox" as any, + env: AppEnv.Sandbox, name: "Unit Test Key", orgId: TEST_ORG_CONFIG.id, - prefix: "am_sk_test", + hardcodedKey: TEST_API_KEY, meta: { createdBy: "setup-test-script", createdAt: new Date().toISOString(), }, - userId: undefined, }); - console.log(chalk.greenBright("✅ Created API key for test organization")); + if (alreadyExists) { + console.log(chalk.greenBright("✅ API key already exists in database")); + } else { + console.log(chalk.greenBright("✅ Created API key for test organization")); + } - return apiKey; + return key; } export { TEST_ORG_CONFIG }; diff --git a/server/src/internal/dev/api-keys/apiKeyUtils.ts b/server/src/internal/dev/api-keys/apiKeyUtils.ts index 858ac2906..44ab1a3bb 100644 --- a/server/src/internal/dev/api-keys/apiKeyUtils.ts +++ b/server/src/internal/dev/api-keys/apiKeyUtils.ts @@ -44,7 +44,7 @@ export const createKey = async ({ name: string; orgId: string; prefix: string; - meta: any; + meta: Record; userId?: string; }) => { const apiKey = generateApiKey(42, prefix); @@ -67,6 +67,51 @@ export const createKey = async ({ return apiKey; }; +export const createHardcodedKey = async ({ + db, + env, + name, + orgId, + hardcodedKey, + meta, +}: { + db: DrizzleCli; + env: AppEnv; + name: string; + orgId: string; + hardcodedKey: string; + meta: Record; +}): Promise<{ key: string; alreadyExists: boolean }> => { + const hashedKey = hashApiKey(hardcodedKey); + + // Check if key already exists + const existing = await ApiKeyService.verifyAndFetch({ + db, + hashedKey, + env, + }); + + if (existing) { + return { key: hardcodedKey, alreadyExists: true }; + } + + const apiKeyData: ApiKey = { + id: generateId("key"), + org_id: orgId, + user_id: null, + name, + prefix: hardcodedKey.substring(0, 14), + created_at: Date.now(), + env, + hashed_key: hashedKey, + meta, + }; + + await ApiKeyService.insert({ db, apiKey: apiKeyData }); + + return { key: hardcodedKey, alreadyExists: false }; +}; + export const verifyKey = async ({ db, key,