/* Unit tests for cache clone commit guard covering cache-clone commit guard (RFC-0821). Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only. RFC-1311: Compass header sweep — declares the cache suite's contract for test-file scaffold coverage. */ import { describe, it, expect } from "vitest"; import { readFileSync, readdirSync, existsSync, statSync } from "node:fs"; import path from "node:path"; const SRC_DIR = path.resolve(__dirname, ".."); function findTsFiles(dir: string, results: string[] = []): string[] { if (!existsSync(dir)) return results; const entries = readdirSync(dir); for (const entry of entries) { const fullPath = path.join(dir, entry); const stat = statSync(fullPath); if (stat.isDirectory() && entry !== "node_modules" && entry !== "tests-handoff") { findTsFiles(fullPath, results); } else if ( entry.endsWith(".ts") && !entry.endsWith(".test.ts") && !entry.endsWith(".spec.ts") ) { results.push(fullPath); } } return results; } /** * Check if a line is inside a block comment or is a line comment. */ function isInComment(fileContent: string, targetLineIdx: number): boolean { const lines = fileContent.split("\n"); let inBlockComment = false; for (let i = 0; i <= targetLineIdx && i < lines.length; i++) { const line = lines[i]; if (inBlockComment) { if (line.includes("*/")) { inBlockComment = false; } if (i === targetLineIdx) return true; } else { if (line.trim().startsWith("//")) { if (i === targetLineIdx) return true; continue; } if (line.includes("/*")) { inBlockComment = true; if (i === targetLineIdx) return true; } } } return false; } describe("cache-clone commit guard (RFC-0821)", () => { it("no raw git commit without MISSION_GIT_COMMIT env var in src/**", () => { const files = findTsFiles(SRC_DIR); const violations: Array<{ file: string; line: number; content: string }> = []; for (const file of files) { const content = readFileSync(file, "utf-8"); const lines = content.split("\n"); for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (isInComment(content, i)) continue; // Only match actual function calls that execute git commit (not rev-parse, etc.): // execSync(`git commit ...`), gitExec(dir, `commit ...`), git(dir, `commit ...`) // Also match execSync("git commit ...") with double quotes const hasExecGitCommit = (line.includes("execSync(") || line.includes("await gitExec(") || /\bgit\(/.test(line)) && (line.includes("commit -m") || line.includes("commit -m") || line.includes("`commit ") || line.includes('"commit ')); if (!hasExecGitCommit) continue; // Skip allowed helpers that handle MISSION_GIT_COMMIT internally if ( line.includes("cacheCloneCommit") || line.includes("commitDirIfDirty") || line.includes("commitAndPushBordbuch") || line.includes("appendAndCommitBordbuch") || line.includes("commitBordbuchProjections") || line.includes("commitWerkstattSideEffects") || line.includes("createSignedCommit") || line.includes("commitWorkpieceIfDirty") || line.includes("commitCacheCloneIfDirty") ) { continue; } // Skip the git() and gitExec helpers themselves if (file.endsWith("mission-git-commit.ts")) continue; if (file.endsWith("git-exec.ts")) continue; // signed-commit.ts uses the git() helper from mission-git-commit.ts which sets MISSION_GIT_COMMIT if (file.endsWith("signed-commit.ts")) continue; // Skip --no-verify commits (intentionally bypasses hook) if (line.includes("--no-verify")) continue; // Check surrounding context (current line + next 5 lines) for MISSION_GIT_COMMIT const context = lines.slice(i, Math.min(i + 6, lines.length)).join("\n"); if (!context.includes("MISSION_GIT_COMMIT") && !context.includes("ECOSYSTEM_COMMIT")) { violations.push({ file: path.relative(SRC_DIR, file), line: i + 1, content: line.trim(), }); } } } if (violations.length > 0) { const formatted = violations.map((v) => ` ${v.file}:${v.line} — ${v.content}`).join("\n"); expect.fail( `Found ${violations.length} raw git commit call(s) without MISSION_GIT_COMMIT env var.\n` + `Use cacheCloneCommit() from mission-git-commit.ts instead.\n` + `Violations:\n${formatted}`, ); } }); });