Use OpenAI-compatible error format for secrets blocking:
authormaximiliancw <redacted>
Fri, 9 Jan 2026 15:52:46 +0000 (16:52 +0100)
committermaximiliancw <redacted>
Fri, 9 Jan 2026 15:52:46 +0000 (16:52 +0100)
- Use 400 status code instead of 422
- Use standard error format {message, type, param, code}
- Remove non-standard 'details' field (secret types already in headers)
- Update tests to match new format

src/routes/proxy.test.ts
src/routes/proxy.ts

index baf62869392043aa4e32fb35127cf102b1f923e9..660be971c1f9a4b6e8e8818eb566f94d3ace5d8c 100644 (file)
@@ -74,16 +74,16 @@ NhAAAAAwEAAQAAAIEAyK8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v
       headers: { "Content-Type": "application/json" },
     });
 
-    expect(res.status).toBe(422);
+    expect(res.status).toBe(400);
     const body = (await res.json()) as {
-      error: { message: string; type: string; details: { secrets_detected: string[] } };
+      error: { message: string; type: string; code: string };
     };
     expect(body.error.type).toBe("invalid_request_error");
     expect(body.error.message).toContain("Request blocked");
     expect(body.error.message).toContain("secret material");
-    expect(body.error.details.secrets_detected).toContain("OPENSSH_PRIVATE_KEY");
+    expect(body.error.code).toBe("secrets_detected");
 
-    // Check headers
+    // Check headers - secret types are exposed via headers
     expect(res.headers.get("X-PasteGuard-Secrets-Detected")).toBe("true");
     expect(res.headers.get("X-PasteGuard-Secrets-Types")).toContain("OPENSSH_PRIVATE_KEY");
   });
@@ -109,12 +109,14 @@ MIIEpAIBAAKCAQEAyK8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v
       headers: { "Content-Type": "application/json" },
     });
 
-    expect(res.status).toBe(422);
+    expect(res.status).toBe(400);
     const body = (await res.json()) as {
-      error: { details: { secrets_detected: string[] } };
+      error: { code: string };
     };
-    expect(body.error.details.secrets_detected).toContain("PEM_PRIVATE_KEY");
+    expect(body.error.code).toBe("secrets_detected");
+    // Secret types are in headers
     expect(res.headers.get("X-PasteGuard-Secrets-Detected")).toBe("true");
+    expect(res.headers.get("X-PasteGuard-Secrets-Types")).toContain("PEM_PRIVATE_KEY");
   });
 
   test("allows request without secrets", async () => {
@@ -132,8 +134,12 @@ MIIEpAIBAAKCAQEAyK8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v5Q8v
       headers: { "Content-Type": "application/json" },
     });
 
-    // Should not be blocked (may fail for other reasons like missing auth, but not 422)
-    expect(res.status).not.toBe(422);
+    // Should not be blocked for secrets (may fail for other reasons like missing auth)
+    // If it's 400, check it's not a secrets_detected error
+    if (res.status === 400) {
+      const body = (await res.json()) as { error?: { code?: string } };
+      expect(body.error?.code).not.toBe("secrets_detected");
+    }
     // Should not have secrets detection headers
     expect(res.headers.get("X-PasteGuard-Secrets-Detected")).toBeNull();
   });
index 1577707aa887db104fc1a8944964c4063ffd2062..1019583db5a4a17dfd75ceabbe6a13273931bc97 100644 (file)
@@ -67,7 +67,8 @@ proxyRoutes.post(
           error: {
             message: "Invalid request body",
             type: "invalid_request_error",
-            details: result.error.errors,
+            param: null,
+            code: null,
           },
         },
         400,
@@ -124,12 +125,11 @@ proxyRoutes.post(
               error: {
                 message: `Request blocked: detected secret material (${secretTypesStr}). Remove secrets and retry.`,
                 type: "invalid_request_error",
-                details: {
-                  secrets_detected: secretTypes,
-                },
+                param: null,
+                code: "secrets_detected",
               },
             },
-            422,
+            400,
           );
         }
 
git clone https://git.99rst.org/PROJECT