@@ -113,6 +113,7 @@ func (s *AgentStartCLI) runWrapper(parent *AgentCLI, logger *slog.Logger, tlsCfg
113113 hello , err := agent .ProbeUpstream (upstreamSocket )
114114 if err != nil {
115115 logger .Warn ("failed to probe upstream agent" , "error" , err )
116+ upstreamSocket = ""
116117 } else if hello != nil {
117118 depth = hello .ChainDepth + 1
118119 brokerOpts = append (brokerOpts , broker .WithUpstream (upstreamSocket ))
@@ -145,7 +146,9 @@ func (s *AgentStartCLI) runWrapper(parent *AgentCLI, logger *slog.Logger, tlsCfg
145146 go func () {
146147 brokerErr <- b .Serve (ctx )
147148 }()
148- <- b .Ready ()
149+ if err := waitForBrokerStartup (b , brokerErr ); err != nil {
150+ return err
151+ }
149152
150153 // Generate SSH config.
151154 sshConfigPath := filepath .Join (tempDir , "ssh-config.conf" )
@@ -158,25 +161,22 @@ func (s *AgentStartCLI) runWrapper(parent *AgentCLI, logger *slog.Logger, tlsCfg
158161 }
159162 }
160163
161- // Create proxy listener if we have an upstream socket to proxy.
162- if upstreamSocket != "" {
163- proxySock := filepath .Join (tempDir , "proxy.sock" )
164- setup := func (p * agent.ProxyAgent ) {
165- p .RegisterExtension (agent .ExtensionHello , agent .HelloHandler (depth ))
166- p .RegisterExtension (agent .ExtensionAuth , agent .AuthHandler (func () (string , error ) {
167- return b .Authenticate (nil )
168- }))
169- }
170- proxyListener := agent .NewProxyListener (logger , proxySock , upstreamSocket , setup )
171- go func () {
172- if err := proxyListener .Serve (ctx ); err != nil && err != context .Canceled {
173- logger .Error ("proxy listener error" , "error" , err )
174- }
175- }()
176- <- proxyListener .Ready ()
177- upstreamSocket = proxySock
178- logger .Info ("proxy agent listening" , "socket" , proxySock )
164+ proxySock := filepath .Join (tempDir , "proxy.sock" )
165+ setup := func (p * agent.ProxyAgent ) {
166+ p .RegisterExtension (agent .ExtensionHello , agent .HelloHandler (depth ))
167+ p .RegisterExtension (agent .ExtensionAuth , agent .AuthHandler (func () (string , error ) {
168+ return b .Authenticate (nil )
169+ }))
179170 }
171+ proxyListener := agent .NewProxyListener (logger , proxySock , upstreamSocket , setup )
172+ go func () {
173+ if err := proxyListener .Serve (ctx ); err != nil && err != context .Canceled {
174+ logger .Error ("proxy listener error" , "error" , err )
175+ }
176+ }()
177+ <- proxyListener .Ready ()
178+ upstreamSocket = proxySock
179+ logger .Info ("proxy agent listening" , "socket" , proxySock )
180180
181181 // Build child environment with updated SSH_AUTH_SOCK.
182182 childEnv := os .Environ ()
@@ -223,6 +223,18 @@ func (s *AgentStartCLI) runWrapper(parent *AgentCLI, logger *slog.Logger, tlsCfg
223223 return nil
224224}
225225
226+ func waitForBrokerStartup (b * broker.Broker , brokerErr <- chan error ) error {
227+ select {
228+ case <- b .Ready ():
229+ return nil
230+ case err := <- brokerErr :
231+ if err == nil || err == context .Canceled {
232+ return fmt .Errorf ("broker exited before becoming ready" )
233+ }
234+ return fmt .Errorf ("broker failed to start: %w" , err )
235+ }
236+ }
237+
226238// setupBrokerWithOptions creates the broker, temp directories, and resolves auth.
227239// When wrapperMode is true, uses a per-process temp directory to avoid collisions
228240// between multiple wrapped shells. When false (daemon mode), uses a deterministic
0 commit comments