mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: Separate workspace agent for tests (#567)
This adds tests for Google Cloud authentication, and lays the ground-work for future agent auth types in the future.
This commit is contained in:
+9
-39
@@ -26,36 +26,6 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func DialSSH(conn *peer.Conn) (net.Conn, error) {
|
||||
channel, err := conn.Dial(context.Background(), "ssh", &peer.ChannelOptions{
|
||||
Protocol: "ssh",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return channel.NetConn(), nil
|
||||
}
|
||||
|
||||
func DialSSHClient(conn *peer.Conn) (*gossh.Client, error) {
|
||||
netConn, err := DialSSH(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sshConn, channels, requests, err := gossh.NewClientConn(netConn, "localhost:22", &gossh.ClientConfig{
|
||||
Config: gossh.Config{
|
||||
Ciphers: []string{"arcfour"},
|
||||
},
|
||||
// SSH host validation isn't helpful, because obtaining a peer
|
||||
// connection already signifies user-intent to dial a workspace.
|
||||
// #nosec
|
||||
HostKeyCallback: gossh.InsecureIgnoreHostKey(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gossh.NewClient(sshConn, channels, requests), nil
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
Logger slog.Logger
|
||||
}
|
||||
@@ -64,7 +34,7 @@ type Dialer func(ctx context.Context, options *peer.ConnOptions) (*peerbroker.Li
|
||||
|
||||
func New(dialer Dialer, options *peer.ConnOptions) io.Closer {
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
server := &server{
|
||||
server := &agent{
|
||||
clientDialer: dialer,
|
||||
options: options,
|
||||
closeCancel: cancelFunc,
|
||||
@@ -74,7 +44,7 @@ func New(dialer Dialer, options *peer.ConnOptions) io.Closer {
|
||||
return server
|
||||
}
|
||||
|
||||
type server struct {
|
||||
type agent struct {
|
||||
clientDialer Dialer
|
||||
options *peer.ConnOptions
|
||||
|
||||
@@ -86,7 +56,7 @@ type server struct {
|
||||
sshServer *ssh.Server
|
||||
}
|
||||
|
||||
func (s *server) run(ctx context.Context) {
|
||||
func (s *agent) run(ctx context.Context) {
|
||||
var peerListener *peerbroker.Listener
|
||||
var err error
|
||||
// An exponential back-off occurs when the connection is failing to dial.
|
||||
@@ -103,7 +73,7 @@ func (s *server) run(ctx context.Context) {
|
||||
s.options.Logger.Warn(context.Background(), "failed to dial", slog.Error(err))
|
||||
continue
|
||||
}
|
||||
s.options.Logger.Debug(context.Background(), "connected")
|
||||
s.options.Logger.Info(context.Background(), "connected")
|
||||
break
|
||||
}
|
||||
select {
|
||||
@@ -129,7 +99,7 @@ func (s *server) run(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) handlePeerConn(ctx context.Context, conn *peer.Conn) {
|
||||
func (s *agent) handlePeerConn(ctx context.Context, conn *peer.Conn) {
|
||||
go func() {
|
||||
<-conn.Closed()
|
||||
s.connCloseWait.Done()
|
||||
@@ -156,7 +126,7 @@ func (s *server) handlePeerConn(ctx context.Context, conn *peer.Conn) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) init(ctx context.Context) {
|
||||
func (s *agent) init(ctx context.Context) {
|
||||
// Clients' should ignore the host key when connecting.
|
||||
// The agent needs to authenticate with coderd to SSH,
|
||||
// so SSH authentication doesn't improve security.
|
||||
@@ -221,7 +191,7 @@ func (s *server) init(ctx context.Context) {
|
||||
go s.run(ctx)
|
||||
}
|
||||
|
||||
func (*server) handleSSHSession(session ssh.Session) error {
|
||||
func (*agent) handleSSHSession(session ssh.Session) error {
|
||||
var (
|
||||
command string
|
||||
args = []string{}
|
||||
@@ -316,7 +286,7 @@ func (*server) handleSSHSession(session ssh.Session) error {
|
||||
}
|
||||
|
||||
// isClosed returns whether the API is closed or not.
|
||||
func (s *server) isClosed() bool {
|
||||
func (s *agent) isClosed() bool {
|
||||
select {
|
||||
case <-s.closed:
|
||||
return true
|
||||
@@ -325,7 +295,7 @@ func (s *server) isClosed() bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) Close() error {
|
||||
func (s *agent) Close() error {
|
||||
s.closeMutex.Lock()
|
||||
defer s.closeMutex.Unlock()
|
||||
if s.isClosed() {
|
||||
|
||||
+4
-2
@@ -39,7 +39,8 @@ func TestAgent(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
_ = conn.Close()
|
||||
})
|
||||
sshClient, err := agent.DialSSHClient(conn)
|
||||
client := agent.Conn{conn}
|
||||
sshClient, err := client.SSHClient()
|
||||
require.NoError(t, err)
|
||||
session, err := sshClient.NewSession()
|
||||
require.NoError(t, err)
|
||||
@@ -64,7 +65,8 @@ func TestAgent(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
_ = conn.Close()
|
||||
})
|
||||
sshClient, err := agent.DialSSHClient(conn)
|
||||
client := &agent.Conn{conn}
|
||||
sshClient, err := client.SSHClient()
|
||||
require.NoError(t, err)
|
||||
session, err := sshClient.NewSession()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/peer"
|
||||
)
|
||||
|
||||
// Conn wraps a peer connection with helper functions to
|
||||
// communicate with the agent.
|
||||
type Conn struct {
|
||||
*peer.Conn
|
||||
}
|
||||
|
||||
// SSH dials the built-in SSH server.
|
||||
func (c *Conn) SSH() (net.Conn, error) {
|
||||
channel, err := c.Dial(context.Background(), "ssh", &peer.ChannelOptions{
|
||||
Protocol: "ssh",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("dial: %w", err)
|
||||
}
|
||||
return channel.NetConn(), nil
|
||||
}
|
||||
|
||||
// SSHClient calls SSH to create a client that uses a weak cipher
|
||||
// for high throughput.
|
||||
func (c *Conn) SSHClient() (*ssh.Client, error) {
|
||||
netConn, err := c.SSH()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("ssh: %w", err)
|
||||
}
|
||||
sshConn, channels, requests, err := ssh.NewClientConn(netConn, "localhost:22", &ssh.ClientConfig{
|
||||
Config: ssh.Config{
|
||||
Ciphers: []string{"arcfour"},
|
||||
},
|
||||
// SSH host validation isn't helpful, because obtaining a peer
|
||||
// connection already signifies user-intent to dial a workspace.
|
||||
// #nosec
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("ssh conn: %w", err)
|
||||
}
|
||||
return ssh.NewClient(sshConn, channels, requests), nil
|
||||
}
|
||||
Reference in New Issue
Block a user