65de4e3e2cc5
test: add Firefox sender-context CI coverage (v5.0.27)
- time
- 2026-08-30 12:30 UTC · 1 month ago
- machine
- koh2
- parent
- a5aedfd3830e
↓ peach-browser-65de4e3e.tar.gzatlas at this save
files changed7 files
bun.lock+32 −13manifest.firefox.json+1 −1manifest.json+1 −1package.json+3 −1scripts/ci.ts+7 −0scripts/test-firefox-sender-context.mjs+238 −0tests/fixtures/firefox-sender-probe.js+18 −0bun.lock+32 −13
@@ -35,6 +35,7 @@3535 "@types/pako": "^2.0.4",3636 "@types/papaparse": "^5.5.2",3737 "chrome-webstore-upload-cli": "^4.0.0",38+ "geckodriver": "6.1.1",3839 "jsdom": "^29.0.2",3940 "typescript": "^6.0.3",4041 "vite": "^8.0.8",@@ -404,8 +405,12 @@404405 405406 "@vitest/utils": ["@vitest/[email protected]", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw=="],406407 408+ "@wdio/logger": ["@wdio/[email protected]", "", { "dependencies": { "chalk": "^5.1.2", "loglevel": "^1.6.0", "loglevel-plugin-prefix": "^0.8.4", "safe-regex2": "^5.0.0", "strip-ansi": "^7.1.0" } }, "sha512-0ZAEIo6PNyMIJPlOGkIgyOJUjcd0pC8/QHlVAAe1c91/IcjZ1X+k0yidXHaboJdN7dq1XPUacmhRdtua0U5EZg=="],409+407410 "@webcomponents/custom-elements": ["@webcomponents/[email protected]", "", {}, "sha512-CqTpxOlUCPWRNUPZDxT5v2NnHXA4oox612iUGnmTUGQFhZ1Gkj8kirtl/2wcF6MqX7+PqqicZzOCBKKfIn0dww=="],408411 412+ "@zip.js/zip.js": ["@zip.js/[email protected]", "", {}, "sha512-F9RnQJXgvCSdAJfMtSrH5Uh/LcLg8fZlg5ARC4u5N4w9v/DG27cN3C/ngUrY1JdJGX2LRv5DDViXeZJgbcppWA=="],413+409414 "@zxcvbn-ts/core": ["@zxcvbn-ts/[email protected]", "", { "dependencies": { "fastest-levenshtein": "1.0.16" } }, "sha512-aQeiT0F09FuJaAqNrxynlAwZ2mW/1MdXakKWNmGM1Qp/VaY6CnB/GfnMS2T8gB2231Esp1/maCWd8vTG4OuShw=="],410415 411416 "@zxcvbn-ts/language-common": ["@zxcvbn-ts/[email protected]", "", {}, "sha512-viSNNnRYtc7ULXzxrQIVUNwHAPSXRtoIwy/Tq4XQQdIknBzw4vz36lQLF6mvhMlTIlpjoN/Z1GFu/fwiAlUSsw=="],@@ -436,7 +441,7 @@436441 437442 "ansi-align": ["[email protected]", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="],438443 439- "ansi-regex": ["[email protected]", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],444+ "ansi-regex": ["[email protected]", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],440445 441446 "ansi-styles": ["[email protected]", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],442447 @@ -664,6 +669,8 @@664669 665670 "fx-runner": ["[email protected]", "", { "dependencies": { "commander": "2.9.0", "shell-quote": "1.7.3", "spawn-sync": "1.0.15", "when": "3.7.7", "which": "1.2.4", "winreg": "0.0.12" }, "bin": "bin/fx-runner" }, "sha512-rci1g6U0rdTg6bAaBboP7XdRu01dzTAaKXxFf+PUqGuCv6Xu7o8NZdY1D5MvKGIjb6EdS1g3VlXOgksir1uGkg=="],666671 672+ "geckodriver": ["[email protected]", "", { "dependencies": { "@wdio/logger": "^9.18.0", "@zip.js/zip.js": "^2.8.11", "decamelize": "^6.0.1", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "modern-tar": "^0.7.3" }, "bin": { "geckodriver": "bin/geckodriver.js" } }, "sha512-/AcCyc9o9o6hUbudaSJM2iOtXbxSLqQPOb4GrPvEN40cjraUeaX/j5kH3mSgwiroyMn7qzx2wM61AQ2XY8j3sA=="],673+667674 "gensync": ["[email protected]", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],668675 669676 "get-caller-file": ["[email protected]", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],@@ -694,6 +701,8 @@694701 695702 "htmlparser2": ["[email protected]", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "entities": "^7.0.1" } }, "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ=="],696703 704+ "http-proxy-agent": ["[email protected]", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],705+697706 "https-proxy-agent": ["[email protected]", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],698707 699708 "iconv-lite": ["[email protected]", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],@@ -838,6 +847,10 @@838847 839848 "lodash.once": ["[email protected]", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="],840849 850+ "loglevel": ["[email protected]", "", {}, "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg=="],851+852+ "loglevel-plugin-prefix": ["[email protected]", "", {}, "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g=="],853+841854 "lru-cache": ["[email protected]", "", {}, "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw=="],842855 843856 "magic-string": ["[email protected]", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],@@ -860,6 +873,8 @@860873 861874 "minimist": ["[email protected]", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],862875 876+ "modern-tar": ["[email protected]", "", {}, "sha512-t9VmxaqrmANnEOBhpSDI6HD192Ge48k8vmWqQQL7hSFEqHEYwZbbsu49+aKLWZeRvFs3j1pMhXOqqF4kPlvjkQ=="],877+863878 "mrmime": ["[email protected]", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],864879 865880 "ms": ["[email protected]", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],@@ -976,6 +991,8 @@976991 977992 "resolve-from": ["[email protected]", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],978993 994+ "ret": ["[email protected]", "", {}, "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw=="],995+979996 "reusify": ["[email protected]", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],980997 981998 "rolldown": ["[email protected]", "", { "dependencies": { "@oxc-project/types": "=0.124.0", "@rolldown/pluginutils": "1.0.0-rc.15" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.15", "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", "@rolldown/binding-darwin-x64": "1.0.0-rc.15", "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" }, "bin": "bin/cli.mjs" }, "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g=="],@@ -990,6 +1007,8 @@9901007 9911008 "safe-buffer": ["[email protected]", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],9921009 1010+ "safe-regex2": ["[email protected]", "", { "dependencies": { "ret": "~0.5.0" }, "bin": { "safe-regex2": "bin/safe-regex2.js" } }, "sha512-mOSBvHGDZMuIEZMdOz/aCEYDCv0E7nfcNsIhUF+/P+xC7Hyf3FkvymqgPbg9D1EdSGu+uKbJgy09K/RKKc7kJA=="],1011+9931012 "safe-stable-stringify": ["[email protected]", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],9941013 9951014 "safer-buffer": ["[email protected]", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],@@ -1042,7 +1061,7 @@10421061 10431062 "string_decoder": ["[email protected]", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],10441063 1045- "strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],1064+ "strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],10461065 10471066 "strip-bom": ["[email protected]", "", {}, "sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A=="],10481067 @@ -1230,8 +1249,12 @@12301249 12311250 "cheerio/whatwg-mimetype": ["[email protected]", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="],12321251 1252+ "cliui/strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],1253+12331254 "cliui/wrap-ansi": ["[email protected]", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],12341255 1256+ "columnify/strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],1257+12351258 "config-chain/ini": ["[email protected]", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="],12361259 12371260 "cross-spawn/which": ["[email protected]", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],@@ -1280,6 +1303,8 @@12801303 12811304 "rxjs/tslib": ["[email protected]", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],12821305 1306+ "string-width/strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],1307+12831308 "thread-stream/real-require": ["[email protected]", "", {}, "sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g=="],12841309 12851310 "update-notifier/semver": ["[email protected]", "", { "bin": "bin/semver.js" }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],@@ -1292,8 +1317,6 @@12921317 12931318 "wrap-ansi/string-width": ["[email protected]", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],12941319 1295- "wrap-ansi/strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],1296-12971320 "wsl-utils/is-wsl": ["[email protected]", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="],12981321 12991322 "yauzl/buffer-crc32": ["[email protected]", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="],@@ -1306,22 +1329,18 @@13061329 13071330 "boxen/string-width/emoji-regex": ["[email protected]", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],13081331 1309- "boxen/string-width/strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],1332+ "cliui/strip-ansi/ansi-regex": ["[email protected]", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],13101333 1334+ "columnify/strip-ansi/ansi-regex": ["[email protected]", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],1335+13111336 "cross-spawn/which/isexe": ["[email protected]", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],13121337 13131338 "eslint/ajv/json-schema-traverse": ["[email protected]", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],13141339 1340+ "string-width/strip-ansi/ansi-regex": ["[email protected]", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],1341+13151342 "widest-line/string-width/emoji-regex": ["[email protected]", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],13161343 1317- "widest-line/string-width/strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],1318-13191344 "wrap-ansi/string-width/emoji-regex": ["[email protected]", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],1320-1321- "wrap-ansi/strip-ansi/ansi-regex": ["[email protected]", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],1322-1323- "boxen/string-width/strip-ansi/ansi-regex": ["[email protected]", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],1324-1325- "widest-line/string-width/strip-ansi/ansi-regex": ["[email protected]", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],13261345 }13271346 }manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach Password Manager",4- "version": "5.0.25",4+ "version": "5.0.27",55 "description": "Zero-knowledge password manager",66 "browser_specific_settings": {77 "gecko": {manifest.json+1 −1
@@ -2,7 +2,7 @@22 "manifest_version": 3,33 "minimum_chrome_version": "116",44 "name": "Peach Password Manager",5- "version": "5.0.25",5+ "version": "5.0.27",66 "description": "Zero-knowledge password manager",77 "action": {88 "default_popup": "src/popup/index.html",package.json+3 −1
@@ -1,6 +1,6 @@11 {22 "name": "peach",3- "version": "5.0.25",3+ "version": "5.0.27",44 "description": "Zero-knowledge password manager",55 "license": "GPL-3.0-only",66 "type": "module",@@ -12,6 +12,7 @@1212 "build:chrome": "node scripts/clean-chrome-dist.mjs && BUILD_TARGET=chrome vite build && npm run check:sw",1313 "build:firefox": "node scripts/clean-firefox-artifacts.mjs && BUILD_TARGET=firefox vite build",1414 "build:e2e": "PEACH_E2E_PASSKEYS=1 BUILD_TARGET=chrome vite build",15+ "test:firefox:sender": "node scripts/test-firefox-sender-context.mjs",1516 "package:firefox": "node scripts/clean-firefox-artifacts.mjs && npm run build:firefox && cd dist-firefox && web-ext build --overwrite-dest",1617 "lint": "biome check src/",1718 "lint:fix": "biome check --write src/",@@ -62,6 +63,7 @@6263 "@types/pako": "^2.0.4",6364 "@types/papaparse": "^5.5.2",6465 "chrome-webstore-upload-cli": "^4.0.0",66+ "geckodriver": "6.1.1",6567 "jsdom": "^29.0.2",6668 "typescript": "^6.0.3",6769 "vite": "^8.0.8",scripts/ci.ts+7 −0
@@ -12,6 +12,7 @@1212 const YELLOW = '\x1b[33m';1313 const BOLD = '\x1b[1m';1414 const DIM = '\x1b[2m';15+const RUN_FIREFOX_BROWSER_CHECKS = process.env.CI === 'true' || process.env.PEACH_E2E_FIREFOX === '1';1516 1617 interface Step {1718 name: string;@@ -53,6 +54,12 @@5354 name: 'Firefox build',5455 cmd: ['npm', 'run', 'build:firefox'],5556 },57+ ...(RUN_FIREFOX_BROWSER_CHECKS58+ ? [{59+ name: 'Firefox sender context',60+ cmd: ['npm', 'run', 'test:firefox:sender'],61+ }]62+ : []),5663 ];5764 5865 function run(step: Step): { ok: boolean; output: string; duration: number } {scripts/test-firefox-sender-context.mjs+238 −0
@@ -0,0 +1,238 @@1+#!/usr/bin/env node2+3+import { execFile } from "node:child_process";4+import { promisify } from "node:util";5+import { cp, mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";6+import { existsSync } from "node:fs";7+import { tmpdir } from "node:os";8+import { join, resolve } from "node:path";9+import net from "node:net";10+import { start } from "geckodriver";11+12+const execFileAsync = promisify(execFile);13+const ROOT = resolve(new URL("..", import.meta.url).pathname);14+const DIST = join(ROOT, "dist-firefox");15+const PROBE = join(ROOT, "tests/fixtures/firefox-sender-probe.js");16+const WEB_EXT = join(ROOT, "node_modules/.bin/web-ext");17+const EXTENSION_ID = "[email protected]";18+19+function findFirefoxBinary() {20+ const candidates = [21+ process.env.PEACH_FIREFOX_BINARY,22+ process.env.FIREFOX_BIN,23+ "/usr/bin/firefox",24+ "/usr/local/bin/firefox",25+ "/Applications/Firefox.app/Contents/MacOS/firefox",26+ "/Applications/Firefox Nightly.app/Contents/MacOS/firefox",27+ ].filter(Boolean);28+ return candidates.find((candidate) => existsSync(candidate));29+}30+31+function findFreePort() {32+ return new Promise((resolvePort, reject) => {33+ const server = net.createServer();34+ server.once("error", reject);35+ server.listen(0, "127.0.0.1", () => {36+ const address = server.address();37+ if (!address || typeof address === "string") {38+ server.close();39+ reject(new Error("Could not allocate a WebDriver port"));40+ return;41+ }42+ server.close(() => resolvePort(address.port));43+ });44+ });45+}46+47+async function waitForDriver(port) {48+ const deadline = Date.now() + 30_000;49+ while (Date.now() < deadline) {50+ try {51+ const response = await fetchWithTimeout(`http://127.0.0.1:${port}/status`, {}, 500);52+ if (response.ok && (await response.json()).value?.ready) return;53+ } catch {54+ // geckodriver is still starting.55+ }56+ await new Promise((resolveDelay) => setTimeout(resolveDelay, 250));57+ }58+ throw new Error("geckodriver did not become ready within 30 seconds");59+}60+61+async function fetchWithTimeout(url, options, timeoutMs) {62+ const controller = new AbortController();63+ let timeoutId;64+ const timeout = new Promise((_, reject) => {65+ timeoutId = setTimeout(() => reject(new Error(`Request timed out after ${timeoutMs}ms`)), timeoutMs);66+ });67+ try {68+ return await Promise.race([69+ fetch(url, { ...options, signal: controller.signal }),70+ timeout,71+ ]);72+ } finally {73+ clearTimeout(timeoutId);74+ controller.abort();75+ }76+}77+78+async function webdriverRequest(port, path, options = {}) {79+ const response = await fetchWithTimeout(`http://127.0.0.1:${port}${path}`, {80+ ...options,81+ headers: { "content-type": "application/json", ...(options.headers ?? {}) },82+ }, 10_000);83+ const body = await response.json();84+ if (!response.ok || body.value?.error) {85+ throw new Error(`WebDriver ${options.method ?? "GET"} ${path} failed: ${JSON.stringify(body)}`);86+ }87+ return body.value;88+}89+90+async function buildTestExtension(tempRoot) {91+ const sourceDir = join(tempRoot, "extension");92+ const artifactsDir = join(tempRoot, "artifacts");93+ await cp(DIST, sourceDir, { recursive: true });94+ await mkdir(artifactsDir, { recursive: true });95+ await cp(PROBE, join(sourceDir, "firefox-sender-probe.js"));96+97+ const manifestPath = join(sourceDir, "manifest.json");98+ const manifest = JSON.parse(await readFile(manifestPath, "utf8"));99+ manifest.content_scripts.push({100+ matches: ["<all_urls>"],101+ js: ["firefox-sender-probe.js"],102+ run_at: "document_start",103+ all_frames: false,104+ });105+ await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);106+107+ await execFileAsync(WEB_EXT, [108+ "build",109+ "--source-dir", sourceDir,110+ "--artifacts-dir", artifactsDir,111+ "--filename", "peach-firefox-sender-context.xpi",112+ "--overwrite-dest",113+ "--no-input",114+ ], { cwd: ROOT });115+ return join(artifactsDir, "peach-firefox-sender-context.xpi");116+}117+118+async function run() {119+ if (!existsSync(DIST)) throw new Error("dist-firefox is missing; run npm run build:firefox first");120+ if (!existsSync(WEB_EXT)) throw new Error("web-ext is missing; run bun install first");121+122+ const tempRoot = await mkdtemp(join(tmpdir(), "peach-firefox-sender-"));123+ let driver;124+ let driverPort;125+ let sessionId;126+ try {127+ const xpiPath = await buildTestExtension(tempRoot);128+ const firefoxBinary = findFirefoxBinary();129+ const port = await findFreePort();130+ driverPort = port;131+ driver = await start({132+ host: "127.0.0.1",133+ port,134+ geckoDriverVersion: "0.37.1",135+ ...(firefoxBinary ? { binary: firefoxBinary } : {}),136+ log: "error",137+ });138+ await waitForDriver(port);139+140+ const capabilities = {141+ browserName: "firefox",142+ acceptInsecureCerts: true,143+ "moz:firefoxOptions": {144+ args: ["-headless"],145+ ...(firefoxBinary ? { binary: firefoxBinary } : {}),146+ prefs: {147+ "browser.shell.checkDefaultBrowser": false,148+ "browser.startup.page": 0,149+ "browser.startup.homepage": "about:blank",150+ },151+ },152+ };153+ const session = await webdriverRequest(port, "/session", {154+ method: "POST",155+ body: JSON.stringify({ capabilities: { alwaysMatch: capabilities } }),156+ });157+ sessionId = session.sessionId;158+159+ const install = await webdriverRequest(port, `/session/${sessionId}/moz/addon/install`, {160+ method: "POST",161+ body: JSON.stringify({162+ addon: (await readFile(xpiPath)).toString("base64"),163+ temporary: true,164+ }),165+ });166+ if (install?.id && install.id !== EXTENSION_ID) {167+ throw new Error(`Unexpected Firefox add-on id: ${install.id}`);168+ }169+170+ await webdriverRequest(port, `/session/${sessionId}/url`, {171+ method: "POST",172+ body: JSON.stringify({ url: "https://example.com/" }),173+ });174+ const result = await webdriverRequest(port, `/session/${sessionId}/execute/async`, {175+ method: "POST",176+ body: JSON.stringify({177+ script: `178+ const done = arguments[arguments.length - 1];179+ const source = "peach-firefox-sender-probe";180+ const send = (message) => new Promise((resolve) => {181+ const id = crypto.randomUUID();182+ const timer = setTimeout(() => {183+ window.removeEventListener("message", onMessage);184+ resolve({ ok: false, error: "probe_timeout" });185+ }, 5000);186+ function onMessage(event) {187+ if (event.source !== window || event.data?.source !== source || event.data.id !== id) return;188+ clearTimeout(timer);189+ window.removeEventListener("message", onMessage);190+ resolve(event.data.response);191+ }192+ window.addEventListener("message", onMessage);193+ window.postMessage({ source, id, message }, window.location.origin);194+ });195+ Promise.all([196+ send({ type: "GET_SETTINGS" }),197+ send({ type: "GET_ENTRIES" }),198+ send({ type: "GET_RECOVERY_WORDS" }),199+ ]).then(([allowed, entries, recovery]) => done({200+ pageOrigin: location.origin,201+ allowed,202+ entries,203+ recovery,204+ }));205+ `,206+ args: [],207+ }),208+ });209+210+ if (result.pageOrigin !== "https://example.com") {211+ throw new Error(`Unexpected page origin: ${result.pageOrigin}`);212+ }213+ if (result.allowed?.error === "invalid_sender") {214+ throw new Error("Content-script-allowed GET_SETTINGS was rejected");215+ }216+ for (const [name, response] of [["GET_ENTRIES", result.entries], ["GET_RECOVERY_WORDS", result.recovery]]) {217+ if (response?.error !== "invalid_sender") {218+ throw new Error(`${name} was not rejected from the real Firefox content-script sender: ${JSON.stringify(response)}`);219+ }220+ }221+ console.log("Firefox sender-context test passed: real content-script GET_ENTRIES and GET_RECOVERY_WORDS were rejected, GET_SETTINGS remained allowed.");222+ } finally {223+ if (driver && sessionId) {224+ try {225+ await webdriverRequest(driverPort, `/session/${sessionId}`, { method: "DELETE" });226+ } catch {227+ // The browser may already have exited after a failed startup.228+ }229+ }230+ driver?.kill("SIGTERM");231+ await rm(tempRoot, { recursive: true, force: true });232+ }233+}234+235+run().catch((error) => {236+ console.error(error instanceof Error ? error.message : error);237+ process.exitCode = 1;238+});tests/fixtures/firefox-sender-probe.js+18 −0
@@ -0,0 +1,18 @@1+(() => {2+ const SOURCE = "peach-firefox-sender-probe";3+ const ALLOWED_TYPES = new Set(["GET_ENTRIES", "GET_RECOVERY_WORDS", "GET_SETTINGS"]);4+5+ window.addEventListener("message", async (event) => {6+ if (event.source !== window || event.data?.source !== SOURCE) return;7+ const { id, message } = event.data;8+ if (typeof id !== "string" || !message || !ALLOWED_TYPES.has(message.type)) return;9+10+ let response;11+ try {12+ response = await chrome.runtime.sendMessage(message);13+ } catch (error) {14+ response = { ok: false, error: String(error) };15+ }16+ window.postMessage({ source: SOURCE, id, response }, window.location.origin);17+ });18+})();