What's left to build in this repo. The Frappe app has its own plan in
frappe-app.md and its own repo (docsigner_integration).
Working end to end. Signed output validates as PAdES, in Adobe and in the EU DSS validator. Server-side signing, token signing through the browser, and the desktop batch app all run. Not yet published to the extension stores.
Shipped: the signing engine, the reference server, the native host (rewritten in Rust), the extension and page library, the desktop app, standards depth up to B-LTA and the CCA profiles, and the device-layer diagnostics that came out of the first live week.
| # | What | Files |
|---|---|---|
| C1 | Marks on every page. A visible mark (name, date, page x of y) on all pages plus the one cryptographic field, in one incremental revision. | new core/docsigner_core/marks.py |
| C2 | Caption line on the stamp. "Reviewed by" / "Approved by" above the name. Additive appearance field, needs a CONTRACTS changelog entry. | core/docsigner_core/appearance.py |
Both are asked for by the Frappe app's phases 9 and 9.5, so they land here first.
The long poles. Nothing else depends on them, but the lead times are weeks.
| # | What | Notes |
|---|---|---|
| D1 | Extension listings. Chrome Web Store and Firefox AMO. Store copy from the README, privacy answers from CONTRACTS (no analytics, no remote calls). | Native messaging draws extra review scrutiny. Submit early. The release now attaches both store zips, so the upload is a download rather than a local build. |
| D2 | Host installers. pkg, MSI, deb/rpm. | macOS no longer waits on a certificate: the Homebrew formula installs unquarantined, so a notarized pkg is a convenience, not the gate. An unsigned MSI works too and only shows "Unknown publisher"; D7 removes that. |
| D3 | Update channel. checkUpdate.checkUpdate(), the default feed is the latest.json each release publishes, and the consent popup shows an amber line with a Get it link when a newer host exists. Left: the desktop Settings panel. |
The check was written, tested and documented, then blocked by the extension's own allowlist, so it just answered UNSUPPORTED. Over https it also failed outright — ureq's native-tls needs its connector handed over, and every test used local http. A js test now pins the allowlist against the commands CONTRACTS §2 defines, and an e2e test pins that https works. |
| D4 | Token compatibility table. Seeded from the known lists in modules.rs and pcsc_readers.rs. |
Grows by user report. |
| D5 | NOTICE for Lucide and the fonts. |
Every manifest declares it and the Homebrew formula carries license "Apache-2.0". The cask has no license stanza to fill; Homebrew does not define one. |
| D6 | A tap repo. resilient-tech/homebrew-tap, with Formula/ and Casks/. The release attaches both files with their checksums already filled in, so each release is a copy of two files. |
Waits on the repo going public, same as D7. Until then the files are validated in place with a throwaway tap: brew tap-new --no-git, copy them in, brew style. |
| D7 | Windows code signing, free. Apply to SignPath Foundation for a certificate at no cost, then sign the host and the desktop .exe in CI. |
Needs the repo public first, plus an OSI license (D5) and a reproducible CI build. They review by hand and it takes a couple of weeks, so apply the day the repo opens. Once signed, the MSI in D2 stops saying "Unknown publisher". |
| D8 | The cryptography<49 pin in the desktop app. Pinned because 49 dropped macOS x86_64 and universal2 wheels, and the .app is x86_64 so the sidecar can reach x86_64-only token drivers. |
Watch pyca advisories. The day a fix lands only in 49+, drop the pin and build the .app arm64-native with the sidecar left at x86_64: they are separate processes, so the architectures need not match, and nothing in the Python process loads a PKCS#11 module. Cost of that switch is Intel Macs losing the desktop app, keeping the browser flow. Reasoning in full in desktop/backend/requirements.txt. |
Before any of it: real-token runs on all 3 operating systems, per release-checklist.md.
Building on all three no longer needs all three. The release workflow ships the
host, the desktop app and both extension zips for macOS, Windows and Linux off
GitHub's runners, and latest.json carries a downloads URL for each. Two of
those artifacts have never been opened: the Windows and Linux desktop builds are
published untested, and the host's Windows certificate-store path is still unrun
code. Running them is a machine, not a build.
From the first week on a real bench with a real Capricorn token (2026-07-08). Each of these is fixed; they're here because they say what to watch for.
- An empty certificate list has to explain itself. The page library was
dropping the host's
readersarray, so every failure showed the same generic "plug in your token" hint.listCertificates()now returns{certificates, readers, diagnostics}and the host reports per-source scan counters, so the hint names the actual cause. - Token drivers wedge. ePass/ProxKey-class drivers allow one process on the
token at a time, and some only enumerate at
C_Initialize. Covered by a reinitialize per scan, a 20-second watchdog per module, and competing-process detection that names the program to close. - SHA-512 worked; the display lied. The verify page labelled the file fingerprint "SHA-256" and never showed the signature digest.
- Ten handwriting fonts was too many. Trimmed to 5, one per personality.
Safari (needs a signed macOS app wrapper), EU trust lists (needs an EUTL XML parser), RSA-PSS, and a database-backed session store. Reasons are in architecture.md under "What we skipped, on purpose". Each one moves onto this list the day someone actually needs it.