Skip to content

feat(auth): desktop auth mode, access gate and admin config file - #708

Open
robspan wants to merge 1 commit into
refactor/platform-jwt-sharedfrom
feat/desktop-auth-gate
Open

robspan wants to merge 1 commit into
refactor/platform-jwt-sharedfrom
feat/desktop-auth-gate

Conversation

@robspan

@robspan robspan commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Second of three PRs for the desktop platform sign-in (#295). Based on #707 (the platform-jwt move); until that merges, only the last commit is this PR. Next: #709.

What

An administrator's config file switches VarLens Desktop into platform sign-in. Without the file nothing is installed: the access gate keeps a pass-through provider and every channel answers as on main. What remains on the default path is an lstat of the config paths at startup and one auth:desktopStatus call while the renderer boots.

With the file, this PR brings the locked half of the feature; signing in comes with the next PR, so until then a configured desktop stays locked.

  • Access gate (src/main/auth/access-gate.ts): every IPC registration goes through it. In platform mode every channel except system:capabilities, system:version and auth:desktopStatus answers UNAUTHENTICATED until somebody signs in, without its handler running. The local accounts' channels are refused (FORBIDDEN), as on the web under platform sign-in. jobs and debug register through the gate too, still without the database startup wait.
  • Admin config file (src/main/auth/desktop-auth-config*.ts, windows-acl.ts): auth.json in a machine-wide folder only administrators can change (/etc/varlens, /Library/Application Support/VarLens, C:\ProgramData\VarLens). Owner and permission checks; on Windows the security descriptor and the content come from one open handle. Only a missing file means no sign-in; a file that cannot be checked, trusted or parsed keeps the desktop locked and says why.
  • Startup: in platform mode the default database is not opened, and the renderer mounts a sign-in screen instead of the app.

Existing files touched

Everything else is in new modules (src/main/auth/, src/main/ipc/handlers/desktop-auth.ts, the renderer's desktopAuthStore, SignInApp.vue, components/auth/).

File Lines Why
src/main/index.ts +7/−1 read the config file before IPC registers; in platform mode create the manager without opening the default database
src/main/ipc/index.ts +6/−5 register through createIpcRegistrars: data domains on startup gate + access gate, jobs and debug on the access gate only
src/main/ipc/domains/{jobs,debug}.ts +2/−2 each ipcMain as a parameter, defaulting to Electron's, so they can register through the gate; their tests stay unchanged
src/main/ipc/domains/auth.ts +3 registers the auth:desktop* channels (they are auth channels)
src/renderer/src/main.ts +13 mount SignInApp instead of the app while sign-in is required
shared contract, preload, capability-features.ts, parity manifest, mocks +18/−5 the new desktop-only auth:desktopStatus method (desktopSignIn capability)
tests/shared/types/preload-contract.test.ts +1/−1 it pins registerJobsHandlers() literally

Verification

Against main at 779a6d25, macOS arm64, Node 24.15.0, Electron 43, windows hidden:

  • Vitest (main and renderer), compared test by test with main: no test changes status; 66 new tests pass.
  • out/ hashed file by file: in out/main only index.js carries changed code (8 shared chunks are only renamed); out/preload has the new method; in out/renderer SignInApp and VContainer are new lazy chunks, and the other chunks differ only in the minified aliases of names they import from the shared index chunk.
  • E2E: startup smoke, the four interaction gates, and the new desktop-sign-in.e2e.ts (sign-in screen, refused data and local login, no varlens.db created before sign-in, a broken config file shows its problem): pass.
  • make lint-check, format-check, typecheck, agent-check pass; make web-gate-static: 1131 passed, 1 expected failure, as on main.

Key tests: tests/main/ipc/ipc-access.test.ts registers the real registerIpcHandlers and checks that every one of its channels is refused while locked except the allowlist, and that only jobs/debug answer before the database opens, as on main. tests/main/ipc/registrars.test.ts compares the new registration with main's over generated channels, arguments, results and errors.

Spec: .planning/specs/2026-10-24-desktop-platform-sign-in.md (design, all seams, PR plan, accepted limits).

An administrator's config file switches VarLens Desktop into platform
sign-in (#295). Without the file nothing is installed: the gate keeps a
pass-through provider and every channel answers as before.

- Access gate: in platform mode every IPC channel except
  system:capabilities, system:version and auth:desktopStatus answers
  UNAUTHENTICATED until somebody signs in, without its handler running.
  The local accounts' channels are refused in platform mode, as on the
  web under platform sign-in. jobs and debug register through the gate
  too and still answer without the database startup wait.
- Config file: auth.json in a machine-wide folder only administrators can
  change (owner and permission checks; on Windows the security descriptor
  and the content come from one open handle). Only a missing file means
  no sign-in; anything that cannot be checked, trusted or parsed keeps the
  desktop locked and says why.
- Startup opens no database in platform mode, and the renderer mounts the
  sign-in screen instead of the app.

Signing in comes with the next change; until then a configured desktop
stays locked.

Spec: .planning/specs/2026-10-24-desktop-platform-sign-in.md

This branch has not been deployed

No deployments
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.

1 participant