fix(agent-bridge-ui): remove double-write of risk-accepted localStorage (M5)

AgentCard.handleRiskAccept was calling markRiskAccepted() before opening the
RiskNoticeModal, which itself writes the same key via dontShowAgainKey on accept.
Remove the redundant markRiskAccepted call and delete the now-unused helper so
RiskNoticeModal (D16) is the sole canonical persistence owner. Add a spy-based
test asserting the key is written exactly once per accept.
This commit is contained in:
diegosouzapw
2026-05-28 16:24:09 -03:00
parent fa655ab4df
commit f0cdc3622e
2 changed files with 55 additions and 8 deletions

View File

@@ -21,13 +21,6 @@ function hasAcceptedRisk(agentId: string): boolean {
}
}
function markRiskAccepted(agentId: string): void {
try {
localStorage.setItem(RISK_STORAGE_KEY_PREFIX + agentId, "true");
} catch {
// ignore storage errors
}
}
interface AgentCardProps {
target: MitmTarget;
@@ -112,7 +105,6 @@ export function AgentCard({
};
const handleRiskAccept = async () => {
markRiskAccepted(target.id);
setRiskModalOpen(false);
await reallyToggleDns(true);
};

View File

@@ -204,6 +204,61 @@ describe("AgentCard RiskNoticeModal", { timeout: 30000 }, () => {
expect(stored).toBe("true");
}, 30000);
it("accepting risk writes localStorage exactly once (RiskNoticeModal is sole writer)", async () => {
const { AgentCard } = await import(
"../../../src/app/(dashboard)/dashboard/tools/agent-bridge/components/AgentCard"
);
const setItemSpy = vi.spyOn(Storage.prototype, "setItem");
const onDnsToggle = vi.fn().mockResolvedValue(undefined);
const container = makeContainer();
await act(async () => {
const root = createRoot(container);
root.render(
React.createElement(AgentCard, {
target: mockTarget,
agentState: baseAgentState,
serverRunning: true,
mappings: [],
onDnsToggle,
onMappingsSave: vi.fn(),
})
);
});
// Expand card
const header = container.querySelector("button[aria-expanded]");
await act(async () => {
header?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
});
// Click DNS toggle to open modal
const dnsBtn = Array.from(container.querySelectorAll("button")).find((b) =>
b.textContent?.includes("startDns")
);
await act(async () => {
dnsBtn?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
});
// Accept modal
const acceptBtn = Array.from(document.querySelectorAll("button")).find((b) =>
b.textContent?.includes("understand")
);
await act(async () => {
acceptBtn?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
});
const riskKey = "omniroute-agentbridge-risk-dismissed-copilot";
const riskWrites = setItemSpy.mock.calls.filter(([key]) => key === riskKey);
// Must be exactly ONE write — RiskNoticeModal is the sole persistence owner (D16)
expect(riskWrites).toHaveLength(1);
expect(riskWrites[0][1]).toBe("true");
setItemSpy.mockRestore();
}, 30000);
it("second DNS activation does NOT open modal when localStorage flag is set", async () => {
// Pre-set the localStorage flag (simulates accepted risk on previous session)
try {