import { assert, assertEquals } from "jsr:@std/assert@1"; import { parse } from "jsr:@std/yaml@1"; type Mapping = Record; const mapping = (value: unknown, at: string): Mapping => { assert( typeof value === "object" && value !== null && !Array.isArray(value), at, ); return value as Mapping; }; const sequence = (value: unknown, at: string): Mapping[] => { assert(Array.isArray(value), at); return value.map((entry, index) => mapping(entry, `${at}[${index}]`)); }; async function yaml(path: string): Promise { return mapping(parse(await Deno.readTextFile(path)), path); } async function yamlFiles(directory = "."): Promise { const result: string[] = []; for await (const entry of Deno.readDir(directory)) { if (entry.name === ".git" || entry.name === ".superpowers") continue; const path = directory === "." ? entry.name : `${directory}/${entry.name}`; if (entry.isDirectory) result.push(...await yamlFiles(path)); if (entry.isFile && /\.ya?ml$/.test(entry.name)) result.push(path); } return result; } Deno.test("all committed YAML parses", async () => { const files = await yamlFiles(); assert(files.length > 0); for (const file of files) await yaml(file); }); Deno.test("the action exposes only the master key and scopes it to preparation", async () => { const action = await yaml("action.yml"); assertEquals(Object.keys(mapping(action.inputs, "inputs")), ["master-key"]); const steps = sequence(mapping(action.runs, "runs").steps, "runs.steps"); const checkout = steps.find((step) => step.uses === "actions/checkout@v4"); const prepare = steps.find((step) => step.id === "prepare"); const agent = steps.find((step) => step.id === "agent"); const post = steps.find((step) => step.id === "post"); const source = steps.find((step) => step.id === "source"); assert(checkout && source && prepare && agent && post); assertEquals( mapping(checkout.with, "checkout.with").token, "${{ gitea.token }}", ); assertEquals( mapping(prepare.env, "prepare.env").BOT_AGENTS_MASTER_KEY, "${{ inputs.master-key }}", ); assertEquals(JSON.stringify(agent).includes("BOT_AGENTS_MASTER_KEY"), false); assertEquals(JSON.stringify(post).includes("BOT_AGENTS_MASTER_KEY"), false); assertEquals( mapping(agent.env, "agent.env").GITEA_TOKEN, "${{ gitea.token }}", ); assert(String(post.if).includes("always()")); for (const step of [prepare, agent, post]) { assert(String(step.run).includes("steps.source.outputs.path")); } }); Deno.test("the repository uses its trusted main action", async () => { const workflow = await yaml(".gitea/workflows/agents.yml"); const job = mapping(mapping(workflow.jobs, "jobs").agent, "jobs.agent"); const permissions = mapping(job.permissions, "jobs.agent.permissions"); assertEquals(permissions, { code: "write", issues: "write", "pull-requests": "write", }); const steps = sequence(job.steps, "jobs.agent.steps"); const local = steps.findIndex((step) => step.uses === "./"); assertEquals(local, -1); const trusted = steps.findIndex((step) => step.uses === "https://git.capsulizers.com/commons/bot-agents@main" ); assert(trusted >= 0); assertEquals( mapping(steps[trusted].with, "trusted.with")["master-key"], "${{ secrets.BOT_AGENTS_MASTER_KEY }}", ); assertEquals(JSON.stringify(workflow).includes("gitea.actor != 'bot'"), true); }); Deno.test("CI checks every phase and the root isolation suite", async () => { const workflow = await yaml(".gitea/workflows/check.yml"); const job = mapping(mapping(workflow.jobs, "jobs").deno, "jobs.deno"); const commands = sequence(job.steps, "jobs.deno.steps") .map((step) => typeof step.run === "string" ? step.run : "") .join("\n"); for (const entrypoint of ["prepare.ts", "run.ts", "post.ts"]) { assert(commands.includes(entrypoint), entrypoint); } assert(commands.includes("deno test --allow-all")); }); Deno.test("uses the standard Skills installer without custom discovery", async () => { const runner = await Deno.readTextFile("run.ts"); assert(runner.includes("skills add obra/superpowers")); try { await Deno.stat("superpowers.ts"); assert(false, "superpowers.ts should be removed"); } catch (error) { assert(error instanceof Deno.errors.NotFound); } });