From 076d049666f1c4621a2f0ddab0ae75493f59674e Mon Sep 17 00:00:00 2001 From: matcha Date: Sun, 4 Oct 2026 02:57:00 +0000 Subject: [PATCH] Finish Persims consolidation --- docs/persimmons-host-receipt.md | 193 ++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 docs/persimmons-host-receipt.md diff --git a/docs/persimmons-host-receipt.md b/docs/persimmons-host-receipt.md new file mode 100644 index 0000000..760c5c9 --- /dev/null +++ b/docs/persimmons-host-receipt.md @@ -0,0 +1,193 @@ +# Persimmons follow-up candidate — 2026-09-30 + +Version **0.3.4** fixes popup-memory-only connection state with a non-secret +owner hint and live session validation on every reopen. Vault keys still die with +the popup. A read-only, exact-origin, same-owner handshake lets the signed-in page +say Extension connected without exposing unlocked state or secrets. Actions/Juice +is a compact collapsed divider with technical details under disclosures. A +same-folder Python update helper plus Reload removes repeated manual ZIP handling. +Orange icons, hero/footer copy, crypto, server pinning, origin allowlist, dedicated +host and MCP boundaries are preserved. + +Candidate acceptance: **42 Python tests**, **11 Node tests across four files**, +plus real Chromium 1243 against the live Persimmons API and the **real** +`https://wp.phly.cloud/wp-login.php` (not an intercepted target fixture). Candidate +homepage assets were served locally into the Persimmons origin for pre-publication +review. Connect → initialize/unlock → save → destroy popup → refresh both pages → +reopen automatically Connected/Locked → wrong-passphrase rejection → unlock/list +→ fill both fields with **zero POST submissions** → delete all pass. Homepage +handshake, expired/logout session rejection, changed-owner rejection and revoked +host permission also pass. No Tea permission was granted. Synthetic accounts +remain, but successful tests remove their ciphertext and sign out; no provider +credentials or sessions are included in receipts. The normal Chromium permission +prompt was not clicked by automation: the harness pregrants the exact permission; +the user's accepted prompt is the human evidence. + +Package SHA-256: `d98ce727ebdedd9ceaec226960103baa58f8a5b65a0b8e31155b5fdea7334996`. +Initial and pre-publication fetch: HEAD/origin-main both +`26fec5fadd444ca2ccfe70c7eeb9ee6688bb7de4`, ahead 0 / behind 0; initial clean, +pre-commit dirty only with this task. No delegation. Build-generated host vault +module remains byte-for-byte copied from the accepted source. + +Deployment remains a separate required receipt: dispatch +**Launch independent Persimmons**, `.gitea/workflows/persimmons-launch.yml`, +`matcha/teahub`, ref **main**, no inputs, after canonical publication. The local +reviewed `tea_workflow_dispatch` allowlist does not include this workflow; do not +extend it through its own running control plane or bypass it with provider secrets. +Check the live `/healthz` source SHA and asset/package bytes after the run, then +repeat the browser check without `PERSIMMONS_LOCAL_UI=1`. + +User retest: use **Update extension** on the homepage, save the helper once, run +`python3 update-extension.py "/path/to/existing/persimmons-extension"`, then +`chrome://extensions` → Persimmons → **Reload** (do not uninstall). Sign in at +Persimmons; open the WordPress login URL, Connect once, unlock, save a disposable +credential, close/refresh/reopen, unlock, select/Fill without submit, and Delete. +Refresh Persimmons to see Extension connected. Future updates reuse the same +helper command/folder; 0.3.4 also offers popup **Reload installed files**. + +Remaining: Chrome Web Store private/unlisted distribution needs explicit approval, +review and a verified matching store identity. No Store upload/publication was +attempted. True self-download of unpacked extension source is unavailable; Reload +alone rereads files. Helper browser acceptance is Linux-only. Detailed update +mechanics, platform notes and official references are in +[persimmons-extension/README.md](../persimmons-extension/README.md#034-connection-controlled-acceptance-and-updates). + +--- + +# Persimmons taste-test receipt — 2026-09-30 + +Accepted: is live. Homepage, health, extension download, +exact-origin preflight and real Chromium encrypted-vault flow pass. + +## Deployment and acceptance + +- Runtime source: `54f0ff75f7b6a89d69dc4a211b44467ffc35be03`. + [Final launch Action 617](https://teahub.xyz/matcha/teahub/actions/runs/617), job 619, + succeeded; complete deployment/check cycle: 52.814 seconds. +- Before deploy: explicit fetch; worktree HEAD = upstream = runtime source; + ahead 0, behind 0, dirty false. Initial canonical source was `a80a64f`. + AGENTS and factory checkpoint read; no delegation. +- Fly app `persimmons-app`, `iad`; one shared CPU / 512 MiB; + machine `48e729dc5796e8`, release 2, health passing. + Encrypted 1 GiB volume `vol_rkgqyxm5k2gxm064` persists `/data`. +- Image `registry.fly.io/persimmons-app:deployment-01M3QY0KQ70X44T1EA7CYETDE0`; + digest `sha256:c99e5711c0dffee68816bd9059e81ce4c9bee6873e6f9b03198d4abae96a234f`. +- Cloudflare apex A `66.241.124.82`, AAAA `2a09:8280:1::1a0:f8e1:0`; + TTL 60, DNS-only. Fly-managed Let's Encrypt RSA/ECDSA certificates are verified + and active. No additional hostname or Cloudflare Worker is needed. +- `/`, `/healthz`, app JS, sign-in JS and extension ZIP: 200/nonempty. + Health reports the runtime source above. Final extension 0.3.2 matches the + tested package byte-for-byte: SHA-256 + `41dd24474ad35fca6d37378b641c0ded300450bc39145315a2d1d256a87d0430`. +- Preflight on `/api/human-vault/items` and `/api/human-vault/items/read`: 204, + credentials true, exactly one ACAO: + `chrome-extension://kiolgjoohhgdohcafgelhikpgkbmckbg`. Untrusted origins: 403, + no ACAO. No wildcard callers. +- Live disposable HTTP flow: register/login 200, extension Web Crypto ciphertext + create 201, logout/login, persisted read 200, delete 200, logout 200. +- Real Chromium 1243: homepage and independent signup pass; actual pinned popup + has Persimmons permission and **no Tea permission**; session cookie transport, + unlock, encrypted save, explicit fill, lock, unlock/delete and logout rejection + all pass. Fill used a locally intercepted HTTPS form; it contacted neither + WordPress nor Tea. Successful probes delete their ciphertext and sign out. +- Ten Node tests and seven Python host/vault/MCP tests pass. Canonical MCP tests + assert exactly `persimmons_list` and `persimmons_juice_list`, with no human-store + access. Connected agent inventory exposes only the metadata tool, no reveal tool. + +## Scope and preserved boundaries + +The host reuses the accepted `tea/web/🍊/index.html` design, with taste-test controls +for independent sign-in and extension download. Repository-token management and +Juice remain on the Tea fallback; this round does not migrate those stores or the +full repository-management UI. No Tea/StreetPulse runtime dependency was added. +No neighboring service was restarted, redeployed, or changed. Tea source/UI and +human-vault routes remain available as fallback. + +Build copies `tea_mcp/human_vault.py` byte-for-byte; both copies have SHA-256 +`8651aed1f8351477cdfd737a9f0d0b38b2e6e7f68edde964980e520a4c9f4f81`. +Route prefix is `/api`; empty POST reads append `/read`. Real Chromium omitted +Origin on permitted extension GET requests, which the accepted handler correctly +rejected. The POST adapter carries Chromium's genuine Origin into the unchanged +read handler; it never invents a caller header or weakens the HTTPS/session/owner +checks. The initial HTTP-only launch ([614](https://teahub.xyz/matcha/teahub/actions/runs/614)) +was corrected before final browser acceptance. + +Independent accounts use scrypt password verifiers, throttled same-origin auth +POSTs, and revocable 12-hour opaque Secure/HttpOnly host-only sessions. Account +passwords are separate from local vault passphrases. No account recovery, local +key sync or old-vault migration is added. Wrapped keys are namespaced by origin +and account. The separate extension Actions/Juice controls retain their explicit +Tea permission/session flow. The new host has no MCP endpoint. + +Existing Actions `FLY_INFRA` / `CLOUD_DNS` secrets stayed inside the runner. +[Preflight 610](https://teahub.xyz/matcha/teahub/actions/runs/610) proved zone reads; +[611](https://teahub.xyz/matcha/teahub/actions/runs/611) created/deleted a unique TXT +probe (both 200). No existing DNS records were replaced. Browser shared libraries +and fonts were extracted under `/tmp`; no worker packages were installed. + +## Exact human taste-test steps + +1. Open `https://persimmons.app`. Follow **Sign in / create account**, choose a + disposable username and a password of at least 12 characters, and create the + account. The homepage should say **Signed in to Persimmons**. +2. Download the Chromium extension from the homepage, extract the ZIP, and use + `chrome://extensions` → Developer mode → **Load unpacked** → extracted + `persimmons-extension` folder. Verify ID `kiolgjoohhgdohcafgelhikpgkbmckbg`. + Update/reload the existing same-ID extension if already installed; retain the + same browser profile. Existing Tea keys remain separate. +3. In that browser profile, open an existing allowed HTTPS login form at + `https://wp.phly.cloud` or `https://teahub.xyz`. This test does not change either + service. Use only the existing disposable-credential test account. +4. Open the extension. Under **My vault · human accounts**, click **Connect / list + this origin** and allow `persimmons.app`. Enter a distinct vault passphrase of + at least 12 characters, then **Initialize / unlock My vault**. The passphrase + and decrypted keys stay in the extension. +5. Enter the disposable account username/password and **Encrypt and save account**. + Close and reopen the popup, reconnect, unlock, select the account, then click + **Fill**. Check the two fields; the extension does not submit the form. +6. Lock the popup and verify Fill is unavailable. Unlock and delete the encrypted + disposable item. Sign out on Persimmons; reconnect must fail safely. Sign in + again to verify the same independent account owns the vault. +7. Agent inspection must expose only connection/Juice metadata through the existing + accepted MCP inventory. Never paste passwords, vault passphrases, cookies or + ciphertext into chat, logs, screenshots, or issue receipts. + +Keep the browser profile and vault passphrase: local keys have no recovery or sync. +No existing credential or wrapped-key migration is attempted in this round. + + +## Repeat automated checks + +Run `python persimmons/build.py`, then +`node --test persimmons-extension/tests/*.test.mjs` and +`python -m unittest tests.test_persimmons_host tests.test_human_vault`. + +`tests/persimmons-host-browser.cjs` repeats the live disposable-account browser +check from repository root. It requires Playwright and Chromium; optionally set +`PERSIMMONS_PLAYWRIGHT_MODULE` to an installed Playwright module path and +`PERSIMMONS_CHROMIUM` to the executable. Synthetic account verifiers remain; +failed early browser probes' unused sessions expire within 12 hours. No real +provider credentials were used. + +Provider mechanics: [Cloudflare DNS API](https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/list/) +and [Fly custom-domain validation](https://docs.fly.io/networking/custom-domain/). + +## 0.3.5 golf pass — 2026-09-30 + +Generic popup copy now shows the current site and Connect, then Unlock, then +saved accounts / Save for this site. Settings appears only after connection; +Juice remains collapsed and appears only when unlocked on its supported Tea +origin. Secondary token requests are lazy. Provider hints are absent elsewhere. +The homepage removes unused provider/repository controls, hides Get when the +extension responds, and shows Update only after a numeric version comparison +against the build's version.json. CSV import is not shipped; the extension README +specifies the bounded local, selective, deduplicating, ciphertext-only next step. +Crypto, origin allowlists, owner/session validation and MCP access are unchanged. + +Validation: 38 Persimmons Python tests plus the human-vault checks pass; six Node +test files cover crypto, current-origin behavior, no-reveal, connection ownership, +popup visibility and homepage version states. Chromium acceptance is inconclusive: +local UI navigation and a subsequent browser launch timed out on this worker. +No successful real-browser result is claimed for this pass. Initial and +pre-publication canonical base: bc1ad9ff8337d18da7ce52704eecbf0f6051d75c, +ahead 0 / behind 0, no unrelated worktree edits. No delegation.