CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | /**
* Block W2 — Claude harness configuration.
*
* Coverage:
* - .claude/settings.json is valid JSON
* - It declares the `gluecron` MCP server with the expected URL pattern
* - It denies the canonical 11 GitHub-write tool names
* - CLAUDE.md contains the "Source of truth: Gluecron" section
* - Each .claude/skills/<name>/SKILL.md exists with the expected
* frontmatter shape (name, description, tools)
*/
import { describe, it, expect } from "bun:test";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
const REPO_ROOT = join(import.meta.dir, "..", "..");
const SETTINGS_PATH = join(REPO_ROOT, ".claude", "settings.json");
const CLAUDE_MD = join(REPO_ROOT, "CLAUDE.md");
const SKILLS_DIR = join(REPO_ROOT, ".claude", "skills");
const SKILLS = ["gluecron-pr", "gluecron-issue", "gluecron-review"] as const;
const DENIED_GITHUB_WRITE_TOOLS = [
"mcp__github__create_pull_request",
"mcp__github__merge_pull_request",
"mcp__github__create_or_update_file",
"mcp__github__push_files",
"mcp__github__delete_file",
"mcp__github__create_branch",
"mcp__github__create_repository",
"mcp__github__create_pull_request_with_copilot",
"mcp__github__update_pull_request",
"mcp__github__update_pull_request_branch",
"mcp__github__merge_pull_request_with_copilot",
];
// ---------------------------------------------------------------------------
// .claude/settings.json shape
// ---------------------------------------------------------------------------
describe(".claude/settings.json", () => {
it("is valid JSON", async () => {
const raw = await readFile(SETTINGS_PATH, "utf8");
expect(() => JSON.parse(raw)).not.toThrow();
});
it("declares the gluecron MCP server", async () => {
const raw = await readFile(SETTINGS_PATH, "utf8");
const cfg = JSON.parse(raw) as {
mcpServers?: Record<string, { transport?: string; url?: string }>;
};
expect(cfg.mcpServers).toBeDefined();
expect(cfg.mcpServers!.gluecron).toBeDefined();
const entry = cfg.mcpServers!.gluecron!;
expect(entry.transport).toBe("http");
// URL ends with /mcp on a gluecron host.
expect(entry.url).toMatch(/gluecron[^\s]*\/mcp$/);
});
it("passes Authorization via env var (PAT never in file)", async () => {
const raw = await readFile(SETTINGS_PATH, "utf8");
const cfg = JSON.parse(raw) as {
mcpServers?: Record<
string,
{ headers?: Record<string, string> }
>;
};
const auth = cfg.mcpServers?.gluecron?.headers?.Authorization;
expect(auth).toBeDefined();
expect(auth).toContain("${env:GLUECRON_PAT}");
expect(auth).toMatch(/^Bearer\s/);
});
it(`denies all ${DENIED_GITHUB_WRITE_TOOLS.length} canonical GitHub write tools`, async () => {
const raw = await readFile(SETTINGS_PATH, "utf8");
const cfg = JSON.parse(raw) as {
permissions?: { deny?: string[] };
};
expect(cfg.permissions?.deny).toBeDefined();
const deny = cfg.permissions!.deny!;
for (const tool of DENIED_GITHUB_WRITE_TOOLS) {
expect(deny).toContain(tool);
}
});
});
// ---------------------------------------------------------------------------
// CLAUDE.md "Source of truth: Gluecron" section
// ---------------------------------------------------------------------------
describe("CLAUDE.md", () => {
it("contains the 'Source of truth: Gluecron' section", async () => {
const raw = await readFile(CLAUDE_MD, "utf8");
expect(raw).toContain("## Source of truth: Gluecron (not GitHub)");
});
it("references .claude/settings.json and the mcp-tools module", async () => {
const raw = await readFile(CLAUDE_MD, "utf8");
expect(raw).toContain(".claude/settings.json");
expect(raw).toContain("src/lib/mcp-tools.ts");
});
it("warns against calling mcp__github__* write tools", async () => {
const raw = await readFile(CLAUDE_MD, "utf8");
expect(raw).toContain("mcp__github__");
});
it("mentions the GLUECRON_PAT env var", async () => {
const raw = await readFile(CLAUDE_MD, "utf8");
expect(raw).toContain("GLUECRON_PAT");
});
});
// ---------------------------------------------------------------------------
// Each .claude/skills/<name>/SKILL.md exists and has the expected frontmatter
// ---------------------------------------------------------------------------
function parseFrontmatter(src: string): Record<string, string> {
if (!src.startsWith("---")) {
throw new Error("SKILL.md missing frontmatter");
}
const end = src.indexOf("\n---", 3);
if (end < 0) throw new Error("SKILL.md frontmatter not terminated");
const raw = src.slice(3, end).trim();
const fields: Record<string, string> = {};
let currentKey = "";
let buffer: string[] = [];
const flush = () => {
if (currentKey) {
fields[currentKey] = buffer.join("\n").trim();
}
buffer = [];
};
for (const line of raw.split("\n")) {
const m = /^([a-zA-Z_][a-zA-Z0-9_-]*):\s*(.*)$/.exec(line);
if (m && !line.startsWith(" ") && !line.startsWith("\t")) {
flush();
currentKey = m[1];
buffer = [m[2]];
} else {
buffer.push(line);
}
}
flush();
return fields;
}
describe(".claude/skills/* SKILL.md shape", () => {
for (const name of SKILLS) {
it(`${name}/SKILL.md exists and has name+description+tools`, async () => {
const path = join(SKILLS_DIR, name, "SKILL.md");
const raw = await readFile(path, "utf8");
const fields = parseFrontmatter(raw);
expect(fields.name).toBe(name);
expect(fields.description).toBeDefined();
expect(fields.description.length).toBeGreaterThan(0);
expect(fields.description.toLowerCase()).toContain("gluecron");
expect(fields.tools).toBeDefined();
expect(fields.tools.length).toBeGreaterThan(0);
});
}
});
|