Repository Public MIT
1import { execFileSync } from "node:child_process";2import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";3import { randomBytes } from "node:crypto";45/** Creates a disposable publisher through the server console and ensures demo content exists. */6export default async function globalSetup() {7 const base = process.env.E2E_BASE_URL ?? "http://localhost:8570";8 if (/skills\.spboucher\.ai/.test(base) && process.env.E2E_READONLY !== "1") throw new Error("Refusing to run mutating E2E tests against production. Set E2E_READONLY=1 for the public-only subset.");9 mkdirSync("test-results", { recursive: true });10 const stateFile = "test-results/e2e-state.json";11 if (process.env.E2E_READONLY === "1") {12 writeFileSync(stateFile, JSON.stringify({ readonly: true, namespace: process.env.E2E_NAMESPACE ?? "spboucher" }));13 return;14 }15 const id = randomBytes(4).toString("hex");16 const pwFile = `test-results/e2e-pw-${id}.txt`;17 const email = `e2e-${id}@example.test`;18 const namespace = `e2e-${id}`;19 execFileSync("pnpm", ["-s", "admin", "user", "create", "--email", email, "--name", "E2E Publisher", "--namespace", namespace, "--password-out", pwFile], { stdio: "pipe" });20 const initialPassword = readFileSync(pwFile, "utf8").trim();21 rmSync(pwFile);22 // Demo content: publish the registry's own examples into the dev database when missing.23 const res = await fetch(`${base}/api/v1/artifacts/spboucher/hello-skill`);24 if (res.status === 404 && existsSync("/tmp/skills-dev-cred.json")) {25 for (const e of ["hello-skill", "citation-check", "echo-mcp-server"]) {26 execFileSync("pnpm", ["-s", "skills", "publish", `examples/${e}`, "--visibility", "public", "--yes"], { stdio: "pipe", env: { ...process.env, SKILLS_REGISTRY: base, SKILLS_CREDENTIAL_STORE: "file:/tmp/skills-dev-cred.json" } });27 }28 }29 // A publisher token for specs that publish through the HTTP API (never printed, never committed).30 const tokenFile = `test-results/e2e-token-${id}.txt`;31 execFileSync("pnpm", ["-s", "admin", "token", "create", "--user", email, "--name", "e2e-api", "--namespace", namespace, "--expires-in", "1d", "--token-out", tokenFile], { stdio: "pipe" });32 const token = readFileSync(tokenFile, "utf8").trim();33 rmSync(tokenFile);34 writeFileSync(stateFile, JSON.stringify({ email, namespace, initialPassword, token, password: `e2e-${randomBytes(12).toString("hex")}` }), { mode: 0o600 });35}36