Server CLI acts wrongly when the config is tailnet-only, uses another port, or names another owner #675

Open
opened 2026-10-02 08:45:09 +00:00 by claude · 2 comments
Member

The owner-aware server CLI misbehaves outside the default single-user loopback setup: it probes without the loopback check, registers with the wrong port, reports the wrong PID, erases a bad config silently, prints a hint that ignores HOME, and prints server-supplied text unfiltered.

Found during IW-652 (per-user dashboard, service links, Claude session links). Follow-ups, verbatim:

  • ServerConfigRepository.getOrCreateDefault (core/adapters/ServerConfigRepository.scala:52-59) writes the default config over a config.json that fails parsing or validation, so a bad edit is erased without a word.
  • The ServerClient lazy spawn and iw dashboard (core/commands/Dashboard.scala:133) probe localhost without the loopback check that IW-652 Phase 1 adds to iw server run and iw server start; with a tailnet-only config they start a server and then report it as failed.
  • The dashboard registers a browser-created worktree through ServerClient.registerWorktree (dashboard/jvm/src/infrastructure/CaskServer.scala:1394), which takes the port from IW_SERVER_PORT or config.json and not from the server's own port; a server started on another port registers with the wrong server, or is refused by the owner check.
  • iw server status prints this user's live PID next to whatever server answers the port, also when /api/status names another owner (core/commands/Server.scala showStatus/reportStatus).
  • The config path hint ~/.local/share/iw/server/config.json is a literal in core/model/ServerOwnership.scala and in the start exit-code text, while Server.configPath follows HOME; the hint is wrong when the data directory moves.
  • The owner name from /api/status and non-JSON error bodies from the server are printed to the terminal unfiltered (ServerOwnership.refusal, Server.scala status lines, ServerClient.scala error mapping); strip control characters or validate the owner as a login name in ServerStatus.readReply.
The owner-aware server CLI misbehaves outside the default single-user loopback setup: it probes without the loopback check, registers with the wrong port, reports the wrong PID, erases a bad config silently, prints a hint that ignores HOME, and prints server-supplied text unfiltered. Found during IW-652 (per-user dashboard, service links, Claude session links). Follow-ups, verbatim: - [ ] `ServerConfigRepository.getOrCreateDefault` (`core/adapters/ServerConfigRepository.scala:52-59`) writes the default config over a `config.json` that fails parsing or validation, so a bad edit is erased without a word. - [ ] The `ServerClient` lazy spawn and `iw dashboard` (`core/commands/Dashboard.scala:133`) probe `localhost` without the loopback check that IW-652 Phase 1 adds to `iw server run` and `iw server start`; with a tailnet-only config they start a server and then report it as failed. - [ ] The dashboard registers a browser-created worktree through `ServerClient.registerWorktree` (`dashboard/jvm/src/infrastructure/CaskServer.scala:1394`), which takes the port from `IW_SERVER_PORT` or `config.json` and not from the server's own port; a server started on another port registers with the wrong server, or is refused by the owner check. - [ ] `iw server status` prints this user's live PID next to whatever server answers the port, also when `/api/status` names another owner (`core/commands/Server.scala` `showStatus`/`reportStatus`). - [ ] The config path hint `~/.local/share/iw/server/config.json` is a literal in `core/model/ServerOwnership.scala` and in the `start` exit-code text, while `Server.configPath` follows `HOME`; the hint is wrong when the data directory moves. - [ ] The owner name from `/api/status` and non-JSON error bodies from the server are printed to the terminal unfiltered (`ServerOwnership.refusal`, `Server.scala` status lines, `ServerClient.scala` error mapping); strip control characters or validate the owner as a login name in `ServerStatus.readReply`.
Author
Member

Intake: needs-human
Workflow: diagnostic
Reason: G5 — 6 phases (also: a refused correction stands — the Defect 4 fix would print "not the server on port" for an owner-unknown server, including your own; see Review Notes)
Analysis: project-management/issues/IW-675/analysis.md on branch IW-675

Intake: needs-human Workflow: diagnostic Reason: G5 — 6 phases (also: a refused correction stands — the Defect 4 fix would print "not the server on port" for an owner-unknown server, including your own; see Review Notes) Analysis: project-management/issues/IW-675/analysis.md on branch IW-675
Author
Member

Intake: needs-input
Workflow: diagnostic
Reason: G5 (6 phases); G7 (1 standing correction of the analysis review)
Analysis: project-management/issues/IW-675/analysis.md on branch IW-675

  1. [G7] Defect 4's fix (analysis.md:733, also :1021, :1091) prints "PID file names live process , but it is not the server on port " also when ServerOwnership decides Unknown (core/model/ServerOwnership.scala:20-24). Unknown means only that the server reports no owner, or that iw cannot read the own user; it does not show that the process is another server. Your live server reports "Owner: unknown" (analysis.md:172), so after the fix iw server status would tell you that your own server is not yours, and would also stop printing PID: until the server restarts on a newer build. The reviewer and the corrector agree that the Unknown line must not say "not the server on port"; the corrector refused the reviewer's one wording because it is false when the own user is unreadable. What should iw server status print on Unknown? Options: a) one line per cause: "the server on port reports no owner, so iw cannot tell whether it is process " when the server reports none, and "iw cannot read your user, so it cannot tell whether the server on port is process " when the own user is unreadable; keep printing PID: on Unknown b) one neutral line for both causes: "iw cannot tell whether the server on port is process ", and keep PID: c) print no ownership line and no PID: on Unknown Recommended: a)
  2. [G5] tasks.md has 6 phases; an unattended issue holds at most 3. The answer is usually to split the issue, not to raise the bar. The phase index falls into two chains: phases 1-3 — a config that fails parsing is erased without a word (2-4 h), the lazy spawn and iw dashboard start a server the CLI cannot reach (3-5 h), a worktree made in the browser is registered with the server config.json names (3-5 h); each needs the one before. Phases 4-6 — the config path hint ignores where the config is read from (1-2 h), server text reaches the terminal with control characters (2-3 h), iw server status prints this user's PID next to another user's server (2-3 h); phase 5 must come before phase 6. How should IW-675 be split? Options: a) IW-675 keeps phases 1-3, and a new issue takes phases 4-6 (Defects 5, 6 and 4) b) three issues of two phases each: 1-2, 3-4, 5-6 c) run all 6 phases as one issue Recommended: a)

Answer in a comment on this issue; intake reads it on its next iteration.

Intake: needs-input Workflow: diagnostic Reason: G5 (6 phases); G7 (1 standing correction of the analysis review) Analysis: project-management/issues/IW-675/analysis.md on branch IW-675 1. [G7] Defect 4's fix (analysis.md:733, also :1021, :1091) prints "PID file names live process <n>, but it is not the server on port <port>" also when `ServerOwnership` decides `Unknown` (`core/model/ServerOwnership.scala:20-24`). `Unknown` means only that the server reports no owner, or that iw cannot read the own user; it does not show that the process is another server. Your live server reports "Owner: unknown" (analysis.md:172), so after the fix `iw server status` would tell you that your own server is not yours, and would also stop printing `PID:` until the server restarts on a newer build. The reviewer and the corrector agree that the `Unknown` line must not say "not the server on port"; the corrector refused the reviewer's one wording because it is false when the own user is unreadable. What should `iw server status` print on `Unknown`? Options: a) one line per cause: "the server on port <port> reports no owner, so iw cannot tell whether it is process <n>" when the server reports none, and "iw cannot read your user, so it cannot tell whether the server on port <port> is process <n>" when the own user is unreadable; keep printing `PID:` on `Unknown` b) one neutral line for both causes: "iw cannot tell whether the server on port <port> is process <n>", and keep `PID:` c) print no ownership line and no `PID:` on `Unknown` Recommended: a) 2. [G5] `tasks.md` has 6 phases; an unattended issue holds at most 3. The answer is usually to split the issue, not to raise the bar. The phase index falls into two chains: phases 1-3 — a config that fails parsing is erased without a word (2-4 h), the lazy spawn and `iw dashboard` start a server the CLI cannot reach (3-5 h), a worktree made in the browser is registered with the server `config.json` names (3-5 h); each needs the one before. Phases 4-6 — the config path hint ignores where the config is read from (1-2 h), server text reaches the terminal with control characters (2-3 h), `iw server status` prints this user's PID next to another user's server (2-3 h); phase 5 must come before phase 6. How should IW-675 be split? Options: a) IW-675 keeps phases 1-3, and a new issue takes phases 4-6 (Defects 5, 6 and 4) b) three issues of two phases each: 1-2, 3-4, 5-6 c) run all 6 phases as one issue Recommended: a) Answer in a comment on this issue; intake reads it on its next iteration.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
iterative-works/iw-cli#675
No description provided.