Files

174 lines
16 KiB
Markdown

# Error log (ERRORS.md)
Every error hit while building/releasing RemminaMac — cause, fix, status. Updated with every build.
As of 2026-09-22 · version 0.7.0 · macOS arm64 · Swift 5.9+ · Xcode 15+
## Overview
| # | Date | Phase | Error | Severity | Status |
|---|------|-------|-------|----------|--------|
| 1 | 2026-09-21 | `swift build` (debug) | `WindowGroup<some View> has no member 'windowTitle'` | blocking | ✅ fixed |
| 2 | 2026-09-21 | `swift build -c release` | no errors, just slow first link (~40 s) | info | ✅ ok |
| 3 | 2026-09-21 | release script | `dist/` missing from `.gitignore` → binary almost committed | medium | ✅ fixed (ignored) |
| 4 | 2026-09-21 | Gitea upload | `GET /api/v1/user` → `401` with old credentials | blocking | ✅ fixed — new credentials, push + v0.1.0 live |
| 5 | 2026-09-21 | app bundle + DMG | no errors: signing ok, UDZO DMG, mount verified | info | ✅ ok |
| 6 | 2026-09-21 | SSH connect | no terminal opened: `NSAppleScript` failed silently (no AppleEvents permission/handling) | blocking | ✅ fixed — in-app PTY terminal (Dracula) + `.command` fallback |
| 7 | 2026-09-21 | ANSI parser (test) | `feed()` flushed chunk AFTER `parseCSI` → wrong style | medium | ✅ fixed — flush before style switch |
| 8 | 2026-09-21 | SSH session dies instantly, no message | stderr shared the PTY: macOS drops unread master data on slave close → bare "code 255" | blocking | ✅ fixed — stderr→pipe, TCP pre-check, error banner |
| 9 | 2026-09-21 | `swift build` | `Result<Void, String>`: String is not Error (follow-on DispatchQueue errors) | blocking | ✅ fixed — completion as `(String?) -> Void` |
| 10 | 2026-09-21 | icon generator (`RenderIcon.swift`) | 3 Swift errors: non-optional `guard let`, `Int * CGFloat`, wrong preview path | small | ✅ fixed |
| 11 | 2026-09-21 | password feature | request: store passwords + keys AND use them (stored but never used) | feature | ✅ done — sshpass auto-login, else interactive |
| 12 | 2026-09-21 | "always connection wrong" | user report without details | open | ⬜ partly: editor validation + copyable error report |
| 13 | 2026-09-21 | Permission denied with correct password | text substitution in input field mangled special chars | high | ✅ fixed — hardened input field (all substitutions off, 9/9) |
| 14 | 2026-09-21 | Terminal works, app doesn't (same password) | SSH agent socket missing for GUI processes → maybe key login in Terminal | high | ✅ app forwards agent socket; user confirmation open |
| 15 | 2026-09-21 | crash on type + send | cause unclear (not reproducible headless) | critical | ⬜ hardened (v0.5.3); crash log requested |
| 16 | 2026-09-22 | profile edits had no effect | session cache ignored host/password/key corrections | high | ✅ fixed — fingerprint reconfig (9/9) |
| 17 | 2026-09-22 | rzsv: pre-check timeout | port 22 dropped server-side (443 ok) — not an app bug | external | ⬜ server side: fail2ban/VPN/firewall |
| 18 | 2026-09-22 | host-key yes/no impossible | ssh without controlling terminal: /dev/tty ENXIO → silent abort | critical | ✅ ctty-run helper (double-fork) + fingerprint popup |
| 19 | 2026-09-22 | empty popup (see screenshot) | `if let` in sheet takes empty branch with no update path | medium | ✅ `.sheet(item:)` + background keyscan |
| 20 | 2026-09-22 | terminal not fully interactive | single-line input, no completion, no vim | feature | ✅ done — SwiftTerm emulator (0.7.0) |
| 21 | 2026-09-22 | yes-asked-twice + password ignored | popup-accept race; sshpass installs went stale | medium | ✅ verified no re-ask; sshpass in fingerprint |
---
## Template for new errors
```markdown
## #N — Title
**Phase:** ...
**Log:** ...
**Cause:** ...
**Fix:** ...
**Verified:** ...
**Status:** ⬜ open / ✅ fixed
```
## How errors get here
- Every `swift build` / `swift build -c release` / script run with an error → log excerpt + exit code goes here.
- Gitea push/release errors likewise.
- New tests: `AnsiParser` via `swiftc` harness, `PTYSession` smoke tests, Keychain roundtrips, TCP checks, host-key flow vs local paramiko server, SwiftTerm core headless.
## #1 — `windowTitle` doesn't exist on `WindowGroup`
**Phase:** first `swift build`
**Log:**
```
RemminaMacApp.swift:14:10: error: value of type 'WindowGroup<some View>' has no member 'windowTitle'
```
**Cause:** `windowTitle(_:)` is not a `WindowGroup` modifier; the title goes in the `WindowGroup` init.
**Fix:** `WindowGroup("RemminaMac") { ... }`.
**Status:** ✅ fixed.
## #2 — Slow but clean release build
**Phase:** `bash scripts/build-release.sh 0.1.0` → `swift build -c release` (~40 s first link).
**Cause:** none — release optimization + link just take a while cold; faster on rebuilds (`.build/` cache).
**Status:** ✅ ok.
## #3 — `dist/` almost committed
**Cause:** `dist/` held ZIP + unpacked binary, `.gitignore` didn't know it.
**Fix:** ignore `.build/`, `dist/`, `*.zip`, `*.sha256`.
**Status:** ✅ fixed.
## #4 — Gitea upload: 401 despite reachable server
**Phase:** `POST /api/v1/user/repos` + `GET /api/v1/user` on `https://git.sysdaemon.xyz` (v1.27.3 confirmed via `/api/v1/version`).
**Log:** `GET /user -> 401 {"message":"invalid username, password or token"}` — tried logins `x3` and `x3@sysdaemon.xyz`, both 401 (Basic auth via Python, no shell-quoting issue).
**Fix:** with corrected credentials: `GET /api/v1/user → 200 (login x3)`, repo `x3/remmina-mac` created (201), push ok, release `v0.1.0` + assets uploaded.
**Status:** ✅ fixed.
## #6 — SSH click opens no terminal (user bug report)
**Cause:** `SSHService.openInTerminal` used `NSAppleScript(tell application "Terminal" …)` — fails silently without `NSAppleEventsUsageDescription` and with no error handling.
**Fix:** `Services/PTYSession.swift` (real PTY via `posix_openpt`), `Views/EmbeddedTerminalView.swift` (in-app Dracula terminal, auto-connect), external fallback via `.command` file + `NSWorkspace` (no automation rights needed).
**Verified:** build ok; parser 8/8; PTY smoke (`/bin/echo` → output + exit 0); `ssh -G` through PTY ok.
**Status:** ✅ fixed.
## #7 — ANSI parser: text got the wrong style
**Phase:** `swiftc` harness during #6. Log: `text("rot", fg: nil)` instead of `fg: 1`.
**Cause:** chunk flushed only after the SGR switch.
**Fix:** `flush()` before `parseCSI`. Harness 8/8 green.
**Status:** ✅ fixed.
## #8 — Terminal connects then dies instantly, no message (user bug report)
**Repro (harness, exact app path `ssh -p 1 nobody@127.0.0.1`):** exit 255, output shows only the session note — ssh's error lost.
**Ground truth (Python pty):** even `/bin/echo hello` yields `b''` when read only AFTER child exit; reading promptly yields `b'hello-py\r\n'` → macOS drops unread PTY master data on slave close (then EIO). Our `DispatchSourceRead` loses that race for instant-exit children — and ssh writes everything (incl. "Connection refused") to stderr, which shared the PTY.
**Fix:** stderr → `Pipe` (buffered data survives child exit), stdin/stdout stay on PTY; non-blocking `finalFlush` + epoch-guarded lifecycle; TCP pre-check (Network.framework, 4 s) with plain-language messages; red error banner + Diagnose/Retry buttons.
**Verified:** refused harness now shows the error (PASS); `cat` roundtrip, `ssh -G`, TCP harness (closed/open/empty) PASS.
**Status:** ✅ fixed.
## #9 — Build: `Result<Void, String>` invalid
**Log:** `error: type 'String' does not conform to protocol 'Error'` (+ follow-on errors).
**Fix:** `TCPCheck.check` uses `(String?) -> Void` (nil = ok, else message).
**Status:** ✅ fixed.
## #10 — Icon generator build errors
**Log:** non-optional `guard let` (`??` already unwraps); `Int * CGFloat`; preview landed in `.iconset/` instead of `/tmp/`.
**Fix:** assign `??` fallback directly; `CGFloat(...)`; path corrected.
**Status:** ✅ fixed. Icon: `Resources/AppIcon.icns` (reproducible via `scripts/generate-icon.sh`), preview `docs/icon-preview.png`.
## #11 — Store AND use passwords (user request)
**State:** passwords/passphrases were stored in Keychain but never used for login (ssh always asked interactively).
**Done:** `SSHService.loginSecret()` (profile password → key passphrase), pure/testable `sessionConfig()`: with secret + sshpass → `sshpass -e ssh/sftp …` + `SSHPASS` env (never command line/logs); otherwise direct call + interactive prompt. `PTYSession.customEnv` + auto-login flag; status shows auto-login state. Editor: saved indicator (✓), delete button, sshpass hint.
**Verified:** config harness 9/9 (incl. "password never on command line"); real Keychain roundtrip 7/7.
**Note:** without `sshpass` (`brew install sshpass`) the interactive prompt remains.
**Status:** ✅ done.
## #12 — "Always connection wrong" (user report, details open)
**State:** reported without target host, banner text or credentials — not reproducible remotely.
**Checklist:** `user@host` in host field or `ssh://` prefix → live editor warnings now; whitespace trimmed; wrong password / missing key → banner + Diagnose; server blocks (fail2ban, key-only) → check server logs.
**Done:** `Models/ProfileValidation.swift` (7/7), password right below username, "Copy report" in banner (no secrets).
**Status:** ⬜ waiting for error report.
## #13 — Permission denied with correct password (user error report)
**Report:** `administrator@sysdaemon.xyz:22`, ssh asks 3x → `Permission denied (publickey,password)`. Same password works in Terminal.app.
**Cause:** the terminal input was a stock TextField — macOS silently substitutes characters (`"` → “”, `--` → —, autocorrect). A password with special chars arrives mangled; Terminal shows nothing wrong, ssh just denies. Verified: stock `NSTextField` has these switches on, and can't even disable dash substitution (compiler proof).
**Fix (`Views/TerminalInputField.swift`, later superseded by SwiftTerm):** NSTextView-based field with all substitutions explicitly off; Secure variant via `NSSecureTextField`; Enter → send, paste normalization.
**Verified:** harness 9/9 (all flags off).
**Status:** ✅ fixed — retest with v0.5.1+.
## #14 — Terminal.app logs in, RemminaMac doesn't (same password)
**User answers:** v0.5.1 installed, password login, Terminal.app works with the same data.
**Analysis:** app side fully verified → difference must be environmental. Main suspect: **SSH agent** — Finder-launched GUI processes don't inherit `SSH_AUTH_SOCK`. If Terminal silently uses an agent key (not the password), the app fails with the password. Verified: `launchctl getenv SSH_AUTH_SOCK` returns the socket.
**Fix:** `SSHService.agentSocket()` → `TerminalManager` injects `SSH_AUTH_SOCK` into the ssh env (coexists with SSHPASS).
**Verified:** harness 4/4. User confirmation check: `ssh-add -l` + `ssh -o IdentitiesOnly=yes administrator@sysdaemon.xyz`.
**Status:** ✅ app side done — waiting for confirmation.
## #15 — Crash on type + send (user report)
**State:** "crashes as soon as I type and send." Not reproducible headless — every layer green alone.
**Ruled out by test:** SIGPIPE on write (macOS returns EIO, no signal; send-after-stop survives); view layer (real coordinator + NSTextView: umlauts/quotes/paste/Enter, 200 programmatic sets); PTY roundtrip, refused, Keychain, TCP harnesses.
**Hardened (v0.5.3, unproven as THE crash):** detach delegate during programmatic sets (no state mutation mid-render); safe pointer in `send()`.
**Still needed if it recurs:** Console.app → Crash Reports → newest `RemminaMac` entry → `Exception Type`, `Termination Reason`, crashed thread.
**Status:** ⬜ waiting for feedback / crash log.
## #16 — Profile edits had no effect ("still doesn't work")
**State:** user kept reporting failure after fixes. Code review (`TerminalManager.session`): a once-created session was reused forever — host/password/key corrections never reached it.
**Fix:** config fingerprint (proto/host/port/user/extraArgs/key path/secret value) per session; on mismatch with a non-running session: stop + reconfigure (same object, tabs stay). Running sessions are never reconfigured underfoot (disconnect first).
**Verified:** harness 9/9.
**Status:** ✅ fixed — retest with v0.5.4 (re-save profile once).
## #17 — rzsv: pre-check timeout (not an app bug, screenshot proof)
**Picture:** tab rzsv (`administrator@sysdaemon.xyz:22`), banner "pre-check: no answer in 4 s", ssh correctly NOT started.
**Measured (same machine):** `sysdaemon.xyz` → `185.117.250.190`; port 443 ok in 0.02 s, port 22 dropped (timeout, no refused). Server reachable, SSH port dropped from this network. No client can connect from here — the pre-check was right.
**Likely causes:** fail2ban ban after the many denied attempts (`fail2ban-client status sshd` → unban); VPN on/off mismatch; firewall allows 22 only from certain networks.
**Update from user:** port 22 is blocked on the company network; hotspot works. Confirmed.
**Status:** ⬜ server/network side.
## #18 — Host-key yes/no impossible (user screenshot: Terminal works, app only says "Host key verification failed.")
**Analysis:** Terminal shows the `Are you sure...?` prompt (with fingerprint), app aborts without prompt. Proof via `-v`: `read_passphrase: can't open /dev/tty: Device not configured` — ssh prompts need a controlling terminal; our PTY slave wasn't one (GUI app has none, child inherits none). Affects password AND yes/no prompts.
**Fix:** `Sources/ctty-run/ctty-run.c` (C helper, SPM target): double-fork (needed because Apple's Process starts children in their own process group → direct setsid = EPERM) → setsid → slave open (= ctty) → exec ssh. stderr stays on the parent pipe (loss-free). `stop()` kills the process group (no orphans, verified). Plus `Views/HostKeySheet.swift` flow: `ssh-keyscan` fingerprint upfront → popup (SHA256/MD5, type) → accept (→ shared `~/.ssh/known_hosts`) / decline; red MITM warning + `ssh-keygen -R` path on changed keys.
**Verified (local paramiko server):** bug reproduced (no prompt, exit 255) → after fix: ctty proven via `ps` (ttys001), yes/no visible + answerable, password accepted, shell active. HostKeyService: unknown/accept/known/changed/revoke/unreachable green.
**Status:** ✅ fixed (v0.6.0).
## #19 — Fingerprint popup appears empty (user screenshot)
**Picture:** sheet window present but tiny and contentless; status stuck on "checking …".
**Cause:** `.sheet(isPresented:)` + `if let info` content: if evaluation takes the empty branch at presentation time, the empty branch has no dependency on the state var → the sheet never updates, stays empty. Classic SwiftUI trap.
**Fix:** `.sheet(item: $hostKeyRequest)` with `HostKeyRequest: Identifiable` — content structurally always exists. Plus `HostKeyService.status` (blocking keyscan) moved to a background queue — the UI used to freeze during "checking …".
**Status:** ✅ fixed (v0.6.1).
## #20 — Terminal not fully interactive (user request)
**State:** single-line input row, no Tab completion, no vim/full-screen apps.
**Done (0.7.0):** SwiftTerm emulator (v1.20.0 SPM dep) as `Views/SwiftTermView.swift`: cursor addressing, colors, scrollback, selection, direct keyboard (completion, arrows, Ctrl+C, Esc), vim/htop. Dracula palette via `installColors` + native fg/bg. PTY layer feeds raw bytes (`onData`); keystrokes go straight to the pty master (`sendBytes`); resizes propagate via `TIOCSWINSZ` (`setWinsize`). Old input row + `TerminalInputField.swift` removed (SwiftTerm handles keys natively, immune to macOS substitutions).
**Verified:** headless emulator core 6/6 (text, absolute cursor addressing, alt-screen on/off, clear, 16-color palette); app-path login + shell still green.
**Status:** ✅ done.
## #21 — Asked for yes twice + password ignored (user reports)
**Analysis:** (a) empty-popup era (#19) forced ssh's own yes/no prompt — fixed by the popup fix; verified no re-ask after popup accept (harness asserts no "Are you sure" post-accept). (b) `sshpass` installs went stale: the session fingerprint didn't include sshpass presence, so installing sshpass later never switched to auto-login. Fixed by including it in `TerminalManager.configTag` (now `nonisolated` pure function).
**Verified:** no-ask + login green; tag changes on sshpass variance.
**Status:** ✅ fixed.