fix(secrets): allow storing values shorter than 8 characters
Keep the 8-character floor only for log redaction so short MinIO keys can be saved. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { inspect } from "node:util";
|
import { inspect } from "node:util";
|
||||||
|
|
||||||
export const REDACTED = "[secret]";
|
export const REDACTED = "[secret]";
|
||||||
|
/** Short values are stored, but skipped in log redaction to avoid false positives. */
|
||||||
export const MIN_SECRET_LENGTH = 8;
|
export const MIN_SECRET_LENGTH = 8;
|
||||||
|
|
||||||
/** @type {Set<string>} */
|
/** @type {Set<string>} */
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
|
|||||||
import { db } from "./db.js";
|
import { db } from "./db.js";
|
||||||
import { assertOwner } from "./fs-store.js";
|
import { assertOwner } from "./fs-store.js";
|
||||||
import { decryptSecret, encryptSecret } from "./secrets.js";
|
import { decryptSecret, encryptSecret } from "./secrets.js";
|
||||||
import { MIN_SECRET_LENGTH, registerPlaintext } from "./secret-value.js";
|
import { registerPlaintext } from "./secret-value.js";
|
||||||
|
|
||||||
const MAX_NAME_LENGTH = 128;
|
const MAX_NAME_LENGTH = 128;
|
||||||
const SECRET_NAME_RE = /^[A-Za-z0-9._-]+$/;
|
const SECRET_NAME_RE = /^[A-Za-z0-9._-]+$/;
|
||||||
@@ -68,8 +68,8 @@ export async function getSecretById(id) {
|
|||||||
* @param {{ owner: string, name: string, value: string }} opts
|
* @param {{ owner: string, name: string, value: string }} opts
|
||||||
*/
|
*/
|
||||||
export async function upsertSecret({ owner, name, value }) {
|
export async function upsertSecret({ owner, name, value }) {
|
||||||
if (typeof value !== "string" || value.length < MIN_SECRET_LENGTH) {
|
if (typeof value !== "string" || value.length === 0) {
|
||||||
const err = new Error(`value must be at least ${MIN_SECRET_LENGTH} characters`);
|
const err = new Error("value is required");
|
||||||
err.statusCode = 400;
|
err.statusCode = 400;
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
listSecrets,
|
listSecrets,
|
||||||
upsertSecret,
|
upsertSecret,
|
||||||
} from "../../secrets-store.js";
|
} from "../../secrets-store.js";
|
||||||
import { MIN_SECRET_LENGTH } from "../../secret-value.js";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("fastify").FastifyInstance} fastify
|
* @param {import("fastify").FastifyInstance} fastify
|
||||||
@@ -37,10 +36,8 @@ export default async function secretsPlugin(fastify) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const value = String(body.value ?? "");
|
const value = String(body.value ?? "");
|
||||||
if (value.length < MIN_SECRET_LENGTH) {
|
if (value.length === 0) {
|
||||||
return reply
|
return reply.code(400).send({ error: "value is required" });
|
||||||
.code(400)
|
|
||||||
.send({ error: `value must be at least ${MIN_SECRET_LENGTH} characters` });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -180,11 +180,11 @@ export function SecretsPage() {
|
|||||||
value={form.value}
|
value={form.value}
|
||||||
onChange={(e) => setForm({ ...form, value: e.target.value })}
|
onChange={(e) => setForm({ ...form, value: e.target.value })}
|
||||||
required
|
required
|
||||||
minLength={8}
|
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
<p className="text-xs opacity-60 mt-1">
|
<p className="text-xs opacity-60 mt-1">
|
||||||
Values are encrypted at rest and never shown again after save.
|
Values are encrypted at rest and never shown again after save.
|
||||||
|
Values shorter than 8 characters are not redacted from logs.
|
||||||
</p>
|
</p>
|
||||||
{upsert.isError ? (
|
{upsert.isError ? (
|
||||||
<p className="text-error text-sm">{errorMessage(upsert.error)}</p>
|
<p className="text-error text-sm">{errorMessage(upsert.error)}</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user