Skip to content

Commit c272ed8

Browse files
ralyodioclaude
andcommitted
join@: require a PTY so onboarding can't hang
handleJoin reads the email and verification code interactively, but the router deliberately skipped the active-PTY guard for join@ on the wrong assumption that it "prints and disconnects." A client without a controlling tty (ssh delegating prompts to ssh-askpass) gets no PTY, so the email prompt blocked forever after the account banner. Guard handleJoin for a PTY and emit a "reconnect with ssh -t" hint instead of hanging; fix the misleading router comment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 84e7066 commit c272ed8

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

cmd/agentbbs/main.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,9 @@ func main() {
194194
}
195195

196196
// router dispatches a session by username (PRD §4.4 + pods addendum).
197-
// The active-PTY guard applies to hub sessions only: join@ must work without
198-
// a terminal (it prints and disconnects), and pod@ checks its PTY itself.
197+
// The active-PTY guard applies to hub sessions only; join@ and pod@ check their
198+
// own PTY (both are interactive) so they can return a tailored hint instead of
199+
// activeterm's opaque rejection.
199200
func (a *app) router() wish.Middleware {
200201
btMw := bm.Middleware(a.teaHandler)
201202
adminMw := bm.Middleware(a.adminTeaHandler)
@@ -291,6 +292,15 @@ func (a *app) handleJoin(s ssh.Session) {
291292
_ = s.Exit(1)
292293
return
293294
}
295+
// Onboarding reads an email and a verification code interactively, so it
296+
// needs a terminal. Without a PTY the prompts would block forever (e.g. ssh
297+
// launched with no controlling tty, which delegates prompts to ssh-askpass).
298+
// Fail fast with a hint instead of hanging.
299+
if _, _, hasPty := s.Pty(); !hasPty {
300+
wish.Println(s, "join@ is interactive — reconnect with a terminal: ssh -t join@"+a.host)
301+
_ = s.Exit(1)
302+
return
303+
}
294304
u, found, err := a.st.UserByFingerprint(fp)
295305
if err == nil && !found {
296306
name := "member-" + strings.ToLower(strings.TrimPrefix(fp, "SHA256:"))[:8]

0 commit comments

Comments
 (0)