refactor(config): tighten plugin config guardrails

This commit is contained in:
Peter Steinberger
2026-04-27 13:46:23 +01:00
parent ef9d108436
commit 5dd1e264eb
16 changed files with 789 additions and 649 deletions

View File

@@ -1,94 +1,10 @@
#!/usr/bin/env node
import fs from "node:fs";
import path from "node:path";
const repoRoot = path.resolve(new URL("..", import.meta.url).pathname);
const CHANNEL_EXTENSION_IDS = new Set([
"discord",
"imessage",
"irc",
"line",
"matrix",
"mattermost",
"nextcloud-talk",
"signal",
"slack",
"telegram",
"whatsapp",
]);
const HELPER_BASENAME_PATTERNS = [
/^action-runtime\.ts$/,
/^actions(?:\..*)?\.ts$/,
/^active-listener\.ts$/,
/^access-control\.ts$/,
/^channel\.ts$/,
/^client(?:[-.].*)?\.ts$/,
/^recipient-resolution\.ts$/,
/^rich-menu\.ts$/,
/^send(?:[-.].*)?\.ts$/,
/^sent-message-cache\.ts$/,
/^thread-bindings\.ts$/,
];
const FORBIDDEN_PATTERNS = [/\bloadConfig\s*\(/, /\.config\.loadConfig\s*\(/];
function* walk(dir) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
if (entry.name === "node_modules" || entry.name === "dist") {
continue;
}
const absolute = path.join(dir, entry.name);
if (entry.isDirectory()) {
yield* walk(absolute);
continue;
}
yield absolute;
}
}
function isCandidate(relativePath) {
const parts = relativePath.split(path.sep);
if (parts[0] !== "extensions" || parts[2] !== "src") {
return false;
}
if (!CHANNEL_EXTENSION_IDS.has(parts[1])) {
return false;
}
if (
relativePath.endsWith(".test.ts") ||
relativePath.endsWith(".test-harness.ts") ||
relativePath.endsWith(".d.ts")
) {
return false;
}
if (parts.includes("monitor") || parts.includes("cli")) {
return false;
}
if (parts.includes("actions")) {
return true;
}
const basename = path.basename(relativePath);
return HELPER_BASENAME_PATTERNS.some((pattern) => pattern.test(basename));
}
import { collectRuntimeActionLoadConfigViolations } from "./lib/config-boundary-guard.mjs";
function main() {
const violations = [];
for (const absolute of walk(path.join(repoRoot, "extensions"))) {
const relativePath = path.relative(repoRoot, absolute);
if (!isCandidate(relativePath)) {
continue;
}
const lines = fs.readFileSync(absolute, "utf8").split(/\r?\n/);
lines.forEach((line, index) => {
if (FORBIDDEN_PATTERNS.some((pattern) => pattern.test(line))) {
violations.push(`${relativePath}:${index + 1}: ${line.trim()}`);
}
});
}
const violations = collectRuntimeActionLoadConfigViolations();
if (violations.length === 0) {
return;
return 0;
}
console.error(
[
@@ -98,7 +14,7 @@ function main() {
...violations,
].join("\n"),
);
process.exitCode = 1;
return 1;
}
main();
process.exitCode = main();