diff --git a/src/mcpd/src/services/secret-backends/openbao.ts b/src/mcpd/src/services/secret-backends/openbao.ts index 5d086fc..93e902c 100644 --- a/src/mcpd/src/services/secret-backends/openbao.ts +++ b/src/mcpd/src/services/secret-backends/openbao.ts @@ -29,6 +29,17 @@ import { readFile } from 'node:fs/promises'; import type { SecretBackendDriver, SecretData, ExternalRef, SecretRefResolver } from './types.js'; +/** Best-effort read of a response body for error messages. Empty on parse failure. */ +async function bodyText(res: Response): Promise { + try { + const text = await res.text(); + // Trim huge HTML error pages to the first 400 chars + return text.length > 400 ? `${text.slice(0, 400)}…` : text; + } catch { + return ''; + } +} + export interface OpenBaoConfigBase { url: string; mount?: string; @@ -128,7 +139,7 @@ export class OpenBaoDriver implements SecretBackendDriver { if (res.status === 404) { throw new Error(`OpenBao: secret '${input.name}' not found at ${path}`); } - if (!res.ok) throw new Error(`OpenBao read ${path}: HTTP ${res.status}`); + if (!res.ok) throw new Error(`OpenBao read ${path}: HTTP ${res.status} ${await bodyText(res)}`); const body = await res.json() as { data?: { data?: SecretData } }; return body.data?.data ?? {}; } @@ -136,7 +147,7 @@ export class OpenBaoDriver implements SecretBackendDriver { async write(input: { name: string; data: SecretData }): Promise<{ externalRef: ExternalRef; storedData: SecretData }> { const path = this.pathFor(input.name); const res = await this.request('POST', `/v1/${this.mount}/data/${path}`, { data: input.data }); - if (!res.ok) throw new Error(`OpenBao write ${path}: HTTP ${res.status}`); + if (!res.ok) throw new Error(`OpenBao write ${path}: HTTP ${res.status} ${await bodyText(res)}`); return { externalRef: `${this.mount}/${path}`, storedData: {} }; } @@ -144,7 +155,7 @@ export class OpenBaoDriver implements SecretBackendDriver { const path = this.pathFor(input.name); const res = await this.request('DELETE', `/v1/${this.mount}/metadata/${path}`); if (!res.ok && res.status !== 404) { - throw new Error(`OpenBao delete ${path}: HTTP ${res.status}`); + throw new Error(`OpenBao delete ${path}: HTTP ${res.status} ${await bodyText(res)}`); } } @@ -152,7 +163,7 @@ export class OpenBaoDriver implements SecretBackendDriver { const listPath = this.pathPrefix === '' ? '' : `${this.pathPrefix}/`; const res = await this.request('LIST', `/v1/${this.mount}/metadata/${listPath}`); if (res.status === 404) return []; - if (!res.ok) throw new Error(`OpenBao list: HTTP ${res.status}`); + if (!res.ok) throw new Error(`OpenBao list: HTTP ${res.status} ${await bodyText(res)}`); const body = await res.json() as { data?: { keys?: string[] } }; const keys = body.data?.keys ?? []; return keys