e1c5043e4311

fix Chrome content-script chunk allowlisting and real-form regression coverage (v5.0.100)

time
2026-09-05 01:15 UTC · 1 month ago
machine
koh2
agent
claude-sonnet-5
session
restore form icon injection
parent
42cdd29d63cf
6 files manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1scripts/web-accessible-resources.test.ts+2 −2tests/form-icon.spec.ts+40 −0vite.config.ts+0 −4
manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach Password Manager",4-  "version": "5.0.99",4+  "version": "5.0.100",55   "description": "Zero-knowledge password manager",66   "browser_specific_settings": {77     "gecko": {

view file

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.99",5+  "version": "5.0.100",66   "description": "Zero-knowledge password manager",77   "action": {88     "default_popup": "src/popup/index.html",

view file

package.json+1 −1
@@ -1,6 +1,6 @@11 {22   "name": "peach",3-  "version": "5.0.99",3+  "version": "5.0.100",44   "description": "Zero-knowledge password manager",55   "license": "GPL-3.0-only",66   "type": "module",

view file

scripts/web-accessible-resources.test.ts+2 −2
@@ -20,11 +20,11 @@2020 }2121 2222 describe("shipped web-accessible resources", () => {23-  it("uses session-randomized URLs for Chrome content-script resources", () => {23+  it("allows Chrome content-script chunks from stable extension URLs", () => {2424     const resources = readManifest("chrome").web_accessible_resources ?? [];2525 2626     expect(resources).toHaveLength(1);27-    expect(resources[0]?.use_dynamic_url).toBe(true);27+    expect(resources[0]?.use_dynamic_url).toBe(false);2828     expect(resources[0]?.matches).toEqual(["<all_urls>"]);2929     expect(resources[0]?.resources.length).toBeGreaterThan(0);3030   });

view file

tests/form-icon.spec.ts+40 −0
@@ -0,0 +1,40 @@1+import { test, expect, type BrowserContext } from "@playwright/test";2+import { createServer, type Server } from "node:http";3+import { makeContext } from "./helpers/vault";4+5+test.describe("Real form icon injection", () => {6+  let ctx: BrowserContext;7+  let server: Server;8+  let origin: string;9+10+  test.beforeEach(async () => {11+    server = createServer((_request, response) => {12+      response.writeHead(200, { "content-type": "text/html; charset=utf-8" });13+      response.end(`<!doctype html>14+        <form aria-label="Sign in">15+          <label>Username <input name="username" autocomplete="username"></label>16+          <label>Password <input type="password" name="password" autocomplete="current-password"></label>17+          <button type="submit">Sign in</button>18+        </form>`);19+    });20+    await new Promise<void>((resolve, reject) => {21+      server.once("error", reject);22+      server.listen(0, "127.0.0.1", resolve);23+    });24+    const address = server.address();25+    if (!address || typeof address === "string") throw new Error("form fixture did not bind");26+    origin = `http://127.0.0.1:${address.port}`;27+    ctx = await makeContext("peach-form-icon");28+  });29+30+  test.afterEach(async () => {31+    await ctx?.close();32+    await new Promise<void>((resolve, reject) => server.close(error => error ? reject(error) : resolve()));33+  });34+35+  test("injects Peach icons into a real login form", async () => {36+    const page = await ctx.newPage();37+    await page.goto(origin);38+    await expect(page.locator('button[aria-label="Peach autofill"]')).toHaveCount(2, { timeout: 10_000 });39+  });40+});

view file

vite.config.ts+0 −4
@@ -11,7 +11,6 @@1111   manifest.web_accessible_resources = [{1212     matches: ["<all_urls>"],1313     resources: ["<dynamic_resource>"],14-    use_dynamic_url: true,1514   }];1615 }1716 const passkeyE2E = process.env.PEACH_E2E_PASSKEYS === "1";@@ -32,9 +31,6 @@3231     if (target === "chrome") {3332       const outputManifest = resolve(outDir, "manifest.json");3433       const builtManifest = JSON.parse(readFileSync(outputManifest, "utf8"));35-      for (const resource of builtManifest.web_accessible_resources ?? []) {36-        resource.use_dynamic_url = true;37-      }3834       writeFileSync(outputManifest, `${JSON.stringify(builtManifest, null, 2)}\n`);3935     }4036   },

view file