UNPKG

alepha

Version:

Easy-to-use modern TypeScript framework for building many kind of applications.

303 lines (253 loc) 9.07 kB
import { Alepha } from "alepha"; import { MemorySecretStore, platformOptions, type SecretStoreProvider, } from "alepha/cli/platform-lib"; import { CliProvider } from "alepha/command"; import { FileSystemProvider, MemoryFileSystemProvider } from "alepha/system"; import { describe, test } from "vitest"; import { SecretsCommand } from "../commands/SecretsCommand.ts"; class TestSecretsCommand extends SecretsCommand { public readonly testList = this.list; public readonly testDiff = this.diff; public readonly testApply = this.apply; public testStore: MemorySecretStore | null = null; public override resolveStore(): SecretStoreProvider { if (this.testStore) return this.testStore; return super.resolveStore(); } } describe("SecretsCommand", () => { const createTestEnv = ( config: Record<string, any> = {}, storeSecrets: Record<string, Record<string, string>> = {}, ) => { const alepha = Alepha.create().with({ provide: FileSystemProvider, use: MemoryFileSystemProvider, }); const fs = alepha.inject(MemoryFileSystemProvider); const store = new MemorySecretStore(); const cli = alepha.inject(CliProvider); const cmd = alepha.inject(TestSecretsCommand); cmd.testStore = store; alepha.set(platformOptions, { name: "my-app", environments: { production: { adapter: "cloudflare" } }, ...config, } as any); // Seed package.json fs.writeFile("/project/package.json", JSON.stringify({ name: "my-app" })); // Seed store with pre-existing secrets for (const [env, secrets] of Object.entries(storeSecrets)) { const envMap = new Map<string, string>(); for (const [k, v] of Object.entries(secrets)) { envMap.set(k, v); } store.secrets.set(env, envMap); } return { alepha, fs, store, cli, cmd }; }; // ----------------------------------------------------------------------- // apply // ----------------------------------------------------------------------- describe("apply", () => { test("filters and pushes secrets to store", async ({ expect }) => { const { fs, store, cli, cmd } = createTestEnv(); await fs.writeFile( "/project/.env.production", "DATABASE_URL=postgres://localhost/db\nAPI_KEY=abc123\nNODE_ENV=production\nVITE_APP=hello\nEMPTY=", ); await cli.run(cmd.testApply, { root: "/project", argv: "--env production", }); expect(store.wasSet("my-app-production", "DATABASE_URL")).toBe(true); expect(store.wasSet("my-app-production", "API_KEY")).toBe(true); expect(store.wasSet("my-app-production", "NODE_ENV")).toBe(false); expect(store.wasSet("my-app-production", "VITE_APP")).toBe(false); expect(store.wasSet("my-app-production", "EMPTY")).toBe(false); }); test("renames GITHUB_ keys with APP_ prefix", async ({ expect }) => { const { fs, store, cli, cmd } = createTestEnv(); await fs.writeFile( "/project/.env.production", "GITHUB_CLIENT_ID=id123\nGITHUB_CLIENT_SECRET=secret456", ); await cli.run(cmd.testApply, { root: "/project", argv: "--env production", }); expect(store.wasSet("my-app-production", "APP_GITHUB_CLIENT_ID")).toBe( true, ); expect( store.wasSet("my-app-production", "APP_GITHUB_CLIENT_SECRET"), ).toBe(true); expect(store.wasSet("my-app-production", "GITHUB_CLIENT_ID")).toBe(false); }); test("dry run does not call store", async ({ expect }) => { const { fs, store, cli, cmd } = createTestEnv(); await fs.writeFile( "/project/.env.production", "API_KEY=abc123\nSECRET=xyz", ); await cli.run(cmd.testApply, { root: "/project", argv: "--env production --dry-run", }); expect(store.calls.filter((c) => c.method === "set")).toHaveLength(0); }); test("uses custom environment pattern", async ({ expect }) => { const { fs, store, cli, cmd } = createTestEnv({ secrets: { store: "github", environmentPattern: "{env}", }, }); await fs.writeFile("/project/.env.production", "API_KEY=abc123"); await cli.run(cmd.testApply, { root: "/project", argv: "--env production", }); expect(store.wasSet("production", "API_KEY")).toBe(true); }); }); // ----------------------------------------------------------------------- // diff // ----------------------------------------------------------------------- describe("diff", () => { test("detects only-local, only-remote, and in-both keys", async ({ expect, }) => { const { fs, cli, cmd } = createTestEnv( {}, { "my-app-production": { API_KEY: "remote-value", OLD_SECRET: "stale", }, }, ); await fs.writeFile( "/project/.env.production", "API_KEY=local-value\nNEW_SECRET=fresh", ); // Capture stdout const writes: string[] = []; const originalWrite = process.stdout.write; process.stdout.write = ((chunk: string) => { writes.push(chunk); return true; }) as any; try { await cli.run(cmd.testDiff, { root: "/project", argv: "--env production", }); } finally { process.stdout.write = originalWrite; } // biome-ignore lint/suspicious/noControlCharactersInRegex: stripping ANSI codes const output = writes.join("").replace(/\x1B\[[0-9;]*m/g, ""); expect(output).toContain("+ NEW_SECRET"); expect(output).toContain("- OLD_SECRET"); expect(output).toContain("= API_KEY"); }); }); // ----------------------------------------------------------------------- // list // ----------------------------------------------------------------------- describe("list", () => { test("shows table format by default", async ({ expect }) => { const { cli, cmd } = createTestEnv( {}, { "my-app-production": { API_KEY: "value1", DATABASE_URL: "value2", }, }, ); const writes: string[] = []; const originalWrite = process.stdout.write; process.stdout.write = ((chunk: string) => { writes.push(chunk); return true; }) as any; try { await cli.run(cmd.testList, { root: "/project", argv: "--env production", }); } finally { process.stdout.write = originalWrite; } const output = writes.join(""); expect(output).toContain("API_KEY"); expect(output).toContain("DATABASE_URL"); }); test("shows GHA format", async ({ expect }) => { const { cli, cmd } = createTestEnv( {}, { "my-app-production": { API_KEY: "value1", APP_GITHUB_CLIENT_ID: "value2", }, }, ); const writes: string[] = []; const originalWrite = process.stdout.write; process.stdout.write = ((chunk: string) => { writes.push(chunk); return true; }) as any; try { await cli.run(cmd.testList, { root: "/project", argv: "--env production --format gha", }); } finally { process.stdout.write = originalWrite; } const output = writes.join(""); expect(output).toContain("env:"); // biome-ignore lint/suspicious/noTemplateCurlyInString: GitHub Actions `${{ ... }}` syntax in plain string expect(output).toContain("API_KEY: ${{ secrets.API_KEY }}"); expect(output).toContain( // biome-ignore lint/suspicious/noTemplateCurlyInString: GitHub Actions `${{ ... }}` syntax in plain string "GITHUB_CLIENT_ID: ${{ secrets.APP_GITHUB_CLIENT_ID }}", ); }); }); // ----------------------------------------------------------------------- // environment name resolution // ----------------------------------------------------------------------- describe("environment name resolution", () => { test("uses default pattern {project}-{env}", async ({ expect }) => { const { fs, store, cli, cmd } = createTestEnv(); await fs.writeFile("/project/.env.production", "KEY=val"); await cli.run(cmd.testApply, { root: "/project", argv: "--env production", }); expect(store.wasSet("my-app-production", "KEY")).toBe(true); }); test("uses custom pattern", async ({ expect }) => { const { fs, store, cli, cmd } = createTestEnv({ secrets: { store: "github", environmentPattern: "deploy-{project}-{env}", }, }); await fs.writeFile("/project/.env.production", "KEY=val"); await cli.run(cmd.testApply, { root: "/project", argv: "--env production", }); expect(store.wasSet("deploy-my-app-production", "KEY")).toBe(true); }); }); });