mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-30 01:06:11 +00:00
Config: enforce source-specific SecretRef id validation
This commit is contained in:
committed by
Peter Steinberger
parent
c3a4251a60
commit
d00ed73026
@@ -56,4 +56,54 @@ describe("config secret refs schema", () => {
|
||||
).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects env refs that are not env var names", () => {
|
||||
const result = validateConfigObjectRaw({
|
||||
models: {
|
||||
providers: {
|
||||
openai: {
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
apiKey: { source: "env", id: "/providers/openai/apiKey" },
|
||||
models: [{ id: "gpt-5", name: "gpt-5" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
if (!result.ok) {
|
||||
expect(
|
||||
result.issues.some(
|
||||
(issue) =>
|
||||
issue.path.includes("models.providers.openai.apiKey") &&
|
||||
issue.message.includes("Env secret reference id"),
|
||||
),
|
||||
).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects file refs that are not absolute JSON pointers", () => {
|
||||
const result = validateConfigObjectRaw({
|
||||
models: {
|
||||
providers: {
|
||||
openai: {
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
apiKey: { source: "file", id: "providers/openai/apiKey" },
|
||||
models: [{ id: "gpt-5", name: "gpt-5" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
if (!result.ok) {
|
||||
expect(
|
||||
result.issues.some(
|
||||
(issue) =>
|
||||
issue.path.includes("models.providers.openai.apiKey") &&
|
||||
issue.message.includes("absolute JSON pointer"),
|
||||
),
|
||||
).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,20 +3,48 @@ import { isSafeExecutableValue } from "../infra/exec-safety.js";
|
||||
import { createAllowDenyChannelRulesSchema } from "./zod-schema.allowdeny.js";
|
||||
import { sensitive } from "./zod-schema.sensitive.js";
|
||||
|
||||
const SECRET_REF_ID_PATTERN = /^[A-Za-z0-9_./:=-](?:[A-Za-z0-9_./:=~-]{0,127})$/;
|
||||
const ENV_SECRET_REF_ID_PATTERN = /^[A-Z][A-Z0-9_]{0,127}$/;
|
||||
const FILE_SECRET_REF_SEGMENT_PATTERN = /^(?:[^~]|~0|~1)*$/;
|
||||
|
||||
export const SecretRefSchema = z
|
||||
function isValidFileSecretRefId(value: string): boolean {
|
||||
if (!value.startsWith("/")) {
|
||||
return false;
|
||||
}
|
||||
return value
|
||||
.slice(1)
|
||||
.split("/")
|
||||
.every((segment) => FILE_SECRET_REF_SEGMENT_PATTERN.test(segment));
|
||||
}
|
||||
|
||||
const EnvSecretRefSchema = z
|
||||
.object({
|
||||
source: z.enum(["env", "file"]),
|
||||
source: z.literal("env"),
|
||||
id: z
|
||||
.string()
|
||||
.regex(
|
||||
SECRET_REF_ID_PATTERN,
|
||||
"Secret reference id must match /^[A-Za-z0-9_./:=-](?:[A-Za-z0-9_./:=~-]{0,127})$/",
|
||||
ENV_SECRET_REF_ID_PATTERN,
|
||||
'Env secret reference id must match /^[A-Z][A-Z0-9_]{0,127}$/ (example: "OPENAI_API_KEY").',
|
||||
),
|
||||
})
|
||||
.strict();
|
||||
|
||||
const FileSecretRefSchema = z
|
||||
.object({
|
||||
source: z.literal("file"),
|
||||
id: z
|
||||
.string()
|
||||
.refine(
|
||||
isValidFileSecretRefId,
|
||||
'File secret reference id must be an absolute JSON pointer (example: "/providers/openai/apiKey").',
|
||||
),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const SecretRefSchema = z.discriminatedUnion("source", [
|
||||
EnvSecretRefSchema,
|
||||
FileSecretRefSchema,
|
||||
]);
|
||||
|
||||
export const SecretInputSchema = z.union([z.string(), SecretRefSchema]);
|
||||
|
||||
const SecretsEnvSourceSchema = z
|
||||
|
||||
Reference in New Issue
Block a user