Skip to content

Commit e6dae62

Browse files
committed
Merge branch 'main' of github.com:coder/coder into bq/fix-syntax-highlight-on-readme
2 parents eee762b + 88bb901 commit e6dae62

File tree

44 files changed

+510
-184
lines changed

Some content is hidden

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

44 files changed

+510
-184
lines changed

.github/workflows/coder.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,9 @@ jobs:
274274
export PATH=${PATH}:$(go env GOPATH)/bin
275275
make --output-sync -j -B fmt
276276
277+
- name: Check for unstaged files
278+
run: ./scripts/check_unstaged.sh
279+
277280
test-go:
278281
name: "test/go"
279282
runs-on: ${{ matrix.os == 'ubuntu-latest' && github.repository_owner == 'coder' && 'ubuntu-latest-16-cores' || matrix.os == 'windows-2022' && github.repository_owner == 'coder' && 'windows-latest-8-cores'|| matrix.os }}

agent/agent.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,16 @@ func (a *agent) run(ctx context.Context) error {
215215
return xerrors.Errorf("create tailnet: %w", err)
216216
}
217217
a.closeMutex.Lock()
218-
a.network = network
218+
// Re-check if agent was closed while initializing the network.
219+
closed := a.isClosed()
220+
if !closed {
221+
a.network = network
222+
}
219223
a.closeMutex.Unlock()
224+
if closed {
225+
_ = network.Close()
226+
return xerrors.New("agent is closed")
227+
}
220228
} else {
221229
// Update the DERP map!
222230
network.SetDERPMap(metadata.DERPMap)
@@ -246,27 +254,20 @@ func (a *agent) trackConnGoroutine(fn func()) error {
246254
}
247255

248256
func (a *agent) createTailnet(ctx context.Context, derpMap *tailcfg.DERPMap) (_ *tailnet.Conn, err error) {
249-
a.closeMutex.Lock()
250-
if a.isClosed() {
251-
a.closeMutex.Unlock()
252-
return nil, xerrors.New("closed")
253-
}
254257
network, err := tailnet.NewConn(&tailnet.Options{
255258
Addresses: []netip.Prefix{netip.PrefixFrom(codersdk.TailnetIP, 128)},
256259
DERPMap: derpMap,
257260
Logger: a.logger.Named("tailnet"),
258261
EnableTrafficStats: true,
259262
})
260263
if err != nil {
261-
a.closeMutex.Unlock()
262264
return nil, xerrors.Errorf("create tailnet: %w", err)
263265
}
264266
defer func() {
265267
if err != nil {
266268
network.Close()
267269
}
268270
}()
269-
a.closeMutex.Unlock()
270271

271272
sshListener, err := network.Listen("tcp", ":"+strconv.Itoa(codersdk.TailnetSSHPort))
272273
if err != nil {

agent/agent_test.go

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,6 @@ func TestAgent(t *testing.T) {
153153
err := session.RequestPty("xterm", 128, 128, ssh.TerminalModes{})
154154
require.NoError(t, err)
155155
ptty := ptytest.New(t)
156-
require.NoError(t, err)
157156
session.Stdout = ptty.Output()
158157
session.Stderr = ptty.Output()
159158
session.Stdin = ptty.Input()
@@ -178,7 +177,6 @@ func TestAgent(t *testing.T) {
178177
err := session.RequestPty("xterm", 128, 128, ssh.TerminalModes{})
179178
require.NoError(t, err)
180179
ptty := ptytest.New(t)
181-
require.NoError(t, err)
182180
session.Stdout = ptty.Output()
183181
session.Stderr = ptty.Output()
184182
session.Stdin = ptty.Input()
@@ -280,8 +278,8 @@ func TestAgent(t *testing.T) {
280278
require.NotContains(t, stdout.String(), wantNotMOTD, "should not show motd")
281279
})
282280

281+
//nolint:paralleltest // This test reserves a port.
283282
t.Run("LocalForwarding", func(t *testing.T) {
284-
t.Parallel()
285283
random, err := net.Listen("tcp", "127.0.0.1:0")
286284
require.NoError(t, err)
287285
_ = random.Close()
@@ -330,6 +328,7 @@ func TestAgent(t *testing.T) {
330328
defer sshClient.Close()
331329
client, err := sftp.NewClient(sshClient)
332330
require.NoError(t, err)
331+
defer client.Close()
333332
wd, err := client.Getwd()
334333
require.NoError(t, err, "get working directory")
335334
require.Equal(t, home, wd, "working directory should be home user home")
@@ -360,6 +359,7 @@ func TestAgent(t *testing.T) {
360359
defer sshClient.Close()
361360
scpClient, err := scp.NewClientBySSH(sshClient)
362361
require.NoError(t, err)
362+
defer scpClient.Close()
363363
tempFile := filepath.Join(t.TempDir(), "scp")
364364
content := "hello world"
365365
err = scpClient.CopyFile(context.Background(), strings.NewReader(content), tempFile, "0755")
@@ -501,6 +501,8 @@ func TestAgent(t *testing.T) {
501501
id := uuid.New()
502502
netConn, err := conn.ReconnectingPTY(ctx, id, 100, 100, "/bin/bash")
503503
require.NoError(t, err)
504+
defer netConn.Close()
505+
504506
bufRead := bufio.NewReader(netConn)
505507

506508
// Brief pause to reduce the likelihood that we send keystrokes while
@@ -539,6 +541,8 @@ func TestAgent(t *testing.T) {
539541
_ = netConn.Close()
540542
netConn, err = conn.ReconnectingPTY(ctx, id, 100, 100, "/bin/bash")
541543
require.NoError(t, err)
544+
defer netConn.Close()
545+
542546
bufRead = bufio.NewReader(netConn)
543547

544548
// Same output again!
@@ -629,6 +633,8 @@ func TestAgent(t *testing.T) {
629633
// After the agent is disconnected from a coordinator, it's supposed
630634
// to reconnect!
631635
coordinator := tailnet.NewCoordinator()
636+
defer coordinator.Close()
637+
632638
agentID := uuid.New()
633639
statsCh := make(chan *codersdk.AgentStats)
634640
derpMap := tailnettest.RunDERPAndSTUN(t)
@@ -650,9 +656,7 @@ func TestAgent(t *testing.T) {
650656
Client: client,
651657
Logger: slogtest.Make(t, nil).Leveled(slog.LevelInfo),
652658
})
653-
t.Cleanup(func() {
654-
_ = closer.Close()
655-
})
659+
defer closer.Close()
656660

657661
require.Eventually(t, func() bool {
658662
return coordinator.Node(agentID) != nil
@@ -665,6 +669,10 @@ func TestAgent(t *testing.T) {
665669

666670
t.Run("WriteVSCodeConfigs", func(t *testing.T) {
667671
t.Parallel()
672+
673+
coordinator := tailnet.NewCoordinator()
674+
defer coordinator.Close()
675+
668676
client := &client{
669677
t: t,
670678
agentID: uuid.New(),
@@ -673,7 +681,7 @@ func TestAgent(t *testing.T) {
673681
DERPMap: &tailcfg.DERPMap{},
674682
},
675683
statsChan: make(chan *codersdk.AgentStats),
676-
coordinator: tailnet.NewCoordinator(),
684+
coordinator: coordinator,
677685
}
678686
filesystem := afero.NewMemMapFs()
679687
closer := agent.New(agent.Options{
@@ -684,9 +692,8 @@ func TestAgent(t *testing.T) {
684692
Logger: slogtest.Make(t, nil).Leveled(slog.LevelInfo),
685693
Filesystem: filesystem,
686694
})
687-
t.Cleanup(func() {
688-
_ = closer.Close()
689-
})
695+
defer closer.Close()
696+
690697
home, err := os.UserHomeDir()
691698
require.NoError(t, err)
692699
path := filepath.Join(home, ".vscode-server", "data", "Machine", "settings.json")
@@ -749,6 +756,9 @@ func setupSSHSession(t *testing.T, options codersdk.WorkspaceAgentMetadata) *ssh
749756
})
750757
session, err := sshClient.NewSession()
751758
require.NoError(t, err)
759+
t.Cleanup(func() {
760+
_ = session.Close()
761+
})
752762
return session
753763
}
754764

@@ -767,6 +777,9 @@ func setupAgent(t *testing.T, metadata codersdk.WorkspaceAgentMetadata, ptyTimeo
767777
metadata.DERPMap = tailnettest.RunDERPAndSTUN(t)
768778
}
769779
coordinator := tailnet.NewCoordinator()
780+
t.Cleanup(func() {
781+
_ = coordinator.Close()
782+
})
770783
agentID := uuid.New()
771784
statsCh := make(chan *codersdk.AgentStats, 50)
772785
fs := afero.NewMemMapFs()
@@ -793,12 +806,17 @@ func setupAgent(t *testing.T, metadata codersdk.WorkspaceAgentMetadata, ptyTimeo
793806
})
794807
require.NoError(t, err)
795808
clientConn, serverConn := net.Pipe()
809+
serveClientDone := make(chan struct{})
796810
t.Cleanup(func() {
797811
_ = clientConn.Close()
798812
_ = serverConn.Close()
799813
_ = conn.Close()
814+
<-serveClientDone
800815
})
801-
go coordinator.ServeClient(serverConn, uuid.New(), agentID)
816+
go func() {
817+
defer close(serveClientDone)
818+
coordinator.ServeClient(serverConn, uuid.New(), agentID)
819+
}()
802820
sendNode, _ := tailnet.ServeCoordinator(clientConn, func(node []*tailnet.Node) error {
803821
return conn.UpdateNodes(node)
804822
})

cli/templateinit.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/spf13/cobra"
99

1010
"github.com/coder/coder/cli/cliui"
11+
"github.com/coder/coder/codersdk"
1112
"github.com/coder/coder/examples"
1213
"github.com/coder/coder/provisionersdk"
1314
)
@@ -22,7 +23,7 @@ func templateInit() *cobra.Command {
2223
return err
2324
}
2425
exampleNames := []string{}
25-
exampleByName := map[string]examples.Example{}
26+
exampleByName := map[string]codersdk.TemplateExample{}
2627
for _, example := range exampleList {
2728
name := fmt.Sprintf(
2829
"%s\n%s\n%s\n",

coderd/audit.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,9 @@ func (api *API) convertAuditLogs(ctx context.Context, dblogs []database.GetAudit
161161
}
162162

163163
type AdditionalFields struct {
164-
WorkspaceName string
165-
BuildNumber string
164+
WorkspaceName string
165+
BuildNumber string
166+
WorkspaceOwner string
166167
}
167168

168169
func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogsOffsetRow) codersdk.AuditLog {
@@ -198,8 +199,9 @@ func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogs
198199
if err != nil {
199200
api.Logger.Error(ctx, "unmarshal additional fields", slog.Error(err))
200201
resourceInfo := map[string]string{
201-
"workspaceName": "unknown",
202-
"buildNumber": "unknown",
202+
"workspaceName": "unknown",
203+
"buildNumber": "unknown",
204+
"workspaceOwner": "unknown",
203205
}
204206
dblog.AdditionalFields, err = json.Marshal(resourceInfo)
205207
api.Logger.Error(ctx, "marshal additional fields", slog.Error(err))
@@ -331,8 +333,12 @@ func auditLogResourceLink(alog database.GetAuditLogsOffsetRow, additionalFields
331333
return fmt.Sprintf("/users?filter=%s",
332334
alog.ResourceTarget)
333335
case database.ResourceTypeWorkspace:
336+
workspaceOwner := alog.UserUsername.String
337+
if len(additionalFields.WorkspaceOwner) != 0 && additionalFields.WorkspaceOwner != "unknown" {
338+
workspaceOwner = additionalFields.WorkspaceOwner
339+
}
334340
return fmt.Sprintf("/@%s/%s",
335-
alog.UserUsername.String, alog.ResourceTarget)
341+
workspaceOwner, alog.ResourceTarget)
336342
case database.ResourceTypeWorkspaceBuild:
337343
if len(additionalFields.WorkspaceName) == 0 || len(additionalFields.BuildNumber) == 0 {
338344
return ""

coderd/coderd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ func New(options *Options) *API {
355355
r.Post("/", api.postTemplateByOrganization)
356356
r.Get("/", api.templatesByOrganization)
357357
r.Get("/{templatename}", api.templateByOrganizationAndName)
358+
r.Get("/examples", api.templateExamples)
358359
})
359360
r.Route("/members", func(r chi.Router) {
360361
r.Get("/roles", api.assignableOrgRoles)

coderd/files.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ import (
1919
"github.com/coder/coder/codersdk"
2020
)
2121

22+
const (
23+
tarMimeType = "application/x-tar"
24+
)
25+
2226
func (api *API) postFile(rw http.ResponseWriter, r *http.Request) {
2327
ctx := r.Context()
2428
apiKey := httpmw.APIKey(r)
@@ -32,7 +36,7 @@ func (api *API) postFile(rw http.ResponseWriter, r *http.Request) {
3236
contentType := r.Header.Get("Content-Type")
3337

3438
switch contentType {
35-
case "application/x-tar":
39+
case tarMimeType:
3640
default:
3741
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
3842
Message: fmt.Sprintf("Unsupported content type header %q.", contentType),

coderd/templates.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/coder/coder/coderd/rbac"
2424
"github.com/coder/coder/coderd/telemetry"
2525
"github.com/coder/coder/codersdk"
26+
"github.com/coder/coder/examples"
2627
)
2728

2829
// Auto-importable templates. These can be auto-imported after the first user
@@ -564,6 +565,29 @@ func (api *API) templateDAUs(rw http.ResponseWriter, r *http.Request) {
564565
httpapi.Write(ctx, rw, http.StatusOK, resp)
565566
}
566567

568+
func (api *API) templateExamples(rw http.ResponseWriter, r *http.Request) {
569+
var (
570+
ctx = r.Context()
571+
organization = httpmw.OrganizationParam(r)
572+
)
573+
574+
if !api.Authorize(r, rbac.ActionRead, rbac.ResourceTemplate.InOrg(organization.ID)) {
575+
httpapi.ResourceNotFound(rw)
576+
return
577+
}
578+
579+
ex, err := examples.List()
580+
if err != nil {
581+
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
582+
Message: "Internal error fetching examples.",
583+
Detail: err.Error(),
584+
})
585+
return
586+
}
587+
588+
httpapi.Write(ctx, rw, http.StatusOK, ex)
589+
}
590+
567591
type autoImportTemplateOpts struct {
568592
name string
569593
archive []byte

0 commit comments

Comments
 (0)