UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

129 lines (128 loc) • 6.08 kB
import { i as normalizeOptionalString, l as isRecord } from "./string-coerce-6O-WySZM.js"; import "./src-BdCVpmTW.js"; import "@openclaw/fs-safe/path"; import path from "node:path"; import { AsyncLocalStorage } from "node:async_hooks"; import fs from "node:fs"; import { resolvePathViaExistingAncestorSync } from "@openclaw/fs-safe/advanced"; //#region packages/normalization-core/src/expect.ts /** Returns the value or throws with the named context; use for genuine invariants only. */ function expectDefined(value, context) { if (value === null || value === void 0) throw new Error("expected " + context + " to be defined"); return value; } //#endregion //#region src/secrets/ref-contract.ts /** Shared SecretRef grammar and validation helpers for config, schema, SDK, and gateway parity. */ /** Provider alias used when a SecretRef omits a source-specific provider. */ const DEFAULT_SECRET_PROVIDER_ALIAS = "default"; /** Strict env-var id shape accepted for env-backed SecretRefs. */ const ENV_SECRET_REF_ID_RE = /^[A-Z][A-Z0-9_]{0,127}$/; /** Narrow a value to the canonical SecretRef object shape. */ function isSecretRef(value) { if (!isRecord(value)) return false; if (Object.keys(value).length !== 3) return false; return (value.source === "env" || value.source === "file" || value.source === "exec" || value.source === "store") && typeof value.provider === "string" && value.provider.trim().length > 0 && typeof value.id === "string" && value.id.trim().length > 0; } /** * Runtime secret-reference grammar shared by config parsing, plugin SDK schemas, * gateway parity checks, and resolver planning. */ const FILE_SECRET_REF_SEGMENT_PATTERN = /^(?:[^~]|~0|~1)*$/; /** Shared alias grammar for env/file/exec/store secret provider names. */ const SECRET_PROVIDER_ALIAS_PATTERN = /^[a-z][a-z0-9_-]{0,63}$/; const EXEC_SECRET_REF_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/#-]{0,255}$/; /** Validates file secret ref ids against the shared JSON-pointer-style contract. */ function isValidFileSecretRefId(value) { if (value === "value") return true; if (!value.startsWith("/")) return false; return value.slice(1).split("/").every((segment) => FILE_SECRET_REF_SEGMENT_PATTERN.test(segment)); } /** Validates exec secret ref ids and reports why invalid ids failed. */ function validateExecSecretRefId(value) { if (!EXEC_SECRET_REF_ID_PATTERN.test(value)) return { ok: false, reason: "pattern" }; for (const segment of value.split("/")) if (segment === "." || segment === "..") return { ok: false, reason: "traversal-segment" }; return { ok: true }; } /** Boolean convenience wrapper for callers that only need accept/reject behavior. */ function isValidExecSecretRefId(value) { return validateExecSecretRefId(value).ok; } /** Formats the user-facing validation message for rejected exec secret ref ids. */ function formatExecSecretRefIdValidationMessage() { return [ "Exec secret reference id must match /^[A-Za-z0-9][A-Za-z0-9._:/#-]{0,255}$/", "and must not include \".\" or \"..\" path segments", "(example: \"vault/openai/api-key\" or \"aws/secret#json_key\")." ].join(" "); } //#endregion //#region src/infra/boundary-path.ts const runInBoundaryPathContext = AsyncLocalStorage.snapshot(); function resolvePathViaExistingAncestorSync$1(targetPath) { return runInBoundaryPathContext(resolvePathViaExistingAncestorSync, targetPath); } function resolveIdentityPathViaExistingAncestorSync(targetPath) { const fallback = path.resolve(targetPath); const missingSegments = []; let cursor = fallback; while (true) try { return path.join(fs.realpathSync.native(cursor), ...missingSegments.toReversed()); } catch { const parent = path.dirname(cursor); if (parent === cursor) return fallback; missingSegments.push(path.basename(cursor)); cursor = parent; } } //#endregion //#region src/config/types.secrets.ts const ENV_SECRET_TEMPLATE_RE = /^\$\{([A-Z][A-Z0-9_]{0,127})\}$/; const ENV_SECRET_SHORTHAND_RE = /^\$([A-Z][A-Z0-9_]{0,127})$/; function isLegacySecretRefWithoutProvider(value) { if (!isRecord(value)) return false; return (value.source === "env" || value.source === "file" || value.source === "exec" || value.source === "store") && typeof value.id === "string" && value.id.trim().length > 0 && value.provider === void 0; } /** Parse `$NAME` and `${NAME}` env-secret shorthand strings into env SecretRefs. */ function parseEnvTemplateSecretRef(value, provider = DEFAULT_SECRET_PROVIDER_ALIAS) { if (typeof value !== "string") return null; const trimmed = value.trim(); const match = ENV_SECRET_TEMPLATE_RE.exec(trimmed) ?? ENV_SECRET_SHORTHAND_RE.exec(trimmed); if (!match) return null; return { source: "env", provider: provider.trim() || "default", id: expectDefined(match[1], "types.secrets regex capture 1") }; } /** Coerce canonical and env-shorthand secret inputs into a SecretRef. * Retired string markers are parsed only by doctor migration above. */ function coerceSecretRef(value, defaults) { if (isSecretRef(value)) return value; if (isLegacySecretRefWithoutProvider(value)) { const provider = defaults?.[value.source] ?? "default"; return { source: value.source, provider, id: value.id }; } return parseEnvTemplateSecretRef(value, defaults?.env); } /** Return whether a value contains either a literal secret string or resolvable SecretRef shape. */ function hasConfiguredSecretInput(value, defaults) { if (normalizeSecretInputString(value)) return true; return coerceSecretRef(value, defaults) !== null; } /** Trim a literal secret input string while leaving non-string inputs unresolved. */ function normalizeSecretInputString(value) { return normalizeOptionalString(value); } //#endregion export { DEFAULT_SECRET_PROVIDER_ALIAS as a, formatExecSecretRefIdValidationMessage as c, expectDefined as d, resolvePathViaExistingAncestorSync$1 as i, isValidExecSecretRefId as l, parseEnvTemplateSecretRef as n, ENV_SECRET_REF_ID_RE as o, resolveIdentityPathViaExistingAncestorSync as r, SECRET_PROVIDER_ALIAS_PATTERN as s, hasConfiguredSecretInput as t, isValidFileSecretRefId as u };