mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
refactor(scripts): share guard runners and paged select UI
This commit is contained in:
@@ -1,24 +1,22 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import path from "node:path";
|
||||
import ts from "typescript";
|
||||
import { createPairingGuardContext } from "./lib/pairing-guard-context.mjs";
|
||||
import {
|
||||
collectFileViolations,
|
||||
getPropertyNameText,
|
||||
resolveRepoRoot,
|
||||
runAsScript,
|
||||
toLine,
|
||||
} from "./lib/ts-guard-utils.mjs";
|
||||
|
||||
const repoRoot = resolveRepoRoot(import.meta.url);
|
||||
const sourceRoots = [path.join(repoRoot, "src"), path.join(repoRoot, "extensions")];
|
||||
const { repoRoot, sourceRoots, resolveFromRepo } = createPairingGuardContext(import.meta.url);
|
||||
|
||||
const allowedFiles = new Set([
|
||||
path.join(repoRoot, "src", "security", "dm-policy-shared.ts"),
|
||||
path.join(repoRoot, "src", "channels", "allow-from.ts"),
|
||||
resolveFromRepo("src/security/dm-policy-shared.ts"),
|
||||
resolveFromRepo("src/channels/allow-from.ts"),
|
||||
// Config migration/audit logic may intentionally reference store + group fields.
|
||||
path.join(repoRoot, "src", "security", "fix.ts"),
|
||||
path.join(repoRoot, "src", "security", "audit-channel.ts"),
|
||||
resolveFromRepo("src/security/fix.ts"),
|
||||
resolveFromRepo("src/security/audit-channel.ts"),
|
||||
]);
|
||||
|
||||
const storeIdentifierRe = /^(?:storeAllowFrom|storedAllowFrom|storeAllowList)$/i;
|
||||
|
||||
@@ -1,25 +1,17 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
import ts from "typescript";
|
||||
import {
|
||||
collectTypeScriptFiles,
|
||||
resolveRepoRoot,
|
||||
runAsScript,
|
||||
toLine,
|
||||
unwrapExpression,
|
||||
} from "./lib/ts-guard-utils.mjs";
|
||||
import { runCallsiteGuard } from "./lib/callsite-guard.mjs";
|
||||
import { runAsScript, toLine, unwrapExpression } from "./lib/ts-guard-utils.mjs";
|
||||
|
||||
const repoRoot = resolveRepoRoot(import.meta.url);
|
||||
const sourceRoots = [
|
||||
path.join(repoRoot, "src", "channels"),
|
||||
path.join(repoRoot, "src", "infra", "outbound"),
|
||||
path.join(repoRoot, "src", "line"),
|
||||
path.join(repoRoot, "src", "media-understanding"),
|
||||
path.join(repoRoot, "extensions"),
|
||||
"src/channels",
|
||||
"src/infra/outbound",
|
||||
"src/line",
|
||||
"src/media-understanding",
|
||||
"extensions",
|
||||
];
|
||||
const allowedCallsites = new Set([path.join(repoRoot, "extensions", "feishu", "src", "dedup.ts")]);
|
||||
const allowedRelativePaths = new Set(["extensions/feishu/src/dedup.ts"]);
|
||||
|
||||
function collectOsTmpdirImports(sourceFile) {
|
||||
const osModuleSpecifiers = new Set(["node:os", "os"]);
|
||||
@@ -82,40 +74,16 @@ export function findMessagingTmpdirCallLines(content, fileName = "source.ts") {
|
||||
}
|
||||
|
||||
export async function main() {
|
||||
const files = (
|
||||
await Promise.all(
|
||||
sourceRoots.map(
|
||||
async (dir) =>
|
||||
await collectTypeScriptFiles(dir, {
|
||||
ignoreMissing: true,
|
||||
}),
|
||||
),
|
||||
)
|
||||
).flat();
|
||||
const violations = [];
|
||||
|
||||
for (const filePath of files) {
|
||||
if (allowedCallsites.has(filePath)) {
|
||||
continue;
|
||||
}
|
||||
const content = await fs.readFile(filePath, "utf8");
|
||||
for (const line of findMessagingTmpdirCallLines(content, filePath)) {
|
||||
violations.push(`${path.relative(repoRoot, filePath)}:${line}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (violations.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.error("Found os.tmpdir()/tmpdir() usage in messaging/channel runtime sources:");
|
||||
for (const violation of violations) {
|
||||
console.error(`- ${violation}`);
|
||||
}
|
||||
console.error(
|
||||
"Use resolvePreferredOpenClawTmpDir() or plugin-sdk temp helpers instead of host tmp defaults.",
|
||||
);
|
||||
process.exit(1);
|
||||
await runCallsiteGuard({
|
||||
importMetaUrl: import.meta.url,
|
||||
sourceRoots,
|
||||
findCallLines: findMessagingTmpdirCallLines,
|
||||
skipRelativePath: (relativePath) => allowedRelativePaths.has(relativePath),
|
||||
header: "Found os.tmpdir()/tmpdir() usage in messaging/channel runtime sources:",
|
||||
footer:
|
||||
"Use resolvePreferredOpenClawTmpDir() or plugin-sdk temp helpers instead of host tmp defaults.",
|
||||
sortViolations: false,
|
||||
});
|
||||
}
|
||||
|
||||
runAsScript(import.meta.url, main);
|
||||
|
||||
@@ -1,28 +1,20 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
import ts from "typescript";
|
||||
import {
|
||||
collectTypeScriptFiles,
|
||||
resolveRepoRoot,
|
||||
runAsScript,
|
||||
toLine,
|
||||
unwrapExpression,
|
||||
} from "./lib/ts-guard-utils.mjs";
|
||||
import { runCallsiteGuard } from "./lib/callsite-guard.mjs";
|
||||
import { runAsScript, toLine, unwrapExpression } from "./lib/ts-guard-utils.mjs";
|
||||
|
||||
const repoRoot = resolveRepoRoot(import.meta.url);
|
||||
const sourceRoots = [
|
||||
path.join(repoRoot, "src", "telegram"),
|
||||
path.join(repoRoot, "src", "discord"),
|
||||
path.join(repoRoot, "src", "slack"),
|
||||
path.join(repoRoot, "src", "signal"),
|
||||
path.join(repoRoot, "src", "imessage"),
|
||||
path.join(repoRoot, "src", "web"),
|
||||
path.join(repoRoot, "src", "channels"),
|
||||
path.join(repoRoot, "src", "routing"),
|
||||
path.join(repoRoot, "src", "line"),
|
||||
path.join(repoRoot, "extensions"),
|
||||
"src/telegram",
|
||||
"src/discord",
|
||||
"src/slack",
|
||||
"src/signal",
|
||||
"src/imessage",
|
||||
"src/web",
|
||||
"src/channels",
|
||||
"src/routing",
|
||||
"src/line",
|
||||
"extensions",
|
||||
];
|
||||
|
||||
// Temporary allowlist for legacy callsites. New raw fetch callsites in channel/plugin runtime
|
||||
@@ -100,43 +92,15 @@ export function findRawFetchCallLines(content, fileName = "source.ts") {
|
||||
}
|
||||
|
||||
export async function main() {
|
||||
const files = (
|
||||
await Promise.all(
|
||||
sourceRoots.map(
|
||||
async (sourceRoot) =>
|
||||
await collectTypeScriptFiles(sourceRoot, {
|
||||
extraTestSuffixes: [".browser.test.ts", ".node.test.ts"],
|
||||
ignoreMissing: true,
|
||||
}),
|
||||
),
|
||||
)
|
||||
).flat();
|
||||
|
||||
const violations = [];
|
||||
for (const filePath of files) {
|
||||
const content = await fs.readFile(filePath, "utf8");
|
||||
const relPath = path.relative(repoRoot, filePath).replaceAll(path.sep, "/");
|
||||
for (const line of findRawFetchCallLines(content, filePath)) {
|
||||
const callsite = `${relPath}:${line}`;
|
||||
if (allowedRawFetchCallsites.has(callsite)) {
|
||||
continue;
|
||||
}
|
||||
violations.push(callsite);
|
||||
}
|
||||
}
|
||||
|
||||
if (violations.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.error("Found raw fetch() usage in channel/plugin runtime sources outside allowlist:");
|
||||
for (const violation of violations.toSorted()) {
|
||||
console.error(`- ${violation}`);
|
||||
}
|
||||
console.error(
|
||||
"Use fetchWithSsrFGuard() or existing channel/plugin SDK wrappers for network calls.",
|
||||
);
|
||||
process.exit(1);
|
||||
await runCallsiteGuard({
|
||||
importMetaUrl: import.meta.url,
|
||||
sourceRoots,
|
||||
extraTestSuffixes: [".browser.test.ts", ".node.test.ts"],
|
||||
findCallLines: findRawFetchCallLines,
|
||||
allowCallsite: (callsite) => allowedRawFetchCallsites.has(callsite),
|
||||
header: "Found raw fetch() usage in channel/plugin runtime sources outside allowlist:",
|
||||
footer: "Use fetchWithSsrFGuard() or existing channel/plugin SDK wrappers for network calls.",
|
||||
});
|
||||
}
|
||||
|
||||
runAsScript(import.meta.url, main);
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import path from "node:path";
|
||||
import ts from "typescript";
|
||||
import { createPairingGuardContext } from "./lib/pairing-guard-context.mjs";
|
||||
import {
|
||||
collectFileViolations,
|
||||
getPropertyNameText,
|
||||
resolveRepoRoot,
|
||||
runAsScript,
|
||||
toLine,
|
||||
} from "./lib/ts-guard-utils.mjs";
|
||||
|
||||
const repoRoot = resolveRepoRoot(import.meta.url);
|
||||
const sourceRoots = [path.join(repoRoot, "src"), path.join(repoRoot, "extensions")];
|
||||
const { repoRoot, sourceRoots } = createPairingGuardContext(import.meta.url);
|
||||
|
||||
function isUndefinedLikeExpression(node) {
|
||||
if (ts.isIdentifier(node) && node.text === "undefined") {
|
||||
|
||||
45
scripts/lib/callsite-guard.mjs
Normal file
45
scripts/lib/callsite-guard.mjs
Normal file
@@ -0,0 +1,45 @@
|
||||
import { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
import {
|
||||
collectTypeScriptFilesFromRoots,
|
||||
resolveRepoRoot,
|
||||
resolveSourceRoots,
|
||||
} from "./ts-guard-utils.mjs";
|
||||
|
||||
export async function runCallsiteGuard(params) {
|
||||
const repoRoot = resolveRepoRoot(params.importMetaUrl);
|
||||
const sourceRoots = resolveSourceRoots(repoRoot, params.sourceRoots);
|
||||
const files = await collectTypeScriptFilesFromRoots(sourceRoots, {
|
||||
extraTestSuffixes: params.extraTestSuffixes,
|
||||
});
|
||||
const violations = [];
|
||||
|
||||
for (const filePath of files) {
|
||||
const relPath = path.relative(repoRoot, filePath).replaceAll(path.sep, "/");
|
||||
if (params.skipRelativePath?.(relPath)) {
|
||||
continue;
|
||||
}
|
||||
const content = await fs.readFile(filePath, "utf8");
|
||||
for (const line of params.findCallLines(content, filePath)) {
|
||||
const callsite = `${relPath}:${line}`;
|
||||
if (params.allowCallsite?.(callsite)) {
|
||||
continue;
|
||||
}
|
||||
violations.push(callsite);
|
||||
}
|
||||
}
|
||||
|
||||
if (violations.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(params.header);
|
||||
const output = params.sortViolations === false ? violations : violations.toSorted();
|
||||
for (const violation of output) {
|
||||
console.error(`- ${violation}`);
|
||||
}
|
||||
if (params.footer) {
|
||||
console.error(params.footer);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
13
scripts/lib/pairing-guard-context.mjs
Normal file
13
scripts/lib/pairing-guard-context.mjs
Normal file
@@ -0,0 +1,13 @@
|
||||
import path from "node:path";
|
||||
import { resolveRepoRoot, resolveSourceRoots } from "./ts-guard-utils.mjs";
|
||||
|
||||
export function createPairingGuardContext(importMetaUrl) {
|
||||
const repoRoot = resolveRepoRoot(importMetaUrl);
|
||||
const sourceRoots = resolveSourceRoots(repoRoot, ["src", "extensions"]);
|
||||
return {
|
||||
repoRoot,
|
||||
sourceRoots,
|
||||
resolveFromRepo: (relativePath) =>
|
||||
path.join(repoRoot, ...relativePath.split("/").filter(Boolean)),
|
||||
};
|
||||
}
|
||||
@@ -9,6 +9,10 @@ export function resolveRepoRoot(importMetaUrl) {
|
||||
return path.resolve(path.dirname(fileURLToPath(importMetaUrl)), "..", "..");
|
||||
}
|
||||
|
||||
export function resolveSourceRoots(repoRoot, relativeRoots) {
|
||||
return relativeRoots.map((root) => path.join(repoRoot, ...root.split("/").filter(Boolean)));
|
||||
}
|
||||
|
||||
export function isTestLikeTypeScriptFile(filePath, options = {}) {
|
||||
const extraTestSuffixes = options.extraTestSuffixes ?? [];
|
||||
return [...baseTestSuffixes, ...extraTestSuffixes].some((suffix) => filePath.endsWith(suffix));
|
||||
@@ -68,18 +72,24 @@ export async function collectTypeScriptFiles(targetPath, options = {}) {
|
||||
return out;
|
||||
}
|
||||
|
||||
export async function collectFileViolations(params) {
|
||||
const files = (
|
||||
export async function collectTypeScriptFilesFromRoots(sourceRoots, options = {}) {
|
||||
return (
|
||||
await Promise.all(
|
||||
params.sourceRoots.map(
|
||||
sourceRoots.map(
|
||||
async (root) =>
|
||||
await collectTypeScriptFiles(root, {
|
||||
ignoreMissing: true,
|
||||
extraTestSuffixes: params.extraTestSuffixes,
|
||||
...options,
|
||||
}),
|
||||
),
|
||||
)
|
||||
).flat();
|
||||
}
|
||||
|
||||
export async function collectFileViolations(params) {
|
||||
const files = await collectTypeScriptFilesFromRoots(params.sourceRoots, {
|
||||
extraTestSuffixes: params.extraTestSuffixes,
|
||||
});
|
||||
|
||||
const violations = [];
|
||||
for (const filePath of files) {
|
||||
|
||||
Reference in New Issue
Block a user