[2.x] fix: Read the token again when it is refused (#9738)

**Problem**
The client sent the handshake and ignored the answer: responsePlan had
no case for it, so an invalid token was dropped. The channel then stayed
unauthenticated and every later request was refused, with nothing saying
why.

**Solution**
Match the handshake response. On a refusal, read the token file again
and present what it names now, up to handshakeAttemptLimit times, then
report the refusal.

---------

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Albert Meltzer
2026-09-17 22:44:10 -04:00
committed by GitHub
co-authored by Claude Opus 5
parent e95712b79f
commit e4e7ec8116
3 changed files with 275 additions and 22 deletions
@@ -39,19 +39,27 @@ object ClientSocket:
parsed.flatMap(Converter.fromJson[PortFile])
def socket(portfile: File, useJNI: Boolean): (Socket, Option[String]) =
import fileFormats.given
val p = loadPortFile(portfile) match
case Success(p) => p
case Failure(e) => throw new ConnectionFileReadException(portfile, e)
val p = readPortFile(portfile)
val uri = new URI(p.uri)
val token = p.tokenfilePath map { tp =>
val token = readToken(p)
(connect(uri, useJNI), token)
private def readPortFile(portfile: File): PortFile = loadPortFile(portfile) match
case Success(p) => p
case Failure(e) => throw new ConnectionFileReadException(portfile, e)
private def readToken(p: PortFile): Option[String] =
import fileFormats.given
p.tokenfilePath map { tp =>
val tokeFile = new File(tp)
try
val json: JValue = Parser.parseFromFile(tokeFile).get
Converter.fromJson[TokenFile](json).get.token
catch case NonFatal(e) => throw new ConnectionFileReadException(tokeFile, e)
}
(connect(uri, useJNI), token)
/** Reads the token that the portfile names, if it names one. */
private[sbt] def token(portfile: File): Option[String] = readToken(readPortFile(portfile))
private def connect(uri: URI, useJNI: Boolean): Socket =
uri.getScheme match