mirror of
https://fastgit.cc/github.com/openclaw/openclaw
synced 2026-04-20 21:02:10 +08:00
lint: share sensitive url config rules
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { promises as fs } from "node:fs";
|
||||
/**
|
||||
* Lint: detect schema URL config fields that are missing redact coverage.
|
||||
*
|
||||
@@ -14,12 +15,11 @@
|
||||
*
|
||||
* That prevents regressions like the browser.cdpUrl omission from PR #67679.
|
||||
*
|
||||
* The isSensitiveUrlConfigPath rules are extracted from source instead of being
|
||||
* duplicated manually, so this lint always matches the real runtime behavior.
|
||||
* The sensitive-path rules come from the same shared JSON data used by runtime
|
||||
* code, so this lint stays aligned with real behavior without parsing source.
|
||||
*/
|
||||
|
||||
import { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
import sensitiveUrlConfigRules from "../src/shared/net/sensitive-url-config-rules.json" with { type: "json" };
|
||||
|
||||
// These URL-shaped field names do not carry credentials and do not need redaction.
|
||||
const SAFE_URL_PATTERNS = [
|
||||
@@ -33,50 +33,19 @@ function isSafeUrlField(key) {
|
||||
return SAFE_URL_PATTERNS.some((p) => p.test(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract path suffix rules for isSensitiveUrlConfigPath() directly from
|
||||
* redact-sensitive-url.ts by parsing endsWith(".xxx") calls.
|
||||
*/
|
||||
function extractEndsWithRules(source) {
|
||||
const rules = [];
|
||||
// Match path.endsWith(".xxx") patterns.
|
||||
const endsWithPattern = /path\.endsWith\("(\.[^"]+)"\)/g;
|
||||
let match;
|
||||
while ((match = endsWithPattern.exec(source)) !== null) {
|
||||
rules.push(match[1]);
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract regex rules directly from redact-sensitive-url.ts by parsing
|
||||
* /^...$/ regex literals used against config paths.
|
||||
*/
|
||||
function extractRegexRules(source) {
|
||||
const rules = [];
|
||||
// Match /pattern/.test(path) patterns.
|
||||
const regexPattern = /\/(\^[^/]+)\$\/\.test\(path\)/g;
|
||||
let match;
|
||||
while ((match = regexPattern.exec(source)) !== null) {
|
||||
rules.push(new RegExp(match[1] + "$"));
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an isSensitiveUrlConfigPath equivalent from rules extracted from source.
|
||||
*/
|
||||
function buildIsSensitiveUrlConfigPath(source) {
|
||||
const endsWithRules = extractEndsWithRules(source);
|
||||
const regexRules = extractRegexRules(source);
|
||||
const SENSITIVE_URL_CONFIG_SUFFIXES = sensitiveUrlConfigRules.suffixes;
|
||||
const SENSITIVE_URL_CONFIG_PATTERNS = sensitiveUrlConfigRules.patterns.map(
|
||||
(pattern) => new RegExp(pattern),
|
||||
);
|
||||
|
||||
function buildIsSensitiveUrlConfigPath() {
|
||||
return function isSensitiveUrlConfigPath(configPath) {
|
||||
for (const suffix of endsWithRules) {
|
||||
for (const suffix of SENSITIVE_URL_CONFIG_SUFFIXES) {
|
||||
if (configPath.endsWith(suffix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const regex of regexRules) {
|
||||
for (const regex of SENSITIVE_URL_CONFIG_PATTERNS) {
|
||||
if (regex.test(configPath)) {
|
||||
return true;
|
||||
}
|
||||
@@ -87,11 +56,7 @@ function buildIsSensitiveUrlConfigPath(source) {
|
||||
|
||||
async function run() {
|
||||
const repoRoot = path.resolve(import.meta.dirname, "..");
|
||||
|
||||
// Read redact-sensitive-url.ts and extract the sensitive-path rules.
|
||||
const redactSourcePath = path.join(repoRoot, "src/shared/net/redact-sensitive-url.ts");
|
||||
const redactSource = await fs.readFile(redactSourcePath, "utf8");
|
||||
const isSensitiveUrlConfigPath = buildIsSensitiveUrlConfigPath(redactSource);
|
||||
const isSensitiveUrlConfigPath = buildIsSensitiveUrlConfigPath();
|
||||
|
||||
// Read schema.base.generated.ts and inspect its URL-shaped config fields.
|
||||
const schemaPath = path.join(repoRoot, "src/config/schema.base.generated.ts");
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import type { ConfigUiHint } from "../config-ui-hints-types.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../string-coerce.js";
|
||||
import sensitiveUrlConfigRules from "./sensitive-url-config-rules.json" with { type: "json" };
|
||||
|
||||
export const SENSITIVE_URL_HINT_TAG = "url-secret";
|
||||
const SENSITIVE_URL_CONFIG_SUFFIXES = sensitiveUrlConfigRules.suffixes;
|
||||
const SENSITIVE_URL_CONFIG_PATTERNS = sensitiveUrlConfigRules.patterns.map(
|
||||
(pattern) => new RegExp(pattern),
|
||||
);
|
||||
|
||||
const SENSITIVE_URL_QUERY_PARAM_NAMES = new Set([
|
||||
"token",
|
||||
@@ -22,19 +27,12 @@ export function isSensitiveUrlQueryParamName(name: string): boolean {
|
||||
}
|
||||
|
||||
export function isSensitiveUrlConfigPath(path: string): boolean {
|
||||
if (path.endsWith(".baseUrl") || path.endsWith(".httpUrl")) {
|
||||
return true;
|
||||
for (const suffix of SENSITIVE_URL_CONFIG_SUFFIXES) {
|
||||
if (path.endsWith(suffix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (path.endsWith(".cdpUrl")) {
|
||||
return true;
|
||||
}
|
||||
if (path.endsWith(".remote.url")) {
|
||||
return true;
|
||||
}
|
||||
if (path.endsWith(".request.proxy.url")) {
|
||||
return true;
|
||||
}
|
||||
return /^mcp\.servers\.(?:\*|[^.]+)\.url$/.test(path);
|
||||
return SENSITIVE_URL_CONFIG_PATTERNS.some((pattern) => pattern.test(path));
|
||||
}
|
||||
|
||||
export function hasSensitiveUrlHintTag(hint: Pick<ConfigUiHint, "tags"> | undefined): boolean {
|
||||
|
||||
4
src/shared/net/sensitive-url-config-rules.json
Normal file
4
src/shared/net/sensitive-url-config-rules.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"suffixes": [".baseUrl", ".httpUrl", ".cdpUrl", ".remote.url", ".request.proxy.url"],
|
||||
"patterns": ["^mcp\\.servers\\.(?:\\*|[^.]+)\\.url$"]
|
||||
}
|
||||
Reference in New Issue
Block a user