fix: floor malformed allowedSites, fraudContracts and selectedToken entries (closes #362)
All checks were successful
check / check (push) Successful in 42s
e2e / e2e-chrome (push) Successful in 1m45s
e2e / e2e-firefox (push) Successful in 31s

A stored allowedSites whose value was not a list rendered a working popup and then made every subsequent save fail silently, so the user operated a wallet that persisted nothing -- worse than a blank popup, which is at least visibly broken. fraudContracts and selectedToken had the same shape: a container floored by truthiness or not at all, while its entries were dereferenced. Entries are now floored as well as containers, following the idiom #311 established, and a failed save raises a persistent banner instead of vanishing into a swallowed rejection.

The per-field justifications that used to live in a hand-written header are replaced by a contract test that drives each field's hostile and falsy values through a real popup boot, so a claim about a field answers to the code rather than to prose. Its guarantee is stated narrowly and deliberately: no structural dereference on the code paths a wholly-corrupted profile takes, which is not every path a stored record takes. The paths it does not drive are named where the claim is made, and are tracked in #379.
This commit was merged in pull request #366.
This commit is contained in:
2026-08-23 23:06:17 +02:00
parent 45500e66cf
commit a098bb0c32
14 changed files with 2100 additions and 354 deletions

View File

@@ -153,7 +153,7 @@ describe("Back onto a view the reopened popup never rendered", () => {
test("Back onto the transaction detail renders it", () => {
reopenedOn("settings", ["main", "transaction"], {
viewData: { tx: { hash: "0xdead" } },
viewData: { tx: { hash: "0xdead", from: ADDRESS, to: ADDRESS } },
});
goBack();
expect(calls).toEqual(["transactionDetail"]);
@@ -162,7 +162,14 @@ describe("Back onto a view the reopened popup never rendered", () => {
test("Back onto the transaction confirmation restores it", () => {
reopenedOn("settings", ["main", "confirm-tx"], {
viewData: { pendingTx: { to: ADDRESS, amount: "1" } },
viewData: {
pendingTx: {
token: "ETH",
from: ADDRESS,
to: ADDRESS,
amount: "1",
},
},
});
goBack();
expect(calls).toEqual(["confirmTx"]);
@@ -171,7 +178,7 @@ describe("Back onto a view the reopened popup never rendered", () => {
test("Back onto the success screen renders it", () => {
reopenedOn("settings", ["main", "success-tx"], {
viewData: { hash: "0xdead" },
viewData: { hash: "0xdead", to: ADDRESS },
});
goBack();
expect(calls).toEqual(["successTx"]);
@@ -180,7 +187,7 @@ describe("Back onto a view the reopened popup never rendered", () => {
test("Back onto the failure screen renders it", () => {
reopenedOn("settings", ["main", "error-tx"], {
viewData: { message: "execution reverted" },
viewData: { message: "execution reverted", to: ADDRESS },
});
goBack();
expect(calls).toEqual(["errorTx"]);