Skip to content

Commit eaabb3a

Browse files
committed
merge branch 'main' of https://github.com/coder/coder into spike/pty-ssh
2 parents 0f07cb9 + ab077d1 commit eaabb3a

File tree

555 files changed

+16255
-11966
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

555 files changed

+16255
-11966
lines changed

.github/workflows/ci.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ jobs:
152152

153153
- uses: actions/setup-go@v4
154154
with:
155+
cache: false
155156
go-version: "~1.20"
156157

157158
- name: Echo Go Cache Paths
@@ -252,6 +253,7 @@ jobs:
252253

253254
- uses: actions/setup-go@v4
254255
with:
256+
cache: false
255257
go-version: "~1.20"
256258

257259
- name: Echo Go Cache Paths
@@ -339,6 +341,7 @@ jobs:
339341

340342
- uses: actions/setup-go@v4
341343
with:
344+
cache: false
342345
go-version: "~1.20"
343346

344347
- name: Echo Go Cache Paths
@@ -429,6 +432,7 @@ jobs:
429432

430433
- uses: actions/setup-go@v4
431434
with:
435+
cache: false
432436
go-version: "~1.20"
433437

434438
- name: Echo Go Cache Paths
@@ -558,6 +562,7 @@ jobs:
558562

559563
- uses: actions/setup-go@v4
560564
with:
565+
cache: false
561566
go-version: "~1.20"
562567

563568
- uses: hashicorp/setup-terraform@v2
@@ -634,6 +639,9 @@ jobs:
634639
- name: Publish to Chromatic (non-mainline)
635640
if: github.ref != 'refs/heads/main' && github.repository_owner == 'coder'
636641
uses: chromaui/action@v1
642+
env:
643+
NODE_OPTIONS: "--max_old_space_size=4096"
644+
STORYBOOK: true
637645
with:
638646
buildScriptName: "storybook:build"
639647
exitOnceUploaded: true
@@ -651,6 +659,9 @@ jobs:
651659
- name: Publish to Chromatic (mainline)
652660
if: github.ref == 'refs/heads/main' && github.repository_owner == 'coder'
653661
uses: chromaui/action@v1
662+
env:
663+
NODE_OPTIONS: "--max_old_space_size=4096"
664+
STORYBOOK: true
654665
with:
655666
autoAcceptChanges: true
656667
buildScriptName: "storybook:build"

.github/workflows/cron-weekly.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Markdown Links Check
1+
name: Weekly Cron
22
# runs every monday at 9 am
33
on:
44
schedule:
@@ -19,10 +19,12 @@ jobs:
1919
with:
2020
use-quiet-mode: "yes"
2121
use-verbose-mode: "yes"
22-
config-file: ".github/workflows/markdown.links.config.json"
22+
config-file: ".github/workflows/mlc_config.json"
2323
folder-path: "docs/"
24+
file-path: "./README.md"
2425

2526
- name: Send Slack notification
27+
if: failure()
2628
run: |
2729
curl -X POST -H 'Content-type: application/json' -d '{"msg":"Broken links found in the documentation. Please check the logs at ${{ env.LOGS_URL }}"}' ${{ secrets.DOCS_LINK_SLACK_WEBHOOK }}
2830
echo "Sent Slack notification"

.github/workflows/mlc_config.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@
1818
{
1919
"pattern": "tailscale.com"
2020
}
21-
]
21+
],
22+
"aliveStatusCodes": [200, 0]
2223
}

Makefile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ gen: \
423423
provisionersdk/proto/provisioner.pb.go \
424424
provisionerd/proto/provisionerd.pb.go \
425425
site/src/api/typesGenerated.ts \
426+
coderd/rbac/object_gen.go \
426427
docs/admin/prometheus.md \
427428
docs/cli.md \
428429
docs/admin/audit-logs.md \
@@ -443,6 +444,7 @@ gen/mark-fresh:
443444
provisionersdk/proto/provisioner.pb.go \
444445
provisionerd/proto/provisionerd.pb.go \
445446
site/src/api/typesGenerated.ts \
447+
coderd/rbac/object_gen.go \
446448
docs/admin/prometheus.md \
447449
docs/cli.md \
448450
docs/admin/audit-logs.md \
@@ -495,6 +497,9 @@ site/src/api/typesGenerated.ts: scripts/apitypings/main.go $(shell find ./coders
495497
cd site
496498
yarn run format:types
497499

500+
coderd/rbac/object_gen.go: scripts/rbacgen/main.go coderd/rbac/object.go
501+
go run scripts/rbacgen/main.go ./coderd/rbac > coderd/rbac/object_gen.go
502+
498503
docs/admin/prometheus.md: scripts/metricsdocgen/main.go scripts/metricsdocgen/metrics
499504
go run scripts/metricsdocgen/main.go
500505
cd site
@@ -505,12 +510,12 @@ docs/cli.md: scripts/clidocgen/main.go $(GO_SRC_FILES) docs/manifest.json
505510
cd site
506511
yarn run format:write:only ../docs/cli.md ../docs/cli/*.md ../docs/manifest.json
507512

508-
docs/admin/audit-logs.md: scripts/auditdocgen/main.go enterprise/audit/table.go
513+
docs/admin/audit-logs.md: scripts/auditdocgen/main.go enterprise/audit/table.go coderd/rbac/object_gen.go
509514
go run scripts/auditdocgen/main.go
510515
cd site
511516
yarn run format:write:only ../docs/admin/audit-logs.md
512517

513-
coderd/apidoc/swagger.json: $(shell find ./scripts/apidocgen $(FIND_EXCLUSIONS) -type f) $(wildcard coderd/*.go) $(wildcard enterprise/coderd/*.go) $(wildcard codersdk/*.go) .swaggo docs/manifest.json
518+
coderd/apidoc/swagger.json: $(shell find ./scripts/apidocgen $(FIND_EXCLUSIONS) -type f) $(wildcard coderd/*.go) $(wildcard enterprise/coderd/*.go) $(wildcard codersdk/*.go) $(wildcard enterprise/wsproxy/wsproxysdk/*.go) coderd/database/querier.go .swaggo docs/manifest.json coderd/rbac/object_gen.go
514519
./scripts/apidocgen/generate.sh
515520
yarn run --cwd=site format:write:only ../docs/api ../docs/manifest.json ../coderd/apidoc/swagger.json
516521

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ coder server --postgres-url <url> --access-url <url>
8484

8585
> <sup>1</sup> For production deployments, set up an external PostgreSQL instance for reliability.
8686
87-
Use `coder --help` to get a list of flags and environment variables. Use our [install guides](https://coder.com/docs/v2/latest/guides) for a full walkthrough.
87+
Use `coder --help` to get a list of flags and environment variables. Use our [install guides](https://coder.com/docs/v2/latest/install) for a full walkthrough.
8888

8989
## Documentation
9090

agent/agent.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ type agent struct {
161161
}
162162

163163
func (a *agent) init(ctx context.Context) {
164-
sshSrv, err := agentssh.NewServer(ctx, a.logger.Named("ssh-server"), a.sshMaxTimeout)
164+
sshSrv, err := agentssh.NewServer(ctx, a.logger.Named("ssh-server"), a.filesystem, a.sshMaxTimeout, "")
165165
if err != nil {
166166
panic(err)
167167
}
@@ -1407,5 +1407,14 @@ func expandDirectory(dir string) (string, error) {
14071407
}
14081408
dir = filepath.Join(home, dir[1:])
14091409
}
1410-
return os.ExpandEnv(dir), nil
1410+
dir = os.ExpandEnv(dir)
1411+
1412+
if !filepath.IsAbs(dir) {
1413+
home, err := userHomeDir()
1414+
if err != nil {
1415+
return "", err
1416+
}
1417+
dir = filepath.Join(home, dir)
1418+
}
1419+
return dir, nil
14111420
}

agent/agent_test.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -706,12 +706,15 @@ func TestAgent_UnixRemoteForwarding(t *testing.T) {
706706

707707
// It's possible that the socket is created but the server is not ready to
708708
// accept connections yet. We need to retry until we can connect.
709+
//
710+
// Note that we wait long here because if the tailnet connection has trouble
711+
// connecting, it could take 5 seconds or more to reconnect.
709712
var conn net.Conn
710713
require.Eventually(t, func() bool {
711714
var err error
712715
conn, err = net.Dial("unix", remoteSocketPath)
713716
return err == nil
714-
}, testutil.WaitShort, testutil.IntervalFast)
717+
}, testutil.WaitLong, testutil.IntervalFast)
715718
defer conn.Close()
716719
_, err = conn.Write([]byte("test"))
717720
require.NoError(t, err)
@@ -1364,6 +1367,22 @@ func TestAgent_Startup(t *testing.T) {
13641367
require.Equal(t, homeDir, client.getStartup().ExpandedDirectory)
13651368
})
13661369

1370+
t.Run("NotAbsoluteDirectory", func(t *testing.T) {
1371+
t.Parallel()
1372+
1373+
_, client, _, _, _ := setupAgent(t, agentsdk.Manifest{
1374+
StartupScript: "true",
1375+
StartupScriptTimeout: 30 * time.Second,
1376+
Directory: "coder/coder",
1377+
}, 0)
1378+
assert.Eventually(t, func() bool {
1379+
return client.getStartup().Version != ""
1380+
}, testutil.WaitShort, testutil.IntervalFast)
1381+
homeDir, err := os.UserHomeDir()
1382+
require.NoError(t, err)
1383+
require.Equal(t, filepath.Join(homeDir, "coder/coder"), client.getStartup().ExpandedDirectory)
1384+
})
1385+
13671386
t.Run("HomeEnvironmentVariable", func(t *testing.T) {
13681387
t.Parallel()
13691388

@@ -1733,7 +1752,9 @@ func setupAgent(t *testing.T, metadata agentsdk.Manifest, ptyTimeout time.Durati
17331752
t.Cleanup(func() {
17341753
_ = agentConn.Close()
17351754
})
1736-
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium)
1755+
// Ideally we wouldn't wait too long here, but sometimes the the
1756+
// networking needs more time to resolve itself.
1757+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
17371758
defer cancel()
17381759
if !agentConn.AwaitReachable(ctx) {
17391760
t.Fatal("agent not reachable")

agent/agentssh/agentssh.go

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020

2121
"github.com/gliderlabs/ssh"
2222
"github.com/pkg/sftp"
23+
"github.com/spf13/afero"
2324
"go.uber.org/atomic"
2425
gossh "golang.org/x/crypto/ssh"
2526
"golang.org/x/xerrors"
@@ -48,6 +49,7 @@ const (
4849

4950
type Server struct {
5051
mu sync.RWMutex // Protects following.
52+
fs afero.Fs
5153
listeners map[net.Listener]struct{}
5254
conns map[net.Conn]struct{}
5355
sessions map[ssh.Session]struct{}
@@ -56,8 +58,9 @@ type Server struct {
5658
// a lock on mu but protected by closing.
5759
wg sync.WaitGroup
5860

59-
logger slog.Logger
60-
srv *ssh.Server
61+
logger slog.Logger
62+
srv *ssh.Server
63+
x11SocketDir string
6164

6265
Env map[string]string
6366
AgentToken func() string
@@ -68,7 +71,7 @@ type Server struct {
6871
connCountSSHSession atomic.Int64
6972
}
7073

71-
func NewServer(ctx context.Context, logger slog.Logger, maxTimeout time.Duration) (*Server, error) {
74+
func NewServer(ctx context.Context, logger slog.Logger, fs afero.Fs, maxTimeout time.Duration, x11SocketDir string) (*Server, error) {
7275
// Clients' should ignore the host key when connecting.
7376
// The agent needs to authenticate with coderd to SSH,
7477
// so SSH authentication doesn't improve security.
@@ -80,15 +83,20 @@ func NewServer(ctx context.Context, logger slog.Logger, maxTimeout time.Duration
8083
if err != nil {
8184
return nil, err
8285
}
86+
if x11SocketDir == "" {
87+
x11SocketDir = filepath.Join(os.TempDir(), ".X11-unix")
88+
}
8389

8490
forwardHandler := &ssh.ForwardedTCPHandler{}
8591
unixForwardHandler := &forwardedUnixHandler{log: logger}
8692

8793
s := &Server{
88-
listeners: make(map[net.Listener]struct{}),
89-
conns: make(map[net.Conn]struct{}),
90-
sessions: make(map[ssh.Session]struct{}),
91-
logger: logger,
94+
listeners: make(map[net.Listener]struct{}),
95+
fs: fs,
96+
conns: make(map[net.Conn]struct{}),
97+
sessions: make(map[ssh.Session]struct{}),
98+
logger: logger,
99+
x11SocketDir: x11SocketDir,
92100
}
93101

94102
s.srv = &ssh.Server{
@@ -125,6 +133,7 @@ func NewServer(ctx context.Context, logger slog.Logger, maxTimeout time.Duration
125133
"streamlocal-forward@openssh.com": unixForwardHandler.HandleSSHRequest,
126134
"cancel-streamlocal-forward@openssh.com": unixForwardHandler.HandleSSHRequest,
127135
},
136+
X11Callback: s.x11Callback,
128137
ServerConfigCallback: func(ctx ssh.Context) *gossh.ServerConfig {
129138
return &gossh.ServerConfig{
130139
NoClientAuth: true,
@@ -163,6 +172,17 @@ func (s *Server) sessionHandler(session ssh.Session) {
163172

164173
ctx := session.Context()
165174

175+
extraEnv := make([]string, 0)
176+
x11, hasX11 := session.X11()
177+
if hasX11 {
178+
handled := s.x11Handler(session.Context(), x11)
179+
if !handled {
180+
_ = session.Exit(1)
181+
return
182+
}
183+
extraEnv = append(extraEnv, fmt.Sprintf("DISPLAY=:%d.0", x11.ScreenNumber))
184+
}
185+
166186
switch ss := session.Subsystem(); ss {
167187
case "":
168188
case "sftp":
@@ -174,7 +194,7 @@ func (s *Server) sessionHandler(session ssh.Session) {
174194
return
175195
}
176196

177-
err := s.sessionStart(session)
197+
err := s.sessionStart(session, extraEnv)
178198
var exitError *exec.ExitError
179199
if xerrors.As(err, &exitError) {
180200
s.logger.Debug(ctx, "ssh session returned", slog.Error(exitError))
@@ -191,9 +211,9 @@ func (s *Server) sessionHandler(session ssh.Session) {
191211
_ = session.Exit(0)
192212
}
193213

194-
func (s *Server) sessionStart(session ssh.Session) error {
214+
func (s *Server) sessionStart(session ssh.Session, extraEnv []string) (retErr error) {
195215
ctx := session.Context()
196-
env := session.Environ()
216+
env := append(session.Environ(), extraEnv...)
197217
var magicType string
198218
for index, kv := range env {
199219
if !strings.HasPrefix(kv, MagicSessionTypeEnvironmentVariable) {

agent/agentssh/agentssh_internal_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"testing"
1212

1313
gliderssh "github.com/gliderlabs/ssh"
14+
"github.com/spf13/afero"
1415
"github.com/stretchr/testify/assert"
1516
"github.com/stretchr/testify/require"
1617

@@ -35,7 +36,7 @@ func Test_sessionStart_orphan(t *testing.T) {
3536
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium)
3637
defer cancel()
3738
logger := slogtest.Make(t, nil)
38-
s, err := NewServer(ctx, logger, 0)
39+
s, err := NewServer(ctx, logger, afero.NewMemMapFs(), 0, "")
3940
require.NoError(t, err)
4041

4142
// Here we're going to call the handler directly with a faked SSH session

agent/agentssh/agentssh_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"sync"
1111
"testing"
1212

13+
"github.com/spf13/afero"
1314
"github.com/stretchr/testify/assert"
1415
"github.com/stretchr/testify/require"
1516
"go.uber.org/atomic"
@@ -32,7 +33,7 @@ func TestNewServer_ServeClient(t *testing.T) {
3233

3334
ctx := context.Background()
3435
logger := slogtest.Make(t, nil)
35-
s, err := agentssh.NewServer(ctx, logger, 0)
36+
s, err := agentssh.NewServer(ctx, logger, afero.NewMemMapFs(), 0, "")
3637
require.NoError(t, err)
3738

3839
// The assumption is that these are set before serving SSH connections.
@@ -50,6 +51,7 @@ func TestNewServer_ServeClient(t *testing.T) {
5051
}()
5152

5253
c := sshClient(t, ln.Addr().String())
54+
5355
var b bytes.Buffer
5456
sess, err := c.NewSession()
5557
sess.Stdout = &b
@@ -72,7 +74,7 @@ func TestNewServer_CloseActiveConnections(t *testing.T) {
7274

7375
ctx := context.Background()
7476
logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
75-
s, err := agentssh.NewServer(ctx, logger, 0)
77+
s, err := agentssh.NewServer(ctx, logger, afero.NewMemMapFs(), 0, "")
7678
require.NoError(t, err)
7779

7880
// The assumption is that these are set before serving SSH connections.

0 commit comments

Comments
 (0)