| import { |
| DEFAULT_SECRET_PROVIDER_ALIAS, |
| type SecretRef, |
| type SecretRefSource, |
| } from "../config/types.secrets.js"; |
|
|
| const FILE_SECRET_REF_SEGMENT_PATTERN = /^(?:[^~]|~0|~1)*$/; |
| export 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}$/; |
|
|
| export const SINGLE_VALUE_FILE_REF_ID = "value"; |
| export const FILE_SECRET_REF_ID_PATTERN = /^(?:value|\/(?:[^~]|~0|~1)*(?:\/(?:[^~]|~0|~1)*)*)$/; |
| export const EXEC_SECRET_REF_ID_JSON_SCHEMA_PATTERN = |
| "^(?!.*(?:^|/)\\.{1,2}(?:/|$))[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$"; |
|
|
| export type ExecSecretRefIdValidationReason = "pattern" | "traversal-segment"; |
|
|
| export type ExecSecretRefIdValidationResult = |
| | { ok: true } |
| | { |
| ok: false; |
| reason: ExecSecretRefIdValidationReason; |
| }; |
|
|
| export type SecretRefDefaultsCarrier = { |
| secrets?: { |
| defaults?: { |
| env?: string; |
| file?: string; |
| exec?: string; |
| }; |
| providers?: Record<string, { source?: string }>; |
| }; |
| }; |
|
|
| export function secretRefKey(ref: SecretRef): string { |
| return `${ref.source}:${ref.provider}:${ref.id}`; |
| } |
|
|
| export function resolveDefaultSecretProviderAlias( |
| config: SecretRefDefaultsCarrier, |
| source: SecretRefSource, |
| options?: { preferFirstProviderForSource?: boolean }, |
| ): string { |
| const configured = |
| source === "env" |
| ? config.secrets?.defaults?.env |
| : source === "file" |
| ? config.secrets?.defaults?.file |
| : config.secrets?.defaults?.exec; |
| if (configured?.trim()) { |
| return configured.trim(); |
| } |
|
|
| if (options?.preferFirstProviderForSource) { |
| const providers = config.secrets?.providers; |
| if (providers) { |
| for (const [providerName, provider] of Object.entries(providers)) { |
| if (provider?.source === source) { |
| return providerName; |
| } |
| } |
| } |
| } |
|
|
| return DEFAULT_SECRET_PROVIDER_ALIAS; |
| } |
|
|
| export function isValidFileSecretRefId(value: string): boolean { |
| if (value === SINGLE_VALUE_FILE_REF_ID) { |
| return true; |
| } |
| if (!value.startsWith("/")) { |
| return false; |
| } |
| return value |
| .slice(1) |
| .split("/") |
| .every((segment) => FILE_SECRET_REF_SEGMENT_PATTERN.test(segment)); |
| } |
|
|
| export function isValidSecretProviderAlias(value: string): boolean { |
| return SECRET_PROVIDER_ALIAS_PATTERN.test(value); |
| } |
|
|
| export function validateExecSecretRefId(value: string): ExecSecretRefIdValidationResult { |
| 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 }; |
| } |
|
|
| export function isValidExecSecretRefId(value: string): boolean { |
| return validateExecSecretRefId(value).ok; |
| } |
|
|
| export function formatExecSecretRefIdValidationMessage(): string { |
| 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").', |
| ].join(" "); |
| } |
|
|