mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 09:41:04 +01:00
fix(secrets): preserve external rotation selectors
Reject empty rotation requests while still allowing external-reference rotations that intentionally supply only provider version or provider config selectors. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
7a5738b6dc
commit
b04069d14d
3 files changed
+23
-10
No files matched your search
@@ -63,12 +63,15 @@ describe("secret validators", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("requires secret rotation payloads to include new material", () => {
|
||||
expect(() => rotateSecretSchema.parse({})).toThrow(/requires value or externalRef/);
|
||||
expect(() => rotateUserSecretValueSchema.parse({})).toThrow(/requires value or externalRef/);
|
||||
it("requires secret rotation payloads to include rotation input", () => {
|
||||
expect(() => rotateSecretSchema.parse({})).toThrow(/requires value, externalRef/);
|
||||
expect(() => rotateUserSecretValueSchema.parse({})).toThrow(/requires value, externalRef/);
|
||||
expect(rotateUserSecretValueSchema.parse({ value: "new-secret" })).toEqual({
|
||||
value: "new-secret",
|
||||
});
|
||||
expect(rotateUserSecretValueSchema.parse({ providerVersionRef: "version-2" })).toEqual({
|
||||
providerVersionRef: "version-2",
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects externalRef on managed secrets", () => {
|
||||
|
||||
@@ -79,15 +79,25 @@ export const createSecretSchema = z.object({
|
||||
|
||||
export type CreateSecret = z.infer<typeof createSecretSchema>;
|
||||
|
||||
function requireSecretRotationMaterial(
|
||||
value: { value?: string | null; externalRef?: string | null },
|
||||
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()) {
|
||||
if (
|
||||
!value.value?.trim() &&
|
||||
!value.externalRef?.trim() &&
|
||||
value.providerVersionRef === undefined &&
|
||||
value.providerConfigId === undefined
|
||||
) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
path: ["value"],
|
||||
message: "Secret rotation requires value or externalRef",
|
||||
message: "Secret rotation requires value, externalRef, providerVersionRef, or providerConfigId",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -97,7 +107,7 @@ export const rotateSecretSchema = z.object({
|
||||
externalRef: z.string().optional().nullable(),
|
||||
providerVersionRef: z.string().optional().nullable(),
|
||||
providerConfigId: z.string().uuid().optional().nullable(),
|
||||
}).superRefine(requireSecretRotationMaterial);
|
||||
}).superRefine(requireSecretRotationInput);
|
||||
|
||||
export type RotateSecret = z.infer<typeof rotateSecretSchema>;
|
||||
|
||||
@@ -194,7 +204,7 @@ export const rotateUserSecretValueSchema = z.object({
|
||||
externalRef: z.string().optional().nullable(),
|
||||
providerVersionRef: z.string().optional().nullable(),
|
||||
providerConfigId: z.string().uuid().optional().nullable(),
|
||||
}).superRefine(requireSecretRotationMaterial);
|
||||
}).superRefine(requireSecretRotationInput);
|
||||
|
||||
export type RotateUserSecretValue = z.infer<typeof rotateUserSecretValueSchema>;
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ describe("secret routes", () => {
|
||||
.send({});
|
||||
|
||||
expect(res.status).toBe(400);
|
||||
expect(JSON.stringify(res.body)).toMatch(/requires value or externalRef/);
|
||||
expect(JSON.stringify(res.body)).toMatch(/requires value, externalRef/);
|
||||
expect(mockSecretService.rotateCurrentUserSecretValue).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user