mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
Config: bound schema lookup paths
This commit is contained in:
@@ -271,6 +271,31 @@ describe("config schema", () => {
|
||||
expect(lookupConfigSchema(baseSchema, "__proto__.polluted")).toBeNull();
|
||||
});
|
||||
|
||||
it("rejects overly deep lookup paths", () => {
|
||||
const buildNestedObjectSchema = (segments: string[]) => {
|
||||
const [head, ...rest] = segments;
|
||||
if (!head) {
|
||||
return { type: "string" };
|
||||
}
|
||||
return {
|
||||
type: "object",
|
||||
properties: {
|
||||
[head]: buildNestedObjectSchema(rest),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const deepPathSegments = Array.from({ length: 33 }, (_, index) => `a${index}`);
|
||||
const deepSchema = {
|
||||
schema: buildNestedObjectSchema(deepPathSegments),
|
||||
uiHints: {},
|
||||
version: "test",
|
||||
generatedAt: "test",
|
||||
} as unknown as Parameters<typeof lookupConfigSchema>[0];
|
||||
|
||||
expect(lookupConfigSchema(deepSchema, deepPathSegments.join("."))).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null for missing config schema paths", () => {
|
||||
expect(lookupConfigSchema(baseSchema, "gateway.notReal.path")).toBeNull();
|
||||
});
|
||||
|
||||
@@ -51,6 +51,7 @@ const LOOKUP_SCHEMA_BOOLEAN_KEYS = new Set([
|
||||
"readOnly",
|
||||
"writeOnly",
|
||||
]);
|
||||
const MAX_LOOKUP_PATH_SEGMENTS = 32;
|
||||
|
||||
function cloneSchema<T>(value: T): T {
|
||||
if (typeof structuredClone === "function") {
|
||||
@@ -682,12 +683,16 @@ export function lookupConfigSchema(
|
||||
if (!normalizedPath) {
|
||||
return null;
|
||||
}
|
||||
const parts = splitLookupPath(normalizedPath);
|
||||
if (parts.length === 0 || parts.length > MAX_LOOKUP_PATH_SEGMENTS) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let current = asSchemaObject(response.schema);
|
||||
if (!current) {
|
||||
return null;
|
||||
}
|
||||
for (const segment of splitLookupPath(normalizedPath)) {
|
||||
for (const segment of parts) {
|
||||
const next = resolveLookupChildSchema(current, segment);
|
||||
if (!next) {
|
||||
return null;
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import { NonEmptyString } from "./primitives.js";
|
||||
|
||||
const NonWhitespaceString = Type.String({ minLength: 1, pattern: ".*\\S.*" });
|
||||
const ConfigSchemaLookupPathString = Type.String({
|
||||
minLength: 1,
|
||||
maxLength: 1024,
|
||||
pattern: "^[A-Za-z0-9_.\\[\\]\\-*]+$",
|
||||
});
|
||||
|
||||
export const ConfigGetParamsSchema = Type.Object({}, { additionalProperties: false });
|
||||
|
||||
@@ -31,7 +35,7 @@ export const ConfigSchemaParamsSchema = Type.Object({}, { additionalProperties:
|
||||
|
||||
export const ConfigSchemaLookupParamsSchema = Type.Object(
|
||||
{
|
||||
path: NonWhitespaceString,
|
||||
path: ConfigSchemaLookupPathString,
|
||||
},
|
||||
{ additionalProperties: false },
|
||||
);
|
||||
|
||||
@@ -87,6 +87,24 @@ describe("gateway config methods", () => {
|
||||
expect(res.error?.message ?? "").toContain("invalid config.schema.lookup params");
|
||||
});
|
||||
|
||||
it("rejects config.schema.lookup when the path exceeds the protocol limit", async () => {
|
||||
const res = await rpcReq<{ ok?: boolean }>(requireWs(), "config.schema.lookup", {
|
||||
path: `gateway.${"a".repeat(1020)}`,
|
||||
});
|
||||
|
||||
expect(res.ok).toBe(false);
|
||||
expect(res.error?.message ?? "").toContain("invalid config.schema.lookup params");
|
||||
});
|
||||
|
||||
it("rejects config.schema.lookup when the path contains invalid characters", async () => {
|
||||
const res = await rpcReq<{ ok?: boolean }>(requireWs(), "config.schema.lookup", {
|
||||
path: "gateway.auth\nspoof",
|
||||
});
|
||||
|
||||
expect(res.ok).toBe(false);
|
||||
expect(res.error?.message ?? "").toContain("invalid config.schema.lookup params");
|
||||
});
|
||||
|
||||
it("rejects prototype-chain config.schema.lookup paths without reflecting them", async () => {
|
||||
const res = await rpcReq<{ ok?: boolean }>(requireWs(), "config.schema.lookup", {
|
||||
path: "constructor",
|
||||
|
||||
Reference in New Issue
Block a user