diff --git a/src/lib/BrewCleanup.svelte b/src/lib/BrewCleanup.svelte index 3ac08ac9f..824ce8c47 100644 --- a/src/lib/BrewCleanup.svelte +++ b/src/lib/BrewCleanup.svelte @@ -25,8 +25,8 @@ reset(); try { judgment = await api.judgeBrewCleanup(); - } catch (e) { - error = String(e); + } catch { + error = "Homebrew 정리 계획을 만들지 못했습니다."; } finally { planning = false; } @@ -72,8 +72,8 @@ confirmationPhrase.trim(), rationale.trim(), ); - } catch (e) { - error = String(e); + } catch { + error = "Homebrew 정리를 실행하지 못했습니다."; } finally { judgment = null; confirmationPhrase = ""; diff --git a/src/lib/brewCleanupErrorPrivacyContract.test.ts b/src/lib/brewCleanupErrorPrivacyContract.test.ts new file mode 100644 index 000000000..a83049f38 --- /dev/null +++ b/src/lib/brewCleanupErrorPrivacyContract.test.ts @@ -0,0 +1,30 @@ +import { readFileSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, expect, it } from "vitest"; + +const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../.."); + +function readSource(path: string): string { + return readFileSync(resolve(repositoryRoot, path), "utf8"); +} + +describe("BrewCleanup privacy-safe failure feedback", () => { + it("never renders arbitrary backend exception text", () => { + const source = readSource("src/lib/BrewCleanup.svelte"); + + expect(source).not.toContain("String(e)"); + expect(source).toContain("Homebrew 정리 계획을 만들지 못했습니다."); + expect(source).toContain("Homebrew 정리를 실행하지 못했습니다."); + expect(source).toContain('role="alert"'); + }); + + it("preserves the existing judgment and execution authority calls", () => { + const source = readSource("src/lib/BrewCleanup.svelte"); + + expect(source).toContain("api.judgeBrewCleanup()"); + expect(source).toContain("api.executeBrewCleanup("); + expect(source).toContain("submittedJudgment.plan_fingerprint"); + expect(source).toContain("submittedJudgment.judgment_id"); + }); +});