Files

202 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Two Auth Modes Implementation Plan
**Intent:** Схлопнуть Lemana VPN до двух понятных пользовательских режимов: ручной вход с сохранёнными LDAP login/password в macOS Keychain и старый личный automatic path через Bitwarden + Touch ID + полный autofill/submit.
**Current Behavior:** Checkout уже manual-first, но публичный контракт всё ещё размазан по `manual`, `saved-login`, `saved-totp`, `auto`, совместимым alias-командам и status/menu `available_modes`. Локально установленный `~/bin/vpn-lemanapro.sh` отстаёт от checkout, поэтому старые сборки и приложение могут видеть другую схему.
**Expected Outcome:** Installer, CLI, app menu, README и smoke tests показывают ровно два режима: `manual-keychain` и `bitwarden-auto`. Первый хранит только LDAP username/password в Keychain и всегда оставляет OTP ручным. Второй сохраняет старую рабочую конфигурацию с Bitwarden, Touch ID, permanent 2FA secret, hidden browser, autofill и submit.
**Target-Perspective Output:** Пользователь переустанавливает пакет, выбирает один из двух режимов, видит тот же выбор в `vpn --status` и в LemanaVPN.app. В ручном режиме он может подключиться с подстановкой логина/пароля, каждый раз вводит OTP руками и может обновить логин/пароль из меню. В Bitwarden-режиме работает прежний автоматический путь.
**Truth Owner:** Два repo profile-template файла владеют режимами; `install.sh` выбирает один профиль и пишет активный `~/.config/lemana-vpn/env`; `bin/vpn-lemanapro.sh` исполняет режим; Swift app только читает CLI JSON и запускает CLI.
**Contract Boundary:** Public contract: mode id `manual-keychain|bitwarden-auto`, CLI flags/status JSON/app menu labels. Internal compatibility may still map old flags to a mode, but UI/docs/installer no longer expose four profiles as first-class choices.
**Cutover:** Fresh install defaults to `manual-keychain` and offers `bitwarden-auto` as the old personal advanced mode. Existing env files with `manual`, `saved-login`, `saved-totp`, or `auto` are migrated or normalized to one of the two public modes during install/status.
**Displaced Path:** Displace public `manual`, `saved-login`, `saved-totp`, and `auto` profile matrix. Keep only minimal compatibility aliases where needed, and make them resolve to one of the two modes.
**Value Density:** The smallest high-value slice removes mode ambiguity and stale install drift while preserving the two flows the user actually needs.
**Acceptance Evidence:** Clean temp HOME install output shows only two modes. Source and installed `vpn --status --json` agree on mode/status JSON. Fake launch captures prove manual-keychain uses visible browser, login/password autofill, no TOTP autofill, no submit; bitwarden-auto uses Bitwarden sync, Touch ID when enabled, hidden browser, TOTP autofill, submit. Installed CLI shasum matches checkout and installed app binary contains the updated menu strings.
**Evidence Lane:** Non-live first: shell syntax, smoke tests, Swift build, `git diff --check`, source/installed status JSON and installed binary string checks. Live VPN check only after `vpn --status`, starting with manual-keychain visible flow; skip if connected/connecting unless explicitly approved.
**Kill Criteria:** No installer prompt, README section, app menu, or `available_modes` JSON may present more than two public modes. No fresh install may require Bitwarden. No manual-keychain path may save or require TOTP seed. No bitwarden-auto path may silently degrade into half-configured Keychain-only auto.
**Architecture Slice:** `install.sh`, `bin/vpn-lemanapro.sh`, two new profile-template files, Swift app menu contract, README, smoke tests, installed-path refresh checks.
**Plan Review Gate:** PRE self-review done against Krypton reviewer checklist; external subagent review not run because subagents require an explicit user request in this environment.
## Короткий План
🎯 Цель: оставить ровно два рабочих режима установки и подключения: ручной с Keychain login/password + ручной OTP, и старый Bitwarden/Touch ID automatic flow.
📦 Репозитории: только `/Users/dokril/git/home/lemana-vpn`.
🧩 Модули: `install.sh`, `bin/vpn-lemanapro.sh`, `app/Sources/LemanaVPN`, `templates/`, `tests/smoke.sh`, `README.md`; installed refresh checks для `~/bin/vpn-lemanapro.sh` и `~/Applications/LemanaVPN.app`.
🛠 Основные изменения:
- Создать два profile-template файла в `templates/`: `manual-keychain.env` и `bitwarden-auto.env`.
- Перевести installer на выбор только этих двух режимов; убрать публичные вопросы про `saved-login/saved-totp/auto`.
- В CLI ввести public mode `LEMANA_VPN_MODE=manual-keychain|bitwarden-auto` и нормализовать старые env/flags в один из двух режимов.
- Сделать app menu и status JSON двухрежимными: `Подключить`, `Подключить старым автоматическим способом`, `Изменить логин и пароль`.
- Оставить старые flags/aliases только как compatibility shims, без отдельного третьего режима в UI/docs.
- Переписать smoke tests под два режима и добавить installed-path evidence: `shasum`, `strings`, `vpn --status --json`.
- Сжать README до двух сценариев установки и восстановления.
✅ Проверка: `sh -n install.sh`, `sh -n uninstall.sh`, `bash -n bin/vpn-lemanapro.sh`, `sh -n tests/smoke.sh`, `tests/smoke.sh`, `swift build -c release --package-path app`, `git diff --check`, затем installed checks после `sh install.sh`.
⚠️ Риски: старые env с `saved-totp`/`auto` могут мигрировать не туда; installed CLI/app могут снова отставать; live auto-flow зависит от Bitwarden/Touch ID и permanent 2FA secret.
➡️ Следующий шаг: начать с mode contract и двух template-файлов, затем подключить installer/runtime normalization.
## Architecture Slice
Files to create:
- `templates/manual-keychain.env` - source profile for the normal manual mode.
- `templates/bitwarden-auto.env` - source profile for the old personal automatic mode.
Files to modify:
- `install.sh` - two-mode wizard, env rendering from templates, migration from old flags/env, final next steps.
- `bin/vpn-lemanapro.sh` - public mode parser, compatibility mapping, status JSON, app menu JSON, runtime env for autofill/click/TOTP.
- `app/Sources/LemanaVPN/VPNManager.swift` - two launch modes, menu labels, status decoding if JSON shape changes.
- `app/Sources/LemanaVPN/LemanaVPNApp.swift` - remove multi-mode rendering that exposes old profiles; keep credential edit action.
- `tests/smoke.sh` - replace four-profile assertions with two-mode assertions plus compatibility tests.
- `README.md` - rewrite mode docs around two supported configurations.
- `docs/goals/manual-first-auth-flow/*` - mark superseded or point to this plan to avoid executing the older four-profile plan.
Files to avoid:
- `libexec/lemana-vpn-dns-cleanup` - unrelated to auth mode split.
- `templates/openconnect-lite-config.toml` unless fake launch evidence shows separate openconnect-lite configs are necessary.
- Direct installed `openconnect-lite` source edits; keep using the existing runtime patch path.
Source of truth:
- Repo templates define the two modes.
- Active install writes exactly one selected mode into `~/.config/lemana-vpn/env`.
- Keychain stores LDAP password for `manual-keychain`; Bitwarden remains the upstream source for `bitwarden-auto` and syncs into Keychain at runtime.
Read path:
- `install.sh` reads selected mode and profile template, writes env.
- `bin/vpn-lemanapro.sh` reads env, normalizes legacy fields, checks required credentials for the selected mode, emits JSON/status, launches `openconnect-lite`.
- Swift app reads only `vpn --status --json` and passes a CLI argument for the chosen mode.
Write path:
- `vpn --configure-login` writes or updates username/password only for `manual-keychain`.
- Bitwarden path reads item `LM LDAP`, unlocks through Touch ID/manual master password, then writes password and normalized permanent TOTP secret into Keychain for `bitwarden-auto`.
- Installer never writes the current 6-digit OTP.
Contract boundary:
- Public mode ids: `manual-keychain`, `bitwarden-auto`.
- Public status JSON should expose `mode.id`, `mode.label`, `mode.ready`, `mode.setup_hint`, and a maximum of two user actions.
- Compatibility inputs allowed: `--saved-login`, `--manual-full`, `--manual`, `--auto`, old `LEMANA_VPN_AUTH_PROFILE`, old `LEMANA_VPN_CREDENTIAL_SOURCE`.
Integration points:
- macOS Keychain service `openconnect-lite`.
- Optional Bitwarden CLI item `LM LDAP`.
- Optional Touch ID helper `~/bin/keychain-fingerprint`.
- `templates/openconnect-lite-config.toml` and runtime autofill patches.
- Swift app JSON contract and installed app binary refresh.
Migration/cutover:
- `saved-login` -> `manual-keychain`.
- `manual`/`manual-full` -> `manual-keychain`, but if no saved password exists, status shows setup hint and connection can still offer full manual fallback as diagnostic.
- `saved-totp`/`auto` + `credential_source=bitwarden` -> `bitwarden-auto`.
- `saved-totp`/`auto` + `credential_source=keychain` is no longer a public mode; installer should ask to switch to either `manual-keychain` or `bitwarden-auto`, or keep a hidden compatibility shim for one release with a warning.
Displaced path:
- The old four-profile matrix.
- App `available_modes` rendering multiple profile buttons.
- README/installer wording that teaches `saved-login`, `saved-totp`, and `auto` as equal modes.
Acceptance evidence gate:
- Fresh install dry-run contains only the two human mode names.
- `tests/smoke.sh` proves both launch profiles and legacy compatibility.
- `~/bin/vpn-lemanapro.sh --status --json` matches source behavior after `sh install.sh`.
- `strings ~/Applications/LemanaVPN.app/Contents/MacOS/LemanaVPN` proves updated menu labels are installed.
## Tasks
### Task 1 - Define Two Mode Templates
Scope: create `templates/manual-keychain.env` and `templates/bitwarden-auto.env`; add a tiny renderer/loader in `install.sh`.
Expected output: the selected profile writes one active public mode and its derived legacy compatibility vars.
Verification: `sh install.sh --dry-run --non-interactive --mode manual-keychain` and `--mode bitwarden-auto` show the correct env writes without exposing old profile names.
Acceptance evidence: dry-run output and rendered temp env contents.
Parallel: no; this is the source-of-truth base.
### Task 2 - Normalize Runtime Modes
Scope: update `bin/vpn-lemanapro.sh` to parse `LEMANA_VPN_MODE`, map old env/flags to the two public modes, and derive autofill/TOTP/submit settings.
Expected output: manual-keychain uses visible browser, password autofill, TOTP off, submit off; bitwarden-auto uses Bitwarden sync, TOTP on, hidden browser, submit on.
Verification: fake `openconnect-lite` capture in `tests/smoke.sh`; `bash -n bin/vpn-lemanapro.sh`.
Acceptance evidence: JSON events and capture files for both modes.
Parallel: after Task 1 only.
### Task 3 - Simplify Installer And CLI UX
Scope: installer questions, flags, usage, aliases, final next steps, and legacy migration warning.
Expected output: installer asks one question with two choices, configures login/password for manual-keychain, and reserves Bitwarden/Touch ID setup for bitwarden-auto.
Verification: expect-based interactive smoke and dry-run smoke.
Acceptance evidence: captured installer transcript with no public `saved-login/saved-totp/auto` wording.
Parallel: can run after Task 1 while Task 2 is in progress, but integration proof must wait.
### Task 4 - Update Swift Menu Contract
Scope: `VPNManager.swift` and `LemanaVPNApp.swift`.
Expected output: disconnected menu is two-mode aware and does not render old profile buttons. Credential edit remains a Terminal launcher for `vpn --configure-login`.
Verification: Swift source smoke, `swift build -c release --package-path app`, installed binary `strings` after install.
Acceptance evidence: menu string checks and build output.
Parallel: can run after Task 2 JSON shape is decided.
### Task 5 - Rewrite Docs And Supersede Old Plan
Scope: `README.md`, `docs/goals/manual-first-auth-flow/PLAN.md`, `docs/goals/manual-first-auth-flow/GOAL.md`.
Expected output: docs teach only two modes and point the older four-profile plan to this plan.
Verification: `rg -n "saved-totp|auth_profile=|credential_source=|four-profile|manual-full" README.md docs/goals`.
Acceptance evidence: only compatibility sections mention old names.
Parallel: can run after Tasks 1-3 settle final names.
### Task 6 - Final Verification And Installed Refresh
Scope: run non-live ladder, install locally, compare installed CLI/app, and optionally perform a live manual check if status is safe.
Expected output: checkout and installed paths agree; user can run the chosen mode from Terminal and app.
Verification: `sh -n install.sh`, `sh -n uninstall.sh`, `bash -n bin/vpn-lemanapro.sh`, `sh -n tests/smoke.sh`, `tests/smoke.sh`, `swift build -c release --package-path app`, `git diff --check`, `sh install.sh`, `vpn --status --json`, `shasum bin/vpn-lemanapro.sh ~/bin/vpn-lemanapro.sh`, installed app `strings`.
Acceptance evidence: command outputs plus a note if live VPN was skipped because status was connected/connecting.
Parallel: no; final integration gate.
## PRE Self-Review
Mode: PRE
Verdict: aligned
Findings:
- minor: "two files" could mean runtime shell modules rather than env templates. Smallest correction: execution should confirm with the user before choosing a different file split, but the current plan makes templates the truth owner because the stated pain is reinstall/config drift.
- minor: legacy `saved-totp` + keychain-only users are not part of the requested two modes. Smallest correction: keep one-release compatibility warning or migration prompt rather than deleting the path blindly.
Recommended next gate: execute Task 1 and Task 2 together as the contract slice, then run smoke before touching Swift/docs.