chore: update meta-audits + add opencode coupling grep gate
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import { readdir, readFile } from "node:fs/promises"
|
import { readdir, readFile, stat } from "node:fs/promises"
|
||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
import ts from "typescript"
|
import ts from "typescript"
|
||||||
|
|
||||||
const SOURCE_ROOT = path.resolve(import.meta.dir, "..")
|
const SOURCE_ROOT = path.resolve(import.meta.dir, "..")
|
||||||
|
const WORKSPACE_ROOT = path.resolve(SOURCE_ROOT, "..")
|
||||||
const MOCK_MODULE_TOKEN = "mock.module"
|
const MOCK_MODULE_TOKEN = "mock.module"
|
||||||
const MOCK_MODULE_LIFECYCLE_ALLOWLIST = new Map<string, string>([
|
const MOCK_MODULE_LIFECYCLE_ALLOWLIST = new Map<string, string>([
|
||||||
// TODO(MOCK-MODULE-AUDIT): add cleanup for team mailbox inbox module mocks.
|
// TODO(MOCK-MODULE-AUDIT): add cleanup for team mailbox inbox module mocks.
|
||||||
@@ -79,6 +80,31 @@ async function listTestFiles(directory: string): Promise<string[]> {
|
|||||||
return nestedFiles.flat()
|
return nestedFiles.flat()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function listPackageTestFiles(): Promise<string[]> {
|
||||||
|
const packagesDir = path.join(WORKSPACE_ROOT, "packages")
|
||||||
|
let packageNames: string[] = []
|
||||||
|
try {
|
||||||
|
packageNames = await readdir(packagesDir)
|
||||||
|
} catch {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const nestedFiles = await Promise.all(packageNames.map(async (name) => {
|
||||||
|
const packageSrc = path.join(packagesDir, name, "src")
|
||||||
|
try {
|
||||||
|
const s = await stat(packageSrc)
|
||||||
|
if (!s.isDirectory()) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return listTestFiles(packageSrc)
|
||||||
|
}))
|
||||||
|
|
||||||
|
return nestedFiles.flat()
|
||||||
|
}
|
||||||
|
|
||||||
function relativeSourcePath(filePath: string): string {
|
function relativeSourcePath(filePath: string): string {
|
||||||
return path.relative(SOURCE_ROOT, filePath)
|
return path.relative(SOURCE_ROOT, filePath)
|
||||||
}
|
}
|
||||||
@@ -177,7 +203,7 @@ function hasCleanupPattern(sourceFile: ts.SourceFile): boolean {
|
|||||||
describe("mock.module lifecycle hygiene", () => {
|
describe("mock.module lifecycle hygiene", () => {
|
||||||
test("#given test files using mock.module #when audited #then each must pair with cleanup", async () => {
|
test("#given test files using mock.module #when audited #then each must pair with cleanup", async () => {
|
||||||
// given
|
// given
|
||||||
const files = await listTestFiles(SOURCE_ROOT)
|
const files = [...await listTestFiles(SOURCE_ROOT), ...await listPackageTestFiles()]
|
||||||
const offenders: string[] = []
|
const offenders: string[] = []
|
||||||
|
|
||||||
// when
|
// when
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import { describe, expect, test } from "bun:test"
|
||||||
|
import { readdir, readFile } from "node:fs/promises"
|
||||||
|
import path from "node:path"
|
||||||
|
|
||||||
|
const WORKSPACE_ROOT = path.resolve(import.meta.dir, "../..")
|
||||||
|
const PACKAGES_DIR = path.join(WORKSPACE_ROOT, "packages")
|
||||||
|
const SKIP_PACKAGES = new Set(["ast-grep-mcp", "lsp-tools-mcp"])
|
||||||
|
|
||||||
|
const OPENCODE_IMPORT_RE = /from\s+['"](@opencode-ai\/[^'"]+|opencode\/[^'"]+)['"]/
|
||||||
|
const BUN_API_RE = /\bBun\.(spawn|file|write|which|hash)\b/
|
||||||
|
|
||||||
|
async function listPackageSourceFiles(): Promise<string[]> {
|
||||||
|
let packageNames: string[] = []
|
||||||
|
try {
|
||||||
|
packageNames = await readdir(PACKAGES_DIR)
|
||||||
|
} catch {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const nestedFiles = await Promise.all(packageNames.map(async (name) => {
|
||||||
|
if (SKIP_PACKAGES.has(name)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const packageSrc = path.join(PACKAGES_DIR, name, "src")
|
||||||
|
const entries = await listSourceFilesRecursive(packageSrc)
|
||||||
|
return entries
|
||||||
|
}))
|
||||||
|
|
||||||
|
return nestedFiles.flat()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function listSourceFilesRecursive(directory: string): Promise<string[]> {
|
||||||
|
let entries: { name: string; isDirectory(): boolean; isFile(): boolean }[] = []
|
||||||
|
try {
|
||||||
|
entries = await readdir(directory, { withFileTypes: true })
|
||||||
|
} catch {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const nestedFiles = await Promise.all(entries.map(async (entry) => {
|
||||||
|
const entryPath = path.join(directory, entry.name)
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
return listSourceFilesRecursive(entryPath)
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
entry.isFile()
|
||||||
|
&& entry.name.endsWith(".ts")
|
||||||
|
&& !entry.name.endsWith(".test.ts")
|
||||||
|
&& !entry.name.endsWith(".d.ts")
|
||||||
|
) {
|
||||||
|
return [entryPath]
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}))
|
||||||
|
|
||||||
|
return nestedFiles.flat()
|
||||||
|
}
|
||||||
|
|
||||||
|
function relativeWorkspacePath(filePath: string): string {
|
||||||
|
return path.relative(WORKSPACE_ROOT, filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("package opencode coupling grep gate", () => {
|
||||||
|
test("#given package source files #when audited #then no file imports from @opencode-ai/* or opencode/", async () => {
|
||||||
|
// given
|
||||||
|
const files = await listPackageSourceFiles()
|
||||||
|
const offenders: string[] = []
|
||||||
|
|
||||||
|
// when
|
||||||
|
for (const filePath of files) {
|
||||||
|
const contents = await readFile(filePath, "utf8")
|
||||||
|
const lines = contents.split("\n")
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
const line = lines[i]
|
||||||
|
const match = OPENCODE_IMPORT_RE.exec(line)
|
||||||
|
if (match) {
|
||||||
|
offenders.push(`${relativeWorkspacePath(filePath)}:${i + 1} imports ${match[1]}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(offenders.sort()).toEqual([])
|
||||||
|
}, 20_000)
|
||||||
|
|
||||||
|
test("#given package source files #when audited #then no file uses Bun.spawn, Bun.file, Bun.write, Bun.which, or Bun.hash", async () => {
|
||||||
|
// given
|
||||||
|
const files = await listPackageSourceFiles()
|
||||||
|
const offenders: string[] = []
|
||||||
|
|
||||||
|
// when
|
||||||
|
for (const filePath of files) {
|
||||||
|
const contents = await readFile(filePath, "utf8")
|
||||||
|
const lines = contents.split("\n")
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
const line = lines[i]
|
||||||
|
const match = BUN_API_RE.exec(line)
|
||||||
|
if (match) {
|
||||||
|
offenders.push(`${relativeWorkspacePath(filePath)}:${i + 1} uses ${match[0]}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(offenders.sort()).toEqual([])
|
||||||
|
}, 20_000)
|
||||||
|
})
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import { readdir, readFile } from "node:fs/promises"
|
import { readdir, readFile, stat } from "node:fs/promises"
|
||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
import ts from "typescript"
|
import ts from "typescript"
|
||||||
|
|
||||||
const SOURCE_ROOT = path.resolve(import.meta.dir, "..")
|
const SOURCE_ROOT = path.resolve(import.meta.dir, "..")
|
||||||
|
const WORKSPACE_ROOT = path.resolve(SOURCE_ROOT, "..")
|
||||||
const PROMPT_GATE_FILE = path.join(SOURCE_ROOT, "shared", "prompt-async-gate.ts")
|
const PROMPT_GATE_FILE = path.join(SOURCE_ROOT, "shared", "prompt-async-gate.ts")
|
||||||
const RAW_PROMPT_ALLOWLIST = new Map<string, string>([
|
const RAW_PROMPT_ALLOWLIST = new Map<string, string>([
|
||||||
[
|
[
|
||||||
@@ -45,6 +46,31 @@ async function listSourceFiles(directory: string): Promise<string[]> {
|
|||||||
return nestedFiles.flat()
|
return nestedFiles.flat()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function listPackageSourceFiles(): Promise<string[]> {
|
||||||
|
const packagesDir = path.join(WORKSPACE_ROOT, "packages")
|
||||||
|
let packageNames: string[] = []
|
||||||
|
try {
|
||||||
|
packageNames = await readdir(packagesDir)
|
||||||
|
} catch {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const nestedFiles = await Promise.all(packageNames.map(async (name) => {
|
||||||
|
const packageSrc = path.join(packagesDir, name, "src")
|
||||||
|
try {
|
||||||
|
const s = await stat(packageSrc)
|
||||||
|
if (!s.isDirectory()) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return listSourceFiles(packageSrc)
|
||||||
|
}))
|
||||||
|
|
||||||
|
return nestedFiles.flat()
|
||||||
|
}
|
||||||
|
|
||||||
function relativeSourcePath(filePath: string): string {
|
function relativeSourcePath(filePath: string): string {
|
||||||
return path.relative(SOURCE_ROOT, filePath)
|
return path.relative(SOURCE_ROOT, filePath)
|
||||||
}
|
}
|
||||||
@@ -334,7 +360,7 @@ await dispatchInternalPrompt(options)
|
|||||||
|
|
||||||
test("#given production TypeScript sources #when prompt routes are audited #then only the shared gate may call raw OpenCode prompt APIs", async () => {
|
test("#given production TypeScript sources #when prompt routes are audited #then only the shared gate may call raw OpenCode prompt APIs", async () => {
|
||||||
// given
|
// given
|
||||||
const files = await listSourceFiles(SOURCE_ROOT)
|
const files = [...await listSourceFiles(SOURCE_ROOT), ...await listPackageSourceFiles()]
|
||||||
const offenders: string[] = []
|
const offenders: string[] = []
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -358,7 +384,7 @@ await dispatchInternalPrompt(options)
|
|||||||
|
|
||||||
test("#given production TypeScript sources #when prompt gate callers are audited #then callers cannot disable the post-dispatch reservation hold", async () => {
|
test("#given production TypeScript sources #when prompt gate callers are audited #then callers cannot disable the post-dispatch reservation hold", async () => {
|
||||||
// given
|
// given
|
||||||
const files = await listSourceFiles(SOURCE_ROOT)
|
const files = [...await listSourceFiles(SOURCE_ROOT), ...await listPackageSourceFiles()]
|
||||||
const offenders: string[] = []
|
const offenders: string[] = []
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -375,7 +401,7 @@ await dispatchInternalPrompt(options)
|
|||||||
|
|
||||||
test("#given production TypeScript sources #when prompt gate callers are audited #then callers cannot bypass the central prompt queue", async () => {
|
test("#given production TypeScript sources #when prompt gate callers are audited #then callers cannot bypass the central prompt queue", async () => {
|
||||||
// given
|
// given
|
||||||
const files = await listSourceFiles(SOURCE_ROOT)
|
const files = [...await listSourceFiles(SOURCE_ROOT), ...await listPackageSourceFiles()]
|
||||||
const offenders: string[] = []
|
const offenders: string[] = []
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -392,7 +418,7 @@ await dispatchInternalPrompt(options)
|
|||||||
|
|
||||||
test("#given production TypeScript sources #when prompt gate callers are audited #then every route declares queue behavior explicitly", async () => {
|
test("#given production TypeScript sources #when prompt gate callers are audited #then every route declares queue behavior explicitly", async () => {
|
||||||
// given
|
// given
|
||||||
const files = await listSourceFiles(SOURCE_ROOT)
|
const files = [...await listSourceFiles(SOURCE_ROOT), ...await listPackageSourceFiles()]
|
||||||
const offenders: string[] = []
|
const offenders: string[] = []
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -413,7 +439,7 @@ await dispatchInternalPrompt(options)
|
|||||||
|
|
||||||
test("#given production TypeScript sources #when model-suggestion prompt wrappers are audited #then every retry caller declares queue behavior explicitly", async () => {
|
test("#given production TypeScript sources #when model-suggestion prompt wrappers are audited #then every retry caller declares queue behavior explicitly", async () => {
|
||||||
// given
|
// given
|
||||||
const files = await listSourceFiles(SOURCE_ROOT)
|
const files = [...await listSourceFiles(SOURCE_ROOT), ...await listPackageSourceFiles()]
|
||||||
const offenders: string[] = []
|
const offenders: string[] = []
|
||||||
|
|
||||||
// when
|
// when
|
||||||
|
|||||||
Reference in New Issue
Block a user