mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-27 20:00:42 +00:00
Secrets: reject exec SecretRef traversal ids across schema/runtime/gateway (#42370)
* Secrets: harden exec SecretRef validation and reload LKG coverage * Tests: harden exec fast-exit stdin regression case * Tests: align lifecycle daemon test formatting with oxfmt 0.36
This commit is contained in:
34
src/gateway/protocol/primitives.secretref.test.ts
Normal file
34
src/gateway/protocol/primitives.secretref.test.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import AjvPkg from "ajv";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
INVALID_EXEC_SECRET_REF_IDS,
|
||||
VALID_EXEC_SECRET_REF_IDS,
|
||||
} from "../../test-utils/secret-ref-test-vectors.js";
|
||||
import { SecretInputSchema, SecretRefSchema } from "./schema/primitives.js";
|
||||
|
||||
describe("gateway protocol SecretRef schema", () => {
|
||||
const Ajv = AjvPkg as unknown as new (opts?: object) => import("ajv").default;
|
||||
const ajv = new Ajv({ allErrors: true, strict: false });
|
||||
const validateSecretRef = ajv.compile(SecretRefSchema);
|
||||
const validateSecretInput = ajv.compile(SecretInputSchema);
|
||||
|
||||
it("accepts valid source-specific refs", () => {
|
||||
expect(validateSecretRef({ source: "env", provider: "default", id: "OPENAI_API_KEY" })).toBe(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
validateSecretRef({ source: "file", provider: "filemain", id: "/providers/openai/apiKey" }),
|
||||
).toBe(true);
|
||||
for (const id of VALID_EXEC_SECRET_REF_IDS) {
|
||||
expect(validateSecretRef({ source: "exec", provider: "vault", id }), id).toBe(true);
|
||||
expect(validateSecretInput({ source: "exec", provider: "vault", id }), id).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects invalid exec refs", () => {
|
||||
for (const id of INVALID_EXEC_SECRET_REF_IDS) {
|
||||
expect(validateSecretRef({ source: "exec", provider: "vault", id }), id).toBe(false);
|
||||
expect(validateSecretInput({ source: "exec", provider: "vault", id }), id).toBe(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,10 @@
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import { ENV_SECRET_REF_ID_RE } from "../../../config/types.secrets.js";
|
||||
import {
|
||||
EXEC_SECRET_REF_ID_JSON_SCHEMA_PATTERN,
|
||||
FILE_SECRET_REF_ID_PATTERN,
|
||||
SECRET_PROVIDER_ALIAS_PATTERN,
|
||||
} from "../../../secrets/ref-contract.js";
|
||||
import { SESSION_LABEL_MAX_LENGTH } from "../../../sessions/session-label.js";
|
||||
import { GATEWAY_CLIENT_IDS, GATEWAY_CLIENT_MODES } from "../client-info.js";
|
||||
|
||||
@@ -27,13 +33,41 @@ export const SecretRefSourceSchema = Type.Union([
|
||||
Type.Literal("exec"),
|
||||
]);
|
||||
|
||||
export const SecretRefSchema = Type.Object(
|
||||
const SecretProviderAliasString = Type.String({
|
||||
pattern: SECRET_PROVIDER_ALIAS_PATTERN.source,
|
||||
});
|
||||
|
||||
const EnvSecretRefSchema = Type.Object(
|
||||
{
|
||||
source: SecretRefSourceSchema,
|
||||
provider: NonEmptyString,
|
||||
id: NonEmptyString,
|
||||
source: Type.Literal("env"),
|
||||
provider: SecretProviderAliasString,
|
||||
id: Type.String({ pattern: ENV_SECRET_REF_ID_RE.source }),
|
||||
},
|
||||
{ additionalProperties: false },
|
||||
);
|
||||
|
||||
const FileSecretRefSchema = Type.Object(
|
||||
{
|
||||
source: Type.Literal("file"),
|
||||
provider: SecretProviderAliasString,
|
||||
id: Type.String({ pattern: FILE_SECRET_REF_ID_PATTERN.source }),
|
||||
},
|
||||
{ additionalProperties: false },
|
||||
);
|
||||
|
||||
const ExecSecretRefSchema = Type.Object(
|
||||
{
|
||||
source: Type.Literal("exec"),
|
||||
provider: SecretProviderAliasString,
|
||||
id: Type.String({ pattern: EXEC_SECRET_REF_ID_JSON_SCHEMA_PATTERN }),
|
||||
},
|
||||
{ additionalProperties: false },
|
||||
);
|
||||
|
||||
export const SecretRefSchema = Type.Union([
|
||||
EnvSecretRefSchema,
|
||||
FileSecretRefSchema,
|
||||
ExecSecretRefSchema,
|
||||
]);
|
||||
|
||||
export const SecretInputSchema = Type.Union([Type.String(), SecretRefSchema]);
|
||||
|
||||
Reference in New Issue
Block a user