mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 02:26:12 +02:00
fix(secrets): close user definition edge cases
Reject deleted status during user-secret definition creation and remove the stale key field from the UI update contract. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
8da5a0b44a
commit
7c7f9b1767
4 files changed
+19
-5
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
createUserSecretDefinitionSchema,
|
||||
createUserSecretDeclarationSchema,
|
||||
createUserSecretValueSchema,
|
||||
createSecretProviderConfigSchema,
|
||||
@@ -63,6 +64,16 @@ describe("secret validators", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("does not allow user secret definitions to be created as deleted", () => {
|
||||
expect(() =>
|
||||
createUserSecretDefinitionSchema.parse({
|
||||
key: "github_api_token",
|
||||
name: "GitHub API token",
|
||||
status: "deleted",
|
||||
}),
|
||||
).toThrow();
|
||||
});
|
||||
|
||||
it("requires secret rotation payloads to include rotation input", () => {
|
||||
expect(() => rotateSecretSchema.parse({})).toThrow(/requires value, externalRef/);
|
||||
expect(() => rotateUserSecretValueSchema.parse({})).toThrow(/requires value, externalRef/);
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
|
||||
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"),
|
||||
@@ -142,7 +143,7 @@ export const createUserSecretDefinitionSchema = z.object({
|
||||
key: secretKeySchema,
|
||||
name: z.string().trim().min(1).max(160),
|
||||
description: z.string().trim().max(500).optional().nullable(),
|
||||
status: z.enum(SECRET_STATUSES).optional(),
|
||||
status: creatableSecretStatusSchema.optional(),
|
||||
provider: z.enum(SECRET_PROVIDERS).optional(),
|
||||
providerConfigId: z.string().uuid().optional().nullable(),
|
||||
managedMode: z.enum(SECRET_MANAGED_MODES).optional(),
|
||||
|
||||
@@ -32,7 +32,7 @@ export interface CreateUserSecretDefinitionInput {
|
||||
key: string;
|
||||
name: string;
|
||||
description?: string | null;
|
||||
status?: SecretStatus;
|
||||
status?: Exclude<SecretStatus, "deleted">;
|
||||
provider?: SecretProvider;
|
||||
managedMode?: SecretManagedMode;
|
||||
providerConfigId?: string | null;
|
||||
@@ -41,7 +41,6 @@ export interface CreateUserSecretDefinitionInput {
|
||||
}
|
||||
|
||||
export interface UpdateUserSecretDefinitionInput {
|
||||
key?: string;
|
||||
name?: string;
|
||||
description?: string | null;
|
||||
status?: SecretStatus;
|
||||
|
||||
@@ -107,14 +107,17 @@ export function UserSecretDefinitionsTab({ companyId }: { companyId: string }) {
|
||||
name: form.name.trim(),
|
||||
description: form.description.trim() || null,
|
||||
usageGuidance: form.usageGuidance.trim() || null,
|
||||
status: form.status,
|
||||
};
|
||||
if (editing) {
|
||||
return secretsApi.updateUserSecretDefinition(companyId, editing.id, sharedPayload);
|
||||
return secretsApi.updateUserSecretDefinition(companyId, editing.id, {
|
||||
...sharedPayload,
|
||||
status: form.status,
|
||||
});
|
||||
}
|
||||
return secretsApi.createUserSecretDefinition(companyId, {
|
||||
...sharedPayload,
|
||||
key: form.key.trim(),
|
||||
status: form.status === "deleted" ? "active" : form.status,
|
||||
});
|
||||
},
|
||||
onSuccess: (definition) => {
|
||||
|
||||
Reference in new issue
Block a user