Files
PaperClipAI/packages/shared/src/validators/secret.ts
T
3abe9e2134 build(deps): bump zod from 3.25.76 to 4.4.3 (#11719)
Bumps [zod](https://github.com/colinhacks/zod) from 3.25.76 to 4.4.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/colinhacks/zod/releases">zod's
releases</a>.</em></p>
<blockquote>
<h2>v4.4.3</h2>
<h2>Commits:</h2>
<ul>
<li>4c2fa95ce3f3390fbc522324e406b4e9e89b88f9 docs: use Zernio primary
wordmark for gold sponsor logo</li>
<li>2aeec83eb135e3a83756e973ef44845fc5a455d2 docs: prune lapsed gold
sponsors and rebalance logo sizing</li>
<li>7391be88ac1ee5cd02057f5ccc012a1f5df4efd0 docs: prune lapsed
silver/bronze sponsors and add active ones</li>
<li>2c703322a21b4e2b12f33f49ea8430c451a68b4f docs: normalize bronze
sponsor logos to github avatar pattern</li>
<li>9195250cab0e7950efe39c3926d6c203b4b0a170 docs: remove Mintlify from
bronze sponsors (churned)</li>
<li>b8dffe9e62f17e6571e6249d05cc5102b54d94e4 docs: remove Numeric and
Speakeasy (2+ missed monthly cycles)</li>
<li>1cab69383fcdeae2a366d5e2a2fc4d8fc765d168 fix(v4): restore catch
handling for absent object keys (<a
href="https://redirect.github.com/colinhacks/zod/issues/5937">#5937</a>)
(<a
href="https://redirect.github.com/colinhacks/zod/issues/5939">#5939</a>)</li>
<li>c2be4f819064eed62c7c350a2d399b5faecd15f8 fix(v4): generalize
optin/fallback to transform; restore preprocess on absent keys (<a
href="https://redirect.github.com/colinhacks/zod/issues/5941">#5941</a>)</li>
<li>f3c9ec03ba7a28ae72d25cc295f38674bee0f559 4.4.3</li>
<li>1fb56a5c18c27102dbc92260a4007c7732a0ccca docs: document release
procedure in AGENTS.md</li>
</ul>
<h2>v4.4.2</h2>
<h2>Commits:</h2>
<ul>
<li>0c62df0ea19fd05abdf90473e9eef7eea530fab2 Clean up docs navigation
and stale labels (<a
href="https://redirect.github.com/colinhacks/zod/issues/5901">#5901</a>)</li>
<li>20cc794895cc8604fe0c87d83a5d1c3f89fad0ac chore: add security policy
and refresh tooling deps</li>
<li>6fbe07b0177efdd1bf1c0b05160e70d7a0702337 fix(docs): heading anchor
links now include the hash so it doesnt scoll all the way up, follows
navbar logic (<a
href="https://redirect.github.com/colinhacks/zod/issues/5791">#5791</a>)</li>
<li>4bbed1b1c73eca4ce9e59b1189ed236aa6c8b5bd Tighten discriminated union
option typing</li>
<li>bbac3e567e7fccfaaf7cdc97f1ce30c295e2c908 Update PR guidance for
agents</li>
<li>cf0dc942a32805c292fff59ade20a7ace980735a Merge remote-tracking
branch 'origin/main' into fix-discriminated-union-key-constraint</li>
<li>292c894a5fd2aa42e527900b83d8d7a3009a709c docs: add Zernio gold
sponsor</li>
<li>1fc9f311c28dcf80d0bb5a36b177086cbc3d8eca docs: document codec
inversion</li>
<li>1373c85da9aeff704a9762d27bc58699618aefb7 docs: remove AI disclosure
guidance</li>
<li>e20d02b473c08e3a4e557bc610b1b5fac079b649 chore: ignore triage
notes</li>
<li>e58ea4d91b1dfe8194b73508203213cbc7e9c936 docs: test Zod Mini tab
code heights</li>
<li>905761a5d127e8d5dd2ebb3bc88c75cb0b8149ff docs: document preprocess
input type narrowing</li>
<li>bf64bac850d4dee2b7dde7e64909d5d796d32043 chore: tighten test
guidance in AGENTS.md</li>
<li>8ec4e73f4c4693b6361ad591be40fb41eb8a9f95 chore: update play.ts
scratch</li>
<li>02c2baf7d0d615872fa4528a8020603b71211702 Make z.preprocess defer
optionality to inner schema (<a
href="https://redirect.github.com/colinhacks/zod/issues/5929">#5929</a>)</li>
<li>88015df8e25c44fb5385eb3ef28935119cd5edea fix(docs): drop deprecated
<code>baseUrl</code> from tsconfig</li>
<li>c59d4474e3b4cad1b323462186cf607178ce8267 4.4.2</li>
</ul>
<h2>v4.4.1</h2>
<h2>Commits:</h2>
<ul>
<li>481f7be4238c83ed58183f921b2646f340a91c6a ci: gate release publishing
on full test workflow</li>
<li>95ccab423aec720b2523c3a64cdc7e3204537cc7 test(v3): restore optional
undefined expectations</li>
<li>cede2c63739a5823d6aa5093d291e9a111da943d fix(v4): reject tuple holes
before required defaults (<a
href="https://redirect.github.com/colinhacks/zod/issues/5900">#5900</a>)</li>
<li>edd0bf0f5ada4a8dc581c259407d7bbad0a71ea7 release: 4.4.1</li>
<li>180d83d1dbe6a59260710cc8637a3dea2281ee56 docs: remove Jazz featured
sponsor</li>
</ul>
<h2>v4.4.0</h2>
<h2>4.4.0</h2>
<p>This is a minor release with a wide set of correctness and soundness
fixes. Some fixes intentionally make Zod stricter, so code that depended
on previously accepted invalid or ambiguous inputs may need small
updates.</p>
<h2>Potentially breaking bug fixes</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/colinhacks/zod/commit/1fb56a5c18c27102dbc92260a4007c7732a0ccca"><code>1fb56a5</code></a>
docs: document release procedure in AGENTS.md</li>
<li><a
href="https://github.com/colinhacks/zod/commit/f3c9ec03ba7a28ae72d25cc295f38674bee0f559"><code>f3c9ec0</code></a>
4.4.3</li>
<li><a
href="https://github.com/colinhacks/zod/commit/c2be4f819064eed62c7c350a2d399b5faecd15f8"><code>c2be4f8</code></a>
fix(v4): generalize optin/fallback to transform; restore preprocess on
absent...</li>
<li><a
href="https://github.com/colinhacks/zod/commit/1cab69383fcdeae2a366d5e2a2fc4d8fc765d168"><code>1cab693</code></a>
fix(v4): restore catch handling for absent object keys (<a
href="https://redirect.github.com/colinhacks/zod/issues/5937">#5937</a>)
(<a
href="https://redirect.github.com/colinhacks/zod/issues/5939">#5939</a>)</li>
<li><a
href="https://github.com/colinhacks/zod/commit/b8dffe9e62f17e6571e6249d05cc5102b54d94e4"><code>b8dffe9</code></a>
docs: remove Numeric and Speakeasy (2+ missed monthly cycles)</li>
<li><a
href="https://github.com/colinhacks/zod/commit/9195250cab0e7950efe39c3926d6c203b4b0a170"><code>9195250</code></a>
docs: remove Mintlify from bronze sponsors (churned)</li>
<li><a
href="https://github.com/colinhacks/zod/commit/2c703322a21b4e2b12f33f49ea8430c451a68b4f"><code>2c70332</code></a>
docs: normalize bronze sponsor logos to github avatar pattern</li>
<li><a
href="https://github.com/colinhacks/zod/commit/7391be88ac1ee5cd02057f5ccc012a1f5df4efd0"><code>7391be8</code></a>
docs: prune lapsed silver/bronze sponsors and add active ones</li>
<li><a
href="https://github.com/colinhacks/zod/commit/2aeec83eb135e3a83756e973ef44845fc5a455d2"><code>2aeec83</code></a>
docs: prune lapsed gold sponsors and rebalance logo sizing</li>
<li><a
href="https://github.com/colinhacks/zod/commit/4c2fa95ce3f3390fbc522324e406b4e9e89b88f9"><code>4c2fa95</code></a>
docs: use Zernio primary wordmark for gold sponsor logo</li>
<li>Additional commits viewable in <a
href="https://github.com/colinhacks/zod/compare/v3.25.76...v4.4.3">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new
releaser for zod since your current version.</p>
</details>
<br />

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Priya Raman <priya@paperclip.ing>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-08-21 00:04:14 -07:00

427 lines
16 KiB
TypeScript

import { z } from "zod";
import {
SECRET_BINDING_TARGET_TYPES,
SECRET_MANAGED_MODES,
SECRET_PROJECTION_CLASSES,
SECRET_PROVIDER_CONFIG_STATUSES,
SECRET_PROVIDERS,
SECRET_STATUSES,
} from "../constants.js";
const secretKeySchema = z.string().trim().min(1).max(120).regex(/^[a-zA-Z0-9_.-]+$/);
const secretVersionSelectorSchema = z.union([z.literal("latest"), z.number().int().positive()]);
const creatableSecretStatusSchema = z.enum(["active", "disabled", "archived"]);
export const envBindingPlainSchema = z.object({
type: z.literal("plain"),
value: z.string(),
});
export const envBindingSecretRefSchema = z.object({
type: z.literal("secret_ref"),
secretId: z.string().guid(),
version: secretVersionSelectorSchema.optional(),
projectionClass: z.enum(SECRET_PROJECTION_CLASSES).optional(),
projectionAllowlistKey: z.string().trim().min(1).max(160).optional().nullable(),
});
export const envBindingUserSecretRefSchema = z.object({
type: z.literal("user_secret_ref"),
key: secretKeySchema,
version: secretVersionSelectorSchema.optional(),
required: z.boolean().optional().default(true),
allowMissingOverride: z.boolean().optional().default(false),
});
// Backward-compatible union that accepts legacy inline values.
export const envBindingSchema = z.union([
z.string(),
envBindingPlainSchema,
envBindingSecretRefSchema,
envBindingUserSecretRefSchema,
]);
export const envConfigSchema = z.record(z.string(), envBindingSchema);
export const createSecretSchema = z.object({
name: z.string().min(1),
key: secretKeySchema.optional(),
provider: z.enum(SECRET_PROVIDERS).optional(),
providerConfigId: z.string().guid().optional().nullable(),
managedMode: z.enum(SECRET_MANAGED_MODES).optional(),
value: z.string().min(1).optional().nullable(),
description: z.string().optional().nullable(),
externalRef: z.string().optional().nullable(),
providerMetadata: z.record(z.string(), z.unknown()).optional().nullable(),
providerVersionRef: z.string().optional().nullable(),
}).superRefine((value, ctx) => {
if ((value.managedMode ?? "paperclip_managed") === "external_reference") {
if (!value.externalRef?.trim()) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["externalRef"],
message: "External reference secrets require externalRef",
});
}
return;
}
if (value.externalRef?.trim()) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["externalRef"],
message: "Managed secrets cannot set externalRef",
});
}
if (!value.value?.trim()) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["value"],
message: "Managed secrets require value",
});
}
});
export type CreateSecret = z.infer<typeof createSecretSchema>;
function requireSecretRotationInput(
value: {
value?: string | null;
externalRef?: string | null;
providerVersionRef?: string | null;
providerConfigId?: string | null;
},
ctx: z.RefinementCtx,
) {
if (
!value.value?.trim() &&
!value.externalRef?.trim() &&
value.providerVersionRef == null &&
value.providerConfigId == null
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["value"],
message: "Secret rotation requires value, externalRef, providerVersionRef, or providerConfigId",
});
}
}
export const rotateSecretSchema = z.object({
value: z.string().min(1).optional().nullable(),
externalRef: z.string().optional().nullable(),
providerVersionRef: z.string().optional().nullable(),
providerConfigId: z.string().guid().optional().nullable(),
}).superRefine(requireSecretRotationInput);
export type RotateSecret = z.infer<typeof rotateSecretSchema>;
export const updateSecretSchema = z.object({
name: z.string().min(1).optional(),
key: secretKeySchema.optional(),
status: z.enum(SECRET_STATUSES).optional(),
providerConfigId: z.string().guid().optional().nullable(),
description: z.string().optional().nullable(),
externalRef: z.string().optional().nullable(),
providerMetadata: z.record(z.string(), z.unknown()).optional().nullable(),
});
export type UpdateSecret = z.infer<typeof updateSecretSchema>;
export const secretBindingTargetSchema = z.object({
targetType: z.enum(SECRET_BINDING_TARGET_TYPES),
targetId: z.string().min(1),
configPath: z.string().min(1),
});
export const createSecretBindingSchema = secretBindingTargetSchema.extend({
secretId: z.string().guid(),
versionSelector: secretVersionSelectorSchema.default("latest"),
required: z.boolean().default(true),
label: z.string().optional().nullable(),
projectionClass: z.enum(SECRET_PROJECTION_CLASSES).optional(),
projectionAllowlistKey: z.string().trim().min(1).max(160).optional().nullable(),
});
export type CreateSecretBinding = z.infer<typeof createSecretBindingSchema>;
export const createUserSecretDefinitionSchema = z.object({
key: secretKeySchema,
name: z.string().trim().min(1).max(160),
description: z.string().trim().max(500).optional().nullable(),
status: creatableSecretStatusSchema.optional(),
provider: z.enum(SECRET_PROVIDERS).optional(),
providerConfigId: z.string().guid().optional().nullable(),
managedMode: z.enum(SECRET_MANAGED_MODES).optional(),
providerMetadata: z.record(z.string(), z.unknown()).optional().nullable(),
usageGuidance: z.string().trim().max(1000).optional().nullable(),
});
export type CreateUserSecretDefinition = z.infer<typeof createUserSecretDefinitionSchema>;
export const updateUserSecretDefinitionSchema = z.object({
name: z.string().trim().min(1).max(160).optional(),
description: z.string().trim().max(500).optional().nullable(),
status: z.enum(SECRET_STATUSES).optional(),
providerConfigId: z.string().guid().optional().nullable(),
providerMetadata: z.record(z.string(), z.unknown()).optional().nullable(),
usageGuidance: z.string().trim().max(1000).optional().nullable(),
});
export type UpdateUserSecretDefinition = z.infer<typeof updateUserSecretDefinitionSchema>;
export const createUserSecretValueSchema = z.object({
definitionKey: secretKeySchema.optional(),
definitionId: z.string().guid().optional(),
value: z.string().min(1).optional().nullable(),
externalRef: z.string().optional().nullable(),
providerVersionRef: z.string().optional().nullable(),
providerConfigId: z.string().guid().optional().nullable(),
}).superRefine((value, ctx) => {
if (!value.definitionKey && !value.definitionId) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["definitionId"],
message: "User secret value requires definitionId or definitionKey",
});
}
if (!value.value?.trim() && !value.externalRef?.trim()) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["value"],
message: "User secret value requires value or externalRef",
});
}
});
export type CreateUserSecretValue = z.infer<typeof createUserSecretValueSchema>;
export const updateUserSecretValueSchema = z.object({
status: z.enum(SECRET_STATUSES).optional(),
value: z.string().min(1).optional().nullable(),
externalRef: z.string().min(1).optional().nullable(),
providerVersionRef: z.string().min(1).optional().nullable(),
providerConfigId: z.string().guid().optional().nullable(),
});
export type UpdateUserSecretValue = z.infer<typeof updateUserSecretValueSchema>;
export const rotateUserSecretValueSchema = z.object({
value: z.string().min(1).optional().nullable(),
externalRef: z.string().min(1).optional().nullable(),
providerVersionRef: z.string().min(1).optional().nullable(),
providerConfigId: z.string().guid().optional().nullable(),
}).superRefine(requireSecretRotationInput);
export type RotateUserSecretValue = z.infer<typeof rotateUserSecretValueSchema>;
export const createUserSecretDeclarationSchema = secretBindingTargetSchema.extend({
definitionKey: secretKeySchema,
envKey: z.string().trim().min(1),
versionSelector: secretVersionSelectorSchema.default("latest"),
required: z.boolean().default(true),
allowMissingOverride: z.boolean().default(false),
label: z.string().optional().nullable(),
});
export type CreateUserSecretDeclaration = z.infer<typeof createUserSecretDeclarationSchema>;
const safeShortText = z.string().trim().min(1).max(160);
const optionalSafeShortText = safeShortText.optional().nullable();
const deniedProviderConfigKeyPattern =
/^(access[-_]?key([-_]?id)?|secret[-_]?access[-_]?key|secret[-_]?key|token|password|passwd|credential|credentials|private[-_]?key|pem|jwt|session[-_]?token|service[-_]?account([-_]?json)?|client[-_]?secret|secret[-_]?id|unseal[-_]?key|recovery[-_]?key|key[-_]?file([-_]?path)?|token[-_]?file([-_]?path)?)$/i;
function rejectSensitiveProviderConfigKeys(value: unknown, ctx: z.RefinementCtx) {
if (!value || typeof value !== "object" || Array.isArray(value)) return;
for (const key of Object.keys(value)) {
if (!deniedProviderConfigKeyPattern.test(key)) continue;
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["config", key],
message: `Provider vault config cannot persist sensitive field: ${key}`,
});
}
}
export const localEncryptedProviderConfigSchema = z.object({
backupReminderAcknowledged: z.boolean().optional(),
}).strict();
export const awsSecretsManagerProviderConfigSchema = z.object({
region: z.string().trim().regex(/^[a-z]{2}(?:-gov)?-[a-z]+-\d+$/, "Invalid AWS region"),
namespace: optionalSafeShortText,
secretNamePrefix: optionalSafeShortText,
kmsKeyId: z.string().trim().min(1).max(512).optional().nullable(),
ownerTag: optionalSafeShortText,
environmentTag: optionalSafeShortText,
}).strict();
export const gcpSecretManagerProviderConfigSchema = z.object({
projectId: z.string().trim().min(1).max(128).regex(/^[a-z][a-z0-9-]{4,127}$/).optional().nullable(),
location: optionalSafeShortText,
namespace: optionalSafeShortText,
secretNamePrefix: optionalSafeShortText,
}).strict();
const vaultAddressSchema = z.preprocess(
(value) => typeof value === "string" ? value.trim() : value,
z.string().url().superRefine((value, ctx) => {
let url: URL;
try {
url = new URL(value);
} catch {
return;
}
const hasPath = url.pathname !== "" && url.pathname !== "/";
if (
(url.protocol !== "http:" && url.protocol !== "https:") ||
url.username ||
url.password ||
url.search ||
url.hash ||
hasPath
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Vault address must be an origin-only HTTP(S) URL without credentials, path, query, or fragment",
});
}
}).transform((value) => new URL(value).origin),
);
function rejectUnsafeVaultAddress(value: unknown, ctx: z.RefinementCtx) {
if (value === undefined || value === null) return;
const parsed = vaultAddressSchema.safeParse(value);
if (parsed.success) return;
for (const issue of parsed.error.issues) {
ctx.addIssue({
...issue,
path: ["config", "address", ...issue.path],
});
}
}
export const vaultProviderConfigSchema = z.object({
address: vaultAddressSchema.optional().nullable(),
namespace: optionalSafeShortText,
mountPath: optionalSafeShortText,
secretPathPrefix: optionalSafeShortText,
}).strict();
export const secretProviderConfigPayloadSchema = z.discriminatedUnion("provider", [
z.object({ provider: z.literal("local_encrypted"), config: localEncryptedProviderConfigSchema }),
z.object({ provider: z.literal("aws_secrets_manager"), config: awsSecretsManagerProviderConfigSchema }),
z.object({ provider: z.literal("gcp_secret_manager"), config: gcpSecretManagerProviderConfigSchema }),
z.object({ provider: z.literal("vault"), config: vaultProviderConfigSchema }),
]);
export const createSecretProviderConfigSchema = z.object({
provider: z.enum(SECRET_PROVIDERS),
displayName: z.string().trim().min(1).max(120),
status: z.enum(SECRET_PROVIDER_CONFIG_STATUSES).optional(),
isDefault: z.boolean().optional(),
config: z.record(z.string(), z.unknown()).default({}),
}).superRefine((value, ctx) => {
rejectSensitiveProviderConfigKeys(value.config, ctx);
const parsed = secretProviderConfigPayloadSchema.safeParse({
provider: value.provider,
config: value.config,
});
if (!parsed.success) {
for (const issue of parsed.error.issues) {
ctx.addIssue({
...issue,
path: issue.path[0] === "config" ? issue.path : ["config", ...issue.path],
});
}
}
const status = value.status ?? (["gcp_secret_manager", "vault"].includes(value.provider) ? "coming_soon" : "ready");
if ((value.provider === "gcp_secret_manager" || value.provider === "vault") && status !== "coming_soon" && status !== "disabled") {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["status"],
message: `${value.provider} provider vaults are locked while coming soon`,
});
}
if ((status === "coming_soon" || status === "disabled") && value.isDefault) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["isDefault"],
message: "Only ready or warning provider vaults can be default",
});
}
});
export type CreateSecretProviderConfig = z.infer<typeof createSecretProviderConfigSchema>;
export const updateSecretProviderConfigSchema = z.object({
displayName: z.string().trim().min(1).max(120).optional(),
status: z.enum(SECRET_PROVIDER_CONFIG_STATUSES).optional(),
isDefault: z.boolean().optional(),
config: z.record(z.string(), z.unknown()).optional(),
}).superRefine((value, ctx) => {
if (value.config !== undefined) {
rejectSensitiveProviderConfigKeys(value.config, ctx);
rejectUnsafeVaultAddress(value.config.address, ctx);
}
if ((value.status === "coming_soon" || value.status === "disabled") && value.isDefault) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["isDefault"],
message: "Only ready or warning provider vaults can be default",
});
}
});
export type UpdateSecretProviderConfig = z.infer<typeof updateSecretProviderConfigSchema>;
export const remoteSecretImportPreviewSchema = z.object({
providerConfigId: z.string().guid(),
query: z.string().trim().max(200).optional().nullable(),
nextToken: z.string().trim().min(1).max(4096).optional().nullable(),
pageSize: z.number().int().min(1).max(100).optional(),
});
export type RemoteSecretImportPreview = z.infer<typeof remoteSecretImportPreviewSchema>;
export const secretProviderConfigDiscoveryPreviewSchema = z.object({
provider: z.enum(SECRET_PROVIDERS),
config: z.record(z.string(), z.unknown()).default({}),
query: z.string().trim().max(200).optional().nullable(),
nextToken: z.string().trim().min(1).max(4096).optional().nullable(),
pageSize: z.number().int().min(1).max(100).optional(),
}).superRefine((value, ctx) => {
rejectSensitiveProviderConfigKeys(value.config, ctx);
const parsed = secretProviderConfigPayloadSchema.safeParse({
provider: value.provider,
config: value.config,
});
if (!parsed.success) {
for (const issue of parsed.error.issues) {
ctx.addIssue({
...issue,
path: issue.path[0] === "config" ? issue.path : ["config", ...issue.path],
});
}
}
});
export type SecretProviderConfigDiscoveryPreview = z.infer<typeof secretProviderConfigDiscoveryPreviewSchema>;
export const remoteSecretImportSelectionSchema = z.object({
externalRef: z.string().trim().min(1).max(2048),
name: z.string().trim().min(1).max(160).optional().nullable(),
key: z.string().trim().min(1).max(120).regex(/^[a-zA-Z0-9_.-]+$/).optional().nullable(),
description: z.string().trim().max(500).optional().nullable(),
providerVersionRef: z.string().trim().min(1).max(512).optional().nullable(),
providerMetadata: z.record(z.string(), z.unknown()).optional().nullable(),
});
export const remoteSecretImportSchema = z.object({
providerConfigId: z.string().guid(),
secrets: z.array(remoteSecretImportSelectionSchema).min(1).max(100),
});
export type RemoteSecretImportSelection = z.infer<typeof remoteSecretImportSelectionSchema>;
export type RemoteSecretImport = z.infer<typeof remoteSecretImportSchema>;