Skip to content

Windows NSIS installer + first-run privacy gate - #35

Draft
kGeee wants to merge 5 commits into
mainfrom
cursor/windows-nsis-first-run-225d
Draft

kGeee wants to merge 5 commits into
mainfrom
cursor/windows-nsis-first-run-225d

Conversation

@kGeee

@kGeee kGeee commented Aug 26, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a releasable native Windows product path for budgetr (Electron + NSIS), without replacing the Mac DMG flow or the skippable Plaid onboarding wizard.

Packaging

  • electron-builder 25.x Windows target: NSIS x64, artifact budgetr-win.exe
  • Per-user install (perMachine: false, allowElevation: false) — no admin/UAC
  • desktop/scripts/make-ico.mjs builds icon.ico from existing PWA icons
  • Receipt OCR extraResources moved under mac only (not shipped on Windows)
  • npm run package:win / package:mac (package remains the Mac alias)
  • .github/workflows/release.yml: windows-nsis on windows-latest alongside mac-dmg, same v* tag
  • Signing split: Mac keeps CSC_LINK / CSC_KEY_PASSWORD. Windows Authenticode uses separate WIN_CSC_LINK / WIN_CSC_KEY_PASSWORD when present; otherwise CSC is unset and the NSIS build stays unsigned (SmartScreen expected). Mac Developer ID must not sign Windows.
  • Publish asserts budgetr-win.exe exists before upload (fail_on_unmatched_files: false only for optional latest.yml / blockmap).
  • asar: false unchanged; secrets still live in per-user budgetr.env

First-run privacy gate (packaged Windows only)

Hard gate at /desktop-setup before /overview, app chrome, or the Plaid wizard. Marketing site (MARKETING_ONLY), npm run dev, and start.bat are not blocked.

Uses only the Marketing Chief three-screen copy (ledger location %APPDATA%\budgetr\ / budgetr.db, BYO Plaid, read-only). No /privacy or terms pages, no placeholder legal URLs, no invented privacy-policy copy.

  1. Your ledger stays on this PC. (required ack)
  2. What this app is allowed to do. (required ack; “Not now” quits the app)
  3. This is the folder. Shows %APPDATA%\budgetr\ copy plus the resolved userData path; Open data folder / Continue into the app

Completion is persisted as privacy-gate-done in Electron userData. Screen 1’s “Where the file will live” peeks at screen 3 without skipping screens 1–2.

Window chrome

Windows uses a native frame (min/max/close + drag). macOS keeps hiddenInset traffic lights.

Docs

Root README points non-devs at the Windows installer from Releases (not start.bat) and explains the expected SmartScreen first-open warning for unsigned builds.

Test plan

  • Unit tests: npm test -- lib/desktop-privacy-gate.test.ts
  • node desktop/scripts/make-ico.mjs produces a valid .ico
  • Forced local preview: /overview redirects to /desktop-setup until all three screens + acks complete, then dashboard loads
  • CI green on this branch
  • Tag v* produces budgetr-win.exe (assert step fails the job if missing)
  • Fresh Windows install: “Not now” quits; “Open data folder” opens userData
  • After completion, relaunch skips the gate; Plaid /onboarding still available/skippable
  • Mac package:mac / release job still green; no OCR binary on Windows artifact
  • windows-nsis does not receive Mac CSC_LINK (only WIN_CSC_* when set)
Open in Web Open in Cursor 

Ship a per-user x64 NSIS installer (budgetr-win.exe) via electron-builder 25.x
and a windows-latest release job alongside the existing Mac DMG path. Packaged
Windows builds show a hard three-screen privacy/permissions/data-folder gate
before any app chrome; Mac packaging, OCR extras, and the skippable Plaid
wizard are unchanged.

Co-authored-by: Kevin George <kGeee@users.noreply.github.com>
@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
budgetr Ready Ready Preview Sep 4, 2026 4:59pm UTC

…preview

The fallback POST handler rejected non-win32 platforms, so the
BUDGETR_PRIVACY_GATE_FORCE local preview could never write the marker.
Packaged Windows still completes via Electron IPC; the HTTP path now
keys off BUDGETR_DESKTOP instead of process.platform.

Co-authored-by: Kevin George <kGeee@users.noreply.github.com>
Make the root README explicit that the first Windows Release artifacts are
intentionally unsigned and that More info → Run anyway is the normal first-open
path for non-developers.

Co-authored-by: Kevin George <kGeee@users.noreply.github.com>
windows-nsis must not reuse Mac CSC_LINK for Authenticode. Wire
WIN_CSC_LINK / WIN_CSC_KEY_PASSWORD when present, otherwise leave CSC
unset so the NSIS build stays unsigned. Fail the job if
budgetr-win.exe is missing before publish.

Co-authored-by: Kevin George <kGeee@users.noreply.github.com>

@kGeee kGeee left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: COMMENT (hold merge) — head e4fe228

Both nits from 4a2b163 are fixed. No remaining code concerns with this delta. Still a draft, so this is not an approve. Do not merge.

What landed (e4fe228, 29/8, one file)

  • Signing split: windows-nsis takes WIN_CSC_LINK / WIN_CSC_KEY_PASSWORD only. Mac CSC_LINK is no longer in this job's env, so a Developer ID .p12 cannot Authenticode-sign the NSIS installer. Empty WIN_CSC_* unsets CSC_LINK and the build stays unsigned (SmartScreen still the first-open path). No cert invented or committed.
  • Required artifact: new step fails the job if web/dist/budgetr-win.exe is missing. fail_on_unmatched_files: false can stay on publish for optional latest.yml / blockmap.

Checklist (unchanged, still pass)

  1. NSIS x64 per-user, no UAC, asar: false
  2. Packaged-Windows-only privacy gate before /overview / chrome / Plaid; marketing / npm run dev / start.bat not blocked
  3. No /privacy pages, no placeholder legal URLs
  4. OCR extraResources Mac-only
  5. SmartScreen called out in README
  6. Do not merge (still draft)

No secrets in the diff (secret names only). web CI was still in progress at review time; it does not exercise package:win (release is tag-only).

Remaining (all non-code)

  • Still a draft
  • First v* / Windows install proof (Not now quits, Open data folder, relaunch skips gate, no OCR on the Windows artifact)
  • WIN_CSC_* repo secrets only when a real Authenticode cert exists — not for this PR

Comment on lines +189 to +200
- name: Assert Windows installer artifact
# cwd is web/ (job default). fail_on_unmatched_files stays false below so
# optional latest.yml / blockmap globs don't fail the job — but the
# NSIS installer itself is required.
shell: bash
run: |
if [ ! -f dist/budgetr-win.exe ]; then
echo "Required artifact missing: web/dist/budgetr-win.exe" >&2
ls -la dist || true
exit 1
fi
ls -lh dist/budgetr-win.exe

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This closes the other nit. fail_on_unmatched_files: false can stay on publish so optional latest.yml / *.blockmap don't fail an unsigned first release, and this step fails the job if web/dist/budgetr-win.exe is missing. Job defaults.run.working-directory is web, so dist/budgetr-win.exe is the right path.

Comment on lines +175 to +186
if [ -z "$WIN_CSC_LINK" ]; then
unset CSC_LINK CSC_KEY_PASSWORD
else
export CSC_LINK="$WIN_CSC_LINK"
export CSC_KEY_PASSWORD="$WIN_CSC_KEY_PASSWORD"
fi
npm run package:win
env:
WIN_CSC_LINK: ${{ secrets.WIN_CSC_LINK }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }}
# Auto-discovery ON only when a Windows Authenticode cert is provided.
CSC_IDENTITY_AUTO_DISCOVERY: ${{ secrets.WIN_CSC_LINK != '' }}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the right split. windows-nsis no longer receives secrets.CSC_LINK, so an Apple Developer ID .p12 cannot Authenticode-sign the NSIS installer. Empty WIN_CSC_* still hits the unset CSC_LINK branch (GitHub expands a missing secret to ""), so the first artifacts stay unsigned and SmartScreen remains the documented path. Do not invent or commit a cert.

One ops note, not a code blocker: the Windows job will stay unsigned until WIN_CSC_LINK / WIN_CSC_KEY_PASSWORD exist in repo secrets. That's intended.

Capture the three-screen Windows first-run privacy gate via
BUDGETR_PRIVACY_GATE_FORCE local web preview (not a packaged .exe).

Co-authored-by: Kevin George <kGeee@users.noreply.github.com>
@kGeee

kGeee commented Sep 4, 2026

Copy link
Copy Markdown
Owner Author

Privacy gate screenshots (forced local web preview)

These are not shots of a packaged Windows .exe / NSIS installer — this Linux cloud VM cannot build or run that. They are the real three-screen privacy gate UI from this PR, rendered via the forced local Next.js preview:

BUDGETR_DESKTOP=1 \
BUDGETR_USER_DATA=/tmp/budgetr-privacy-preview-userdata \
BUDGETR_PRIVACY_GATE_FORCE=1 \
BUDGETR_LICENSE_DISABLED=1 \
PORT=3010 npm run dev

/overview redirects to /desktop-setup until all three screens + acks complete. Screen 3’s resolved path shows the Linux preview userData (/tmp/...); the marketing copy still uses %APPDATA%\budgetr\ as on Windows.

Screen 1 — Your ledger stays on this PC.

35-privacy-1

Screen 2 — What this app is allowed to do.

35-privacy-2

Screen 3 — This is the folder.

35-privacy-3

Committed on branch tip 2aabf97 under .pr-screenshots/.
PR remains draft (no merge).

@kGeee kGeee left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: COMMENT (hold merge) — head 2aabf97

Screenshot gate PASS for the three-screen privacy gate UI. Tip is docs-only (no code delta since e4fe228). Still a draft, so this is not an approve. Do not merge. PR Merger stay off until undraft.

What landed (2aabf97)

  • Three forced local Next.js preview shots committed under .pr-screenshots/ and attached on the PR:
    1. Your ledger stays on this PC. (ack + Continue + “Where the file will live”)
    2. What this app is allowed to do. (ack + Allow and continue + “Not now (exit setup)”)
    3. This is the folder. (%APPDATA%\budgetr\ / budgetr.db / budgetr.env copy + Open data folder / Continue into the app)
  • Correctly disclosed as not a packaged Windows .exe / NSIS run. Screen 3’s resolved path showing /tmp/budgetr-privacy-preview-userdata is expected for BUDGETR_PRIVACY_GATE_FORCE on Linux preview; marketing copy still uses %APPDATA%\budgetr\.
  • Copy matches the Marketing Chief three-screen lock (ledger local, BYO Plaid / providers only, read-only). No /privacy or placeholder legal URLs in the shots.

Carry-forward from e4fe228 (still pass)

  1. NSIS x64 per-user, no UAC, asar: false
  2. Packaged-Windows-only privacy gate; marketing / npm run dev / start.bat not blocked
  3. Signing split: windows-nsis uses WIN_CSC_* only (Mac CSC_LINK out of that job)
  4. Job fails if budgetr-win.exe missing; OCR extraResources Mac-only
  5. SmartScreen called out in README
  6. No secrets in tip (PNGs only); prior secret names only in workflow

Checks

  • web green
  • Vercel Preview Comments green

Soft (non-blocking)

  • Dev “N” badge in the corner is from the forced web preview, not a packaged-Windows chrome claim.

Remaining blockers (non-code)

  • Still a draft (no APPROVE / no merge)
  • First v* / Windows install proof (Not now quits, Open data folder, relaunch skips gate, no OCR on the Windows artifact)
  • WIN_CSC_* only when a real Authenticode cert exists

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants