From b0fe9bcdd1cd162d7ad1d5c3bb09553d8afe9007 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sun, 21 Aug 2022 17:32:53 -0500 Subject: [PATCH] chore: Upgrade to Go 1.19 (#3617) This is required as part of #3505. --- .github/workflows/coder.yaml | 16 ++++++++-------- .vscode/settings.json | 3 +++ agent/reaper/reaper_test.go | 1 + cli/cliflag/cliflag.go | 3 +-- cli/cliflag/cliflag_test.go | 1 + cli/configssh.go | 2 +- cli/delete_test.go | 1 + cli/gitssh_test.go | 1 + cli/publickey_test.go | 1 + cli/root_test.go | 1 + cli/server.go | 11 ++++++++--- cli/server_test.go | 7 +++++-- cli/userstatus_test.go | 3 +-- coderd/audit/diff.go | 1 + coderd/audit/diff_test.go | 1 + coderd/authorize.go | 1 + coderd/autobuild/notify/notifier.go | 20 ++++++++++---------- coderd/autobuild/schedule/schedule.go | 25 +++++++++++++------------ coderd/azureidentity/azureidentity.go | 2 ++ coderd/database/pubsub_test.go | 7 +------ coderd/devtunnel/tunnel_test.go | 11 ++++++++--- coderd/features_internal_test.go | 1 + coderd/httpmw/authorize_test.go | 4 +++- coderd/httpmw/oauth2_test.go | 1 + coderd/httpmw/prometheus_test.go | 1 + coderd/httpmw/ratelimit_test.go | 4 +++- coderd/pagination_internal_test.go | 3 ++- coderd/provisionerjobs_internal_test.go | 1 + coderd/rbac/authz.go | 1 + coderd/rbac/authz_internal_test.go | 3 ++- coderd/rbac/builtin.go | 4 +++- coderd/rbac/builtin_test.go | 2 ++ coderd/roles_test.go | 2 +- coderd/telemetry/telemetry.go | 2 ++ coderd/templateversions_test.go | 2 +- coderd/userauth_test.go | 6 ++++-- coderd/users_test.go | 8 ++++---- coderd/workspaceapps_test.go | 2 ++ coderd/workspaces_test.go | 2 +- coderd/wsconncache/wsconncache_test.go | 6 ++++-- cryptorand/errors_test.go | 1 + cryptorand/numbers.go | 1 + dogfood/Dockerfile | 25 ++++++++++++------------- go.mod | 2 +- peer/conn_test.go | 1 + peerbroker/proto/peerbroker.pb.go | 1 + peerbroker/proxy.go | 13 ++++++++----- provisioner/terraform/provision_test.go | 3 +-- provisionerd/proto/provisionerd.pb.go | 3 +++ provisionersdk/proto/provisioner.pb.go | 4 ++++ scripts/apitypings/main.go | 1 + site/site_test.go | 1 + 52 files changed, 144 insertions(+), 86 deletions(-) diff --git a/.github/workflows/coder.yaml b/.github/workflows/coder.yaml index c20411005d..f64424d98c 100644 --- a/.github/workflows/coder.yaml +++ b/.github/workflows/coder.yaml @@ -96,11 +96,11 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: "~1.18" + go-version: "~1.19" - name: golangci-lint uses: golangci/golangci-lint-action@v3.2.0 with: - version: v1.46.0 + version: v1.48.0 check-enterprise-imports: name: check/enterprise-imports @@ -199,7 +199,7 @@ jobs: version: "3.20.0" - uses: actions/setup-go@v3 with: - go-version: "~1.18" + go-version: "~1.19" - name: Echo Go Cache Paths id: go-cache-paths @@ -283,7 +283,7 @@ jobs: - uses: actions/setup-go@v3 with: - go-version: "~1.18" + go-version: "~1.19" - name: Echo Go Cache Paths id: go-cache-paths @@ -370,7 +370,7 @@ jobs: - uses: actions/setup-go@v3 with: - go-version: "~1.18" + go-version: "~1.19" - name: Echo Go Cache Paths id: go-cache-paths @@ -453,7 +453,7 @@ jobs: - uses: actions/setup-go@v3 with: - go-version: "~1.18" + go-version: "~1.19" - name: Echo Go Cache Paths id: go-cache-paths @@ -558,7 +558,7 @@ jobs: # Go is required for uploading the test results to datadog - uses: actions/setup-go@v3 with: - go-version: "~1.18" + go-version: "~1.19" - uses: actions/setup-node@v3 with: @@ -616,7 +616,7 @@ jobs: # Go is required for uploading the test results to datadog - uses: actions/setup-go@v3 with: - go-version: "~1.18" + go-version: "~1.19" - uses: hashicorp/setup-terraform@v2 with: diff --git a/.vscode/settings.json b/.vscode/settings.json index f4d9255c0b..81965c4261 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,7 @@ "cSpell.words": [ "apps", "awsidentity", + "bodyclose", "buildinfo", "buildname", "circbuf", @@ -52,6 +53,7 @@ "ntqry", "OIDC", "oneof", + "paralleltest", "parameterscopeid", "pqtype", "prometheusmetrics", @@ -80,6 +82,7 @@ "tfjson", "tfplan", "tfstate", + "tparallel", "trimprefix", "turnconn", "typegen", diff --git a/agent/reaper/reaper_test.go b/agent/reaper/reaper_test.go index 88573636ee..867bcfa574 100644 --- a/agent/reaper/reaper_test.go +++ b/agent/reaper/reaper_test.go @@ -29,6 +29,7 @@ func TestReap(t *testing.T) { // exited processes and passing the PIDs through the shared // channel. t.Run("OK", func(t *testing.T) { + t.Parallel() pids := make(reap.PidCh, 1) err := reaper.ForkReap( reaper.WithPIDCallback(pids), diff --git a/cli/cliflag/cliflag.go b/cli/cliflag/cliflag.go index 053ea948f0..843416c3ff 100644 --- a/cli/cliflag/cliflag.go +++ b/cli/cliflag/cliflag.go @@ -6,8 +6,7 @@ // // Will produce the following usage docs: // -// -a, --address string The address to serve the API and dashboard (uses $CODER_ADDRESS). (default "127.0.0.1:3000") -// +// -a, --address string The address to serve the API and dashboard (uses $CODER_ADDRESS). (default "127.0.0.1:3000") package cliflag import ( diff --git a/cli/cliflag/cliflag_test.go b/cli/cliflag/cliflag_test.go index a5c9f532ab..acdf7d6765 100644 --- a/cli/cliflag/cliflag_test.go +++ b/cli/cliflag/cliflag_test.go @@ -14,6 +14,7 @@ import ( ) // Testcliflag cannot run in parallel because it uses t.Setenv. +// //nolint:paralleltest func TestCliflag(t *testing.T) { t.Run("StringDefault", func(t *testing.T) { diff --git a/cli/configssh.go b/cli/configssh.go index 08aeaf6c9d..a3f9a4517c 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -558,7 +558,7 @@ func currentBinPath(w io.Writer) (string, error) { // diffBytes takes two byte slices and diffs them as if they were in a // file named name. -//nolint: revive // Color is an option, not a control coupling. +// nolint: revive // Color is an option, not a control coupling. func diffBytes(name string, b1, b2 []byte, color bool) ([]byte, error) { var buf bytes.Buffer var opts []write.Option diff --git a/cli/delete_test.go b/cli/delete_test.go index c8039d454f..a2ea15fd18 100644 --- a/cli/delete_test.go +++ b/cli/delete_test.go @@ -15,6 +15,7 @@ import ( ) func TestDelete(t *testing.T) { + t.Parallel() t.Run("WithParameter", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true}) diff --git a/cli/gitssh_test.go b/cli/gitssh_test.go index ff15e145e4..4a6e571502 100644 --- a/cli/gitssh_test.go +++ b/cli/gitssh_test.go @@ -22,6 +22,7 @@ import ( func TestGitSSH(t *testing.T) { t.Parallel() t.Run("Dial", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true}) user := coderdtest.CreateFirstUser(t, client) diff --git a/cli/publickey_test.go b/cli/publickey_test.go index cd2ab35486..f0bef2c653 100644 --- a/cli/publickey_test.go +++ b/cli/publickey_test.go @@ -13,6 +13,7 @@ import ( func TestPublicKey(t *testing.T) { t.Parallel() t.Run("OK", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t, nil) _ = coderdtest.CreateFirstUser(t, client) cmd, root := clitest.New(t, "publickey") diff --git a/cli/root_test.go b/cli/root_test.go index 5dc97bb060..04a9b2c99e 100644 --- a/cli/root_test.go +++ b/cli/root_test.go @@ -15,6 +15,7 @@ import ( ) func TestRoot(t *testing.T) { + t.Parallel() t.Run("FormatCobraError", func(t *testing.T) { t.Parallel() diff --git a/cli/server.go b/cli/server.go index 126ea0bc82..9a9d464b4c 100644 --- a/cli/server.go +++ b/cli/server.go @@ -475,8 +475,9 @@ func server() *cobra.Command { server := &http.Server{ // These errors are typically noise like "TLS: EOF". Vault does similar: // https://github.com/hashicorp/vault/blob/e2490059d0711635e529a4efcbaa1b26998d6e1c/command/server.go#L2714 - ErrorLog: log.New(io.Discard, "", 0), - Handler: coderAPI.Handler, + ErrorLog: log.New(io.Discard, "", 0), + Handler: coderAPI.Handler, + ReadHeaderTimeout: time.Minute, BaseContext: func(_ net.Listener) context.Context { return shutdownConnsCtx }, @@ -1080,7 +1081,11 @@ func configureGithubOAuth2(accessURL *url.URL, clientID, clientSecret string, al func serveHandler(ctx context.Context, logger slog.Logger, handler http.Handler, addr, name string) (closeFunc func()) { logger.Debug(ctx, "http server listening", slog.F("addr", addr), slog.F("name", name)) - srv := &http.Server{Addr: addr, Handler: handler} + srv := &http.Server{ + Addr: addr, + Handler: handler, + ReadHeaderTimeout: time.Minute, + } go func() { err := srv.ListenAndServe() if err != nil && !xerrors.Is(err, http.ErrServerClosed) { diff --git a/cli/server_test.go b/cli/server_test.go index 66303339bb..7dd7324381 100644 --- a/cli/server_test.go +++ b/cli/server_test.go @@ -39,7 +39,7 @@ import ( ) // This cannot be ran in parallel because it uses a signal. -// nolint:paralleltest +// nolint:tparallel,paralleltest func TestServer(t *testing.T) { t.Run("Production", func(t *testing.T) { if runtime.GOOS != "linux" || testing.Short() { @@ -410,6 +410,7 @@ func TestServer(t *testing.T) { require.Eventually(t, func() bool { req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("http://127.0.0.1:%d", randomPort), nil) assert.NoError(t, err) + // nolint:bodyclose res, err = http.DefaultClient.Do(req) return err == nil }, testutil.WaitShort, testutil.IntervalFast) @@ -461,7 +462,9 @@ func TestServer(t *testing.T) { } githubURL, err := accessURL.Parse("/api/v2/users/oauth2/github") require.NoError(t, err) - res, err := client.HTTPClient.Get(githubURL.String()) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, githubURL.String(), nil) + require.NoError(t, err) + res, err := client.HTTPClient.Do(req) require.NoError(t, err) defer res.Body.Close() fakeURL, err := res.Location() diff --git a/cli/userstatus_test.go b/cli/userstatus_test.go index 700c08616d..aea26f8387 100644 --- a/cli/userstatus_test.go +++ b/cli/userstatus_test.go @@ -12,6 +12,7 @@ import ( "github.com/coder/coder/codersdk" ) +// nolint:tparallel,paralleltest func TestUserStatus(t *testing.T) { t.Parallel() client := coderdtest.New(t, nil) @@ -20,7 +21,6 @@ func TestUserStatus(t *testing.T) { otherUser, err := other.User(context.Background(), codersdk.Me) require.NoError(t, err, "fetch user") - //nolint:paralleltest t.Run("StatusSelf", func(t *testing.T) { cmd, root := clitest.New(t, "users", "suspend", "me") clitest.SetupConfig(t, client, root) @@ -32,7 +32,6 @@ func TestUserStatus(t *testing.T) { require.ErrorContains(t, err, "cannot suspend yourself") }) - //nolint:paralleltest t.Run("StatusOther", func(t *testing.T) { require.Equal(t, otherUser.Status, codersdk.UserStatusActive, "start as active") diff --git a/coderd/audit/diff.go b/coderd/audit/diff.go index eb500891b9..efb8d87548 100644 --- a/coderd/audit/diff.go +++ b/coderd/audit/diff.go @@ -99,6 +99,7 @@ func diffValues[T any](left, right T, table Table) Map { } // convertDiffType converts external struct types to primitive types. +// //nolint:forcetypeassert func convertDiffType(left, right any) (newLeft, newRight any, changed bool) { switch typed := left.(type) { diff --git a/coderd/audit/diff_test.go b/coderd/audit/diff_test.go index fc9c41b7cb..0e90d8c30d 100644 --- a/coderd/audit/diff_test.go +++ b/coderd/audit/diff_test.go @@ -230,6 +230,7 @@ func runDiffTests[T audit.Auditable](t *testing.T, tests []diffTest[T]) { for _, test := range tests { t.Run(typName+"/"+test.name, func(t *testing.T) { + t.Parallel() require.Equal(t, test.exp, audit.Diff(test.left, test.right), diff --git a/coderd/authorize.go b/coderd/authorize.go index 855348aaf6..981af5e868 100644 --- a/coderd/authorize.go +++ b/coderd/authorize.go @@ -31,6 +31,7 @@ func AuthorizeFilter[O rbac.Objecter](api *API, r *http.Request, action rbac.Act // This function will log appropriately, but the caller must return an // error to the api client. // Eg: +// // if !api.Authorize(...) { // httpapi.Forbidden(rw) // return diff --git a/coderd/autobuild/notify/notifier.go b/coderd/autobuild/notify/notifier.go index f7e1058aee..e0db12af35 100644 --- a/coderd/autobuild/notify/notifier.go +++ b/coderd/autobuild/notify/notifier.go @@ -20,14 +20,14 @@ type Notifier struct { } // Condition is a function that gets executed with a certain time. -// - It should return the deadline for the notification, as well as a -// callback function to execute once the time to the deadline is -// less than one of the notify attempts. If deadline is the zero -// time, callback will not be executed. -// - Callback is executed once for every time the difference between deadline -// and the current time is less than an element of countdown. -// - To enforce a minimum interval between consecutive callbacks, truncate -// the returned deadline to the minimum interval. +// - It should return the deadline for the notification, as well as a +// callback function to execute once the time to the deadline is +// less than one of the notify attempts. If deadline is the zero +// time, callback will not be executed. +// - Callback is executed once for every time the difference between deadline +// and the current time is less than an element of countdown. +// - To enforce a minimum interval between consecutive callbacks, truncate +// the returned deadline to the minimum interval. type Condition func(now time.Time) (deadline time.Time, callback func()) // Notify is a convenience function that initializes a new Notifier @@ -44,8 +44,8 @@ func Notify(cond Condition, interval time.Duration, countdown ...time.Duration) } // New returns a Notifier that calls cond once every time it polls. -// - Duplicate values are removed from countdown, and it is sorted in -// descending order. +// - Duplicate values are removed from countdown, and it is sorted in +// descending order. func New(cond Condition, countdown ...time.Duration) *Notifier { // Ensure countdown is sorted in descending order and contains no duplicates. ct := unique(countdown) diff --git a/coderd/autobuild/schedule/schedule.go b/coderd/autobuild/schedule/schedule.go index 43afcf2223..59433450c0 100644 --- a/coderd/autobuild/schedule/schedule.go +++ b/coderd/autobuild/schedule/schedule.go @@ -28,13 +28,14 @@ var defaultParser = cron.NewParser(parserFormat) // - day of week e.g. 1 (required) // // Example Usage: -// local_sched, _ := schedule.Weekly("59 23 *") -// fmt.Println(sched.Next(time.Now().Format(time.RFC3339))) -// // Output: 2022-04-04T23:59:00Z // -// us_sched, _ := schedule.Weekly("CRON_TZ=US/Central 30 9 1-5") -// fmt.Println(sched.Next(time.Now()).Format(time.RFC3339)) -// // Output: 2022-04-04T14:30:00Z +// local_sched, _ := schedule.Weekly("59 23 *") +// fmt.Println(sched.Next(time.Now().Format(time.RFC3339))) +// // Output: 2022-04-04T23:59:00Z +// +// us_sched, _ := schedule.Weekly("CRON_TZ=US/Central 30 9 1-5") +// fmt.Println(sched.Next(time.Now()).Format(time.RFC3339)) +// // Output: 2022-04-04T14:30:00Z func Weekly(raw string) (*Schedule, error) { if err := validateWeeklySpec(raw); err != nil { return nil, xerrors.Errorf("validate weekly schedule: %w", err) @@ -115,12 +116,12 @@ var tMax = t0.Add(168 * time.Hour) // Min returns the minimum duration of the schedule. // This is calculated as follows: -// - Let t(0) be a given point in time (1970-01-01T01:01:01Z00:00) -// - Let t(max) be 168 hours after t(0). -// - Let t(1) be the next scheduled time after t(0). -// - Let t(n) be the next scheduled time after t(n-1). -// - Then, the minimum duration of s d(min) -// = min( t(n) - t(n-1) ∀ n ∈ N, t(n) < t(max) ) +// - Let t(0) be a given point in time (1970-01-01T01:01:01Z00:00) +// - Let t(max) be 168 hours after t(0). +// - Let t(1) be the next scheduled time after t(0). +// - Let t(n) be the next scheduled time after t(n-1). +// - Then, the minimum duration of s d(min) +// = min( t(n) - t(n-1) ∀ n ∈ N, t(n) < t(max) ) func (s Schedule) Min() time.Duration { durMin := tMax.Sub(t0) tPrev := s.Next(t0) diff --git a/coderd/azureidentity/azureidentity.go b/coderd/azureidentity/azureidentity.go index d80c60367d..b1161edfc8 100644 --- a/coderd/azureidentity/azureidentity.go +++ b/coderd/azureidentity/azureidentity.go @@ -52,8 +52,10 @@ func Validate(ctx context.Context, signature string, options x509.VerifyOptions) } data, err := io.ReadAll(res.Body) if err != nil { + _ = res.Body.Close() return "", xerrors.Errorf("read body %q: %w", certURL, err) } + _ = res.Body.Close() cert, err := x509.ParseCertificate(data) if err != nil { return "", xerrors.Errorf("parse certificate %q: %w", certURL, err) diff --git a/coderd/database/pubsub_test.go b/coderd/database/pubsub_test.go index 558b4e5650..c1377b69aa 100644 --- a/coderd/database/pubsub_test.go +++ b/coderd/database/pubsub_test.go @@ -14,6 +14,7 @@ import ( "github.com/coder/coder/coderd/database/postgres" ) +// nolint:tparallel,paralleltest func TestPubsub(t *testing.T) { t.Parallel() @@ -22,10 +23,7 @@ func TestPubsub(t *testing.T) { return } - // nolint:paralleltest t.Run("Postgres", func(t *testing.T) { - // postgres.Open() seems to be creating race conditions when run in parallel. - // t.Parallel() ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() @@ -54,10 +52,7 @@ func TestPubsub(t *testing.T) { assert.Equal(t, string(message), data) }) - // nolint:paralleltest t.Run("PostgresCloseCancel", func(t *testing.T) { - // postgres.Open() seems to be creating race conditions when run in parallel. - // t.Parallel() ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() connectionURL, closePg, err := postgres.Open() diff --git a/coderd/devtunnel/tunnel_test.go b/coderd/devtunnel/tunnel_test.go index 23dd92d966..9bf435ce32 100644 --- a/coderd/devtunnel/tunnel_test.go +++ b/coderd/devtunnel/tunnel_test.go @@ -52,6 +52,7 @@ func TestTunnel(t *testing.T) { defer cancelTun() server := http.Server{ + ReadHeaderTimeout: time.Minute, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { t.Log("got request for", r.URL) // Going to use something _slightly_ exotic so that we can't accidentally get some @@ -100,8 +101,8 @@ func TestTunnel(t *testing.T) { // fakeTunnelServer is a fake version of the real dev tunnel server. It fakes 2 client interactions // that we want to test: -// 1. Responding to a POST /tun from the client -// 2. Sending an HTTP request down the wireguard connection +// 1. Responding to a POST /tun from the client +// 2. Sending an HTTP request down the wireguard connection // // Note that for 2, we don't implement a full proxy that accepts arbitrary requests, we just send // a test request over the Wireguard tunnel to make sure that we can listen. The proxy behavior is @@ -229,5 +230,9 @@ func (f *fakeTunnelServer) requestHTTP() (*http.Response, error) { Transport: transport, Timeout: testutil.WaitLong, } - return client.Get(fmt.Sprintf("http://[%s]:8090", clientIP)) + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, fmt.Sprintf("http://[%s]:8090", clientIP), nil) + if err != nil { + return nil, err + } + return client.Do(req) } diff --git a/coderd/features_internal_test.go b/coderd/features_internal_test.go index d8480899c6..50c7e8f53e 100644 --- a/coderd/features_internal_test.go +++ b/coderd/features_internal_test.go @@ -20,6 +20,7 @@ func TestEntitlements(t *testing.T) { rw := httptest.NewRecorder() entitlements(rw, r) resp := rw.Result() + defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) dec := json.NewDecoder(resp.Body) var result codersdk.Entitlements diff --git a/coderd/httpmw/authorize_test.go b/coderd/httpmw/authorize_test.go index 14ab961106..dcae5bff96 100644 --- a/coderd/httpmw/authorize_test.go +++ b/coderd/httpmw/authorize_test.go @@ -99,7 +99,9 @@ func TestExtractUserRoles(t *testing.T) { }) rtr.ServeHTTP(rw, req) - require.Equal(t, http.StatusOK, rw.Result().StatusCode) + resp := rw.Result() + defer resp.Body.Close() + require.Equal(t, http.StatusOK, resp.StatusCode) }) } } diff --git a/coderd/httpmw/oauth2_test.go b/coderd/httpmw/oauth2_test.go index 771dcdd772..dd5c7c6bc7 100644 --- a/coderd/httpmw/oauth2_test.go +++ b/coderd/httpmw/oauth2_test.go @@ -32,6 +32,7 @@ func (*testOAuth2Provider) TokenSource(_ context.Context, _ *oauth2.Token) oauth return nil } +// nolint:bodyclose func TestOAuth2(t *testing.T) { t.Parallel() t.Run("NotSetup", func(t *testing.T) { diff --git a/coderd/httpmw/prometheus_test.go b/coderd/httpmw/prometheus_test.go index 1ab93cef06..97c5575406 100644 --- a/coderd/httpmw/prometheus_test.go +++ b/coderd/httpmw/prometheus_test.go @@ -17,6 +17,7 @@ import ( func TestPrometheus(t *testing.T) { t.Parallel() t.Run("All", func(t *testing.T) { + t.Parallel() req := httptest.NewRequest("GET", "/", nil) req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, chi.NewRouteContext())) res := chimw.NewWrapResponseWriter(httptest.NewRecorder(), 0) diff --git a/coderd/httpmw/ratelimit_test.go b/coderd/httpmw/ratelimit_test.go index 132615d669..3ed0178a16 100644 --- a/coderd/httpmw/ratelimit_test.go +++ b/coderd/httpmw/ratelimit_test.go @@ -26,7 +26,9 @@ func TestRateLimit(t *testing.T) { req := httptest.NewRequest("GET", "/", nil) rec := httptest.NewRecorder() rtr.ServeHTTP(rec, req) - return rec.Result().StatusCode == http.StatusTooManyRequests + resp := rec.Result() + defer resp.Body.Close() + return resp.StatusCode == http.StatusTooManyRequests }, testutil.WaitShort, testutil.IntervalFast) }) } diff --git a/coderd/pagination_internal_test.go b/coderd/pagination_internal_test.go index 978cfab417..d1e6bd107c 100644 --- a/coderd/pagination_internal_test.go +++ b/coderd/pagination_internal_test.go @@ -1,6 +1,7 @@ package coderd import ( + "context" "encoding/json" "net/http" "net/http/httptest" @@ -93,7 +94,7 @@ func TestPagination(t *testing.T) { t.Run(c.Name, func(t *testing.T) { t.Parallel() rw := httptest.NewRecorder() - r, err := http.NewRequest("GET", "https://example.com", nil) + r, err := http.NewRequestWithContext(context.Background(), "GET", "https://example.com", nil) require.NoError(t, err, "new request") // Set query params diff --git a/coderd/provisionerjobs_internal_test.go b/coderd/provisionerjobs_internal_test.go index da593e68f9..80a94f88fc 100644 --- a/coderd/provisionerjobs_internal_test.go +++ b/coderd/provisionerjobs_internal_test.go @@ -28,6 +28,7 @@ func TestProvisionerJobLogs_Unit(t *testing.T) { t.Parallel() t.Run("QueryPubSubDupes", func(t *testing.T) { + t.Parallel() logger := slogtest.Make(t, nil).Leveled(slog.LevelDebug) // mDB := mocks.NewStore(t) fDB := databasefake.New() diff --git a/coderd/rbac/authz.go b/coderd/rbac/authz.go index 4b99c29438..d124aae29b 100644 --- a/coderd/rbac/authz.go +++ b/coderd/rbac/authz.go @@ -54,6 +54,7 @@ type RegoAuthorizer struct { } // Load the policy from policy.rego in this directory. +// //go:embed policy.rego var policy string diff --git a/coderd/rbac/authz_internal_test.go b/coderd/rbac/authz_internal_test.go index a3aca022c7..b91130d0f4 100644 --- a/coderd/rbac/authz_internal_test.go +++ b/coderd/rbac/authz_internal_test.go @@ -491,8 +491,8 @@ func TestAuthorizeDomain(t *testing.T) { } // TestAuthorizeLevels ensures level overrides are acting appropriately -//nolint:paralleltest func TestAuthorizeLevels(t *testing.T) { + t.Parallel() defOrg := uuid.New() unusedID := uuid.New() @@ -638,6 +638,7 @@ func testAuthorize(t *testing.T, name string, subject subject, sets ...[]authTes for _, cases := range sets { for _, c := range cases { t.Run(name, func(t *testing.T) { + t.Parallel() for _, a := range c.actions { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) t.Cleanup(cancel) diff --git a/coderd/rbac/builtin.go b/coderd/rbac/builtin.go index bfa6ded0a5..d2a52511df 100644 --- a/coderd/rbac/builtin.go +++ b/coderd/rbac/builtin.go @@ -361,7 +361,9 @@ func ChangeRoleSet(from []string, to []string) (added []string, removed []string } // roleName is a quick helper function to return -// role_name:scopeID +// +// role_name:scopeID +// // If no scopeID is required, only 'role_name' is returned func roleName(name string, orgID string) string { if orgID == "" { diff --git a/coderd/rbac/builtin_test.go b/coderd/rbac/builtin_test.go index bbedc1e485..d357271943 100644 --- a/coderd/rbac/builtin_test.go +++ b/coderd/rbac/builtin_test.go @@ -13,6 +13,7 @@ import ( ) // BenchmarkRBACFilter benchmarks the rbac.Filter method. +// // go test -bench BenchmarkRBACFilter -benchmem -memprofile memprofile.out -cpuprofile profile.out func BenchmarkRBACFilter(b *testing.B) { orgs := []uuid.UUID{ @@ -392,6 +393,7 @@ func TestIsOrgRole(t *testing.T) { // nolint:paralleltest for _, c := range testCases { t.Run(c.RoleName, func(t *testing.T) { + t.Parallel() orgID, ok := rbac.IsOrgRole(c.RoleName) require.Equal(t, c.OrgRole, ok, "match expected org role") require.Equal(t, c.OrgID, orgID, "match expected org id") diff --git a/coderd/roles_test.go b/coderd/roles_test.go index 034be6a6bb..27b5bc9df6 100644 --- a/coderd/roles_test.go +++ b/coderd/roles_test.go @@ -112,7 +112,7 @@ func TestListRoles(t *testing.T) { orgAdmin := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID, rbac.RoleOrgAdmin(admin.OrganizationID)) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() + t.Cleanup(cancel) otherOrg, err := client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{ Name: "other", diff --git a/coderd/telemetry/telemetry.go b/coderd/telemetry/telemetry.go index d4b6d42db8..d44166635c 100644 --- a/coderd/telemetry/telemetry.go +++ b/coderd/telemetry/telemetry.go @@ -133,6 +133,7 @@ func (r *remoteReporter) reportSync(snapshot *Snapshot) { r.options.Logger.Debug(r.ctx, "submit", slog.Error(err)) return } + defer resp.Body.Close() if resp.StatusCode != http.StatusAccepted { r.options.Logger.Debug(r.ctx, "bad response from telemetry server", slog.F("status", resp.StatusCode)) return @@ -261,6 +262,7 @@ func (r *remoteReporter) deployment() error { if err != nil { return xerrors.Errorf("perform request: %w", err) } + defer resp.Body.Close() if resp.StatusCode != http.StatusAccepted { return xerrors.Errorf("update deployment: %w", err) } diff --git a/coderd/templateversions_test.go b/coderd/templateversions_test.go index fa29c976de..6187da3707 100644 --- a/coderd/templateversions_test.go +++ b/coderd/templateversions_test.go @@ -818,7 +818,7 @@ func TestPaginatedTemplateVersions(t *testing.T) { // This test takes longer than a long time. ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong*2) - defer cancel() + t.Cleanup(cancel) // Populate database with template versions. total := 9 diff --git a/coderd/userauth_test.go b/coderd/userauth_test.go index f1768b588d..a1e850a090 100644 --- a/coderd/userauth_test.go +++ b/coderd/userauth_test.go @@ -76,6 +76,7 @@ func TestUserAuthMethods(t *testing.T) { }) } +// nolint:bodyclose func TestUserOAuth2Github(t *testing.T) { t.Parallel() t.Run("NotInAllowedOrganization", func(t *testing.T) { @@ -281,6 +282,7 @@ func TestUserOAuth2Github(t *testing.T) { }) } +// nolint:bodyclose func TestUserOIDC(t *testing.T) { t.Parallel() @@ -456,7 +458,7 @@ func oauth2Callback(t *testing.T, client *codersdk.Client) *http.Response { state := "somestate" oauthURL, err := client.URL.Parse("/api/v2/users/oauth2/github/callback?code=asd&state=" + state) require.NoError(t, err) - req, err := http.NewRequest("GET", oauthURL.String(), nil) + req, err := http.NewRequestWithContext(context.Background(), "GET", oauthURL.String(), nil) require.NoError(t, err) req.AddCookie(&http.Cookie{ Name: codersdk.OAuth2StateKey, @@ -478,7 +480,7 @@ func oidcCallback(t *testing.T, client *codersdk.Client) *http.Response { state := "somestate" oauthURL, err := client.URL.Parse("/api/v2/users/oidc/callback?code=asd&state=" + state) require.NoError(t, err) - req, err := http.NewRequest("GET", oauthURL.String(), nil) + req, err := http.NewRequestWithContext(context.Background(), "GET", oauthURL.String(), nil) require.NoError(t, err) req.AddCookie(&http.Cookie{ Name: codersdk.OAuth2StateKey, diff --git a/coderd/users_test.go b/coderd/users_test.go index bf372f01f1..c813e7bcc7 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -477,7 +477,7 @@ func TestGrantSiteRoles(t *testing.T) { } ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() + t.Cleanup(cancel) var err error admin := coderdtest.New(t, nil) @@ -734,7 +734,7 @@ func TestUsersFilter(t *testing.T) { first := coderdtest.CreateFirstUser(t, client) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() + t.Cleanup(cancel) firstUser, err := client.User(ctx, codersdk.Me) require.NoError(t, err, "fetch me") @@ -1075,7 +1075,7 @@ func TestSuspendedPagination(t *testing.T) { coderdtest.CreateFirstUser(t, client) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() + t.Cleanup(cancel) me, err := client.User(ctx, codersdk.Me) require.NoError(t, err) @@ -1121,7 +1121,7 @@ func TestPaginatedUsers(t *testing.T) { // This test takes longer than a long time. ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong*2) - defer cancel() + t.Cleanup(cancel) me, err := client.User(ctx, codersdk.Me) require.NoError(t, err) diff --git a/coderd/workspaceapps_test.go b/coderd/workspaceapps_test.go index 76aa335106..d17a5e95cc 100644 --- a/coderd/workspaceapps_test.go +++ b/coderd/workspaceapps_test.go @@ -7,6 +7,7 @@ import ( "net" "net/http" "testing" + "time" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -27,6 +28,7 @@ func TestWorkspaceAppsProxyPath(t *testing.T) { ln, err := net.Listen("tcp", ":0") require.NoError(t, err) server := http.Server{ + ReadHeaderTimeout: time.Minute, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, err := r.Cookie(codersdk.SessionTokenKey) assert.ErrorIs(t, err, http.ErrNoCookie) diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 3c4acc52f4..db47eb796b 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -402,7 +402,7 @@ func TestWorkspaceFilter(t *testing.T) { first := coderdtest.CreateFirstUser(t, client) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() + t.Cleanup(cancel) users := make([]coderUser, 0) for i := 0; i < 10; i++ { diff --git a/coderd/wsconncache/wsconncache_test.go b/coderd/wsconncache/wsconncache_test.go index 46e7df383e..452c516c8a 100644 --- a/coderd/wsconncache/wsconncache_test.go +++ b/coderd/wsconncache/wsconncache_test.go @@ -94,6 +94,7 @@ func TestCache(t *testing.T) { require.True(t, valid) server := &http.Server{ + ReadHeaderTimeout: time.Minute, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }), @@ -131,8 +132,9 @@ func TestCache(t *testing.T) { proxy.Transport = conn.HTTPTransport() res := httptest.NewRecorder() proxy.ServeHTTP(res, req) - res.Result().Body.Close() - assert.Equal(t, http.StatusOK, res.Result().StatusCode) + resp := res.Result() + defer resp.Body.Close() + assert.Equal(t, http.StatusOK, resp.StatusCode) }() } wg.Wait() diff --git a/cryptorand/errors_test.go b/cryptorand/errors_test.go index f228ebd289..ab0fabdd1e 100644 --- a/cryptorand/errors_test.go +++ b/cryptorand/errors_test.go @@ -15,6 +15,7 @@ import ( // the rand.Reader. // // This test replaces the global rand.Reader, so cannot be parallelized +// //nolint:paralleltest func TestRandError(t *testing.T) { var origReader = rand.Reader diff --git a/cryptorand/numbers.go b/cryptorand/numbers.go index f840cd5c3f..0059203ff3 100644 --- a/cryptorand/numbers.go +++ b/cryptorand/numbers.go @@ -110,6 +110,7 @@ func Int31n(max int32) (int32, error) { // set, regenerating v if necessary. n must be > 0. All input bits in v must be // fully random, you cannot cast a random uint8/uint16 for input into this // function. +// //nolint:varnamelen func UnbiasedModulo32(v uint32, n int32) (int32, error) { prod := uint64(v) * uint64(n) diff --git a/dogfood/Dockerfile b/dogfood/Dockerfile index ad03b25111..4703a67e63 100644 --- a/dogfood/Dockerfile +++ b/dogfood/Dockerfile @@ -8,17 +8,17 @@ FROM ubuntu AS go RUN apt-get update && apt-get install --yes curl gcc # Install Go manually, so that we can control the version -ARG GOBORING_VERSION=1.18b7 -RUN mkdir --parents /usr/local/go /usr/local/goboring +ARG GO_VERSION=1.19 +RUN mkdir --parents /usr/local/go # Boring Go is needed to build FIPS-compliant binaries. RUN curl --silent --show-error --location \ - "https://storage.googleapis.com/go-boringcrypto/go${GOBORING_VERSION}.linux-amd64.tar.gz" \ - -o /usr/local/goboring.tar.gz + "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" \ + -o /usr/local/go.tar.gz -RUN tar --extract --gzip --directory=/usr/local/goboring --file=/usr/local/goboring.tar.gz --strip-components=1 +RUN tar --extract --gzip --directory=/usr/local/go --file=/usr/local/go.tar.gz --strip-components=1 -ENV PATH=$PATH:/usr/local/goboring/bin +ENV PATH=$PATH:/usr/local/go/bin # Install Go utilities. ARG GOPATH="/tmp/" @@ -196,7 +196,7 @@ RUN systemctl enable \ ARG CLOUD_SQL_PROXY_VERSION=1.26.0 \ DIVE_VERSION=0.10.0 \ DOCKER_GCR_VERSION=2.1.0 \ - GOLANGCI_LINT_VERSION=1.44.2 \ + GOLANGCI_LINT_VERSION=1.48.0 \ GRYPE_VERSION=0.24.0 \ HELM_VERSION=3.8.0 \ KUBE_LINTER_VERSION=0.2.5 \ @@ -290,14 +290,13 @@ RUN echo "PermitUserEnvironment yes" >>/etc/ssh/sshd_config && \ # We avoid copying the extracted directory since COPY slows to minutes when there # are a lot of small files. -COPY --from=go /usr/local/goboring.tar.gz /usr/local/goboring.tar.gz -RUN mkdir /usr/local/goboring && \ - tar --extract --gzip --directory=/usr/local/goboring --file=/usr/local/goboring.tar.gz --strip-components=1 +COPY --from=go /usr/local/go.tar.gz /usr/local/go.tar.gz +RUN mkdir /usr/local/go && \ + tar --extract --gzip --directory=/usr/local/go --file=/usr/local/go.tar.gz --strip-components=1 -ENV PATH=$PATH:/usr/local/goboring/bin +ENV PATH=$PATH:/usr/local/go/bin -# Ensure goboring is made the default Go -RUN update-alternatives --install /usr/local/bin/gofmt gofmt /usr/local/goboring/bin/gofmt 100 +RUN update-alternatives --install /usr/local/bin/gofmt gofmt /usr/local/go/bin/gofmt 100 COPY --from=go /tmp/bin /usr/local/bin diff --git a/go.mod b/go.mod index 4b8c596c4b..38163dd09a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/coder/coder -go 1.18 +go 1.19 // Required until https://github.com/manifoldco/promptui/pull/169 is merged. replace github.com/manifoldco/promptui => github.com/kylecarbs/promptui v0.8.1-0.20201231190244-d8f2159af2b2 diff --git a/peer/conn_test.go b/peer/conn_test.go index 6e2de345f0..992765b940 100644 --- a/peer/conn_test.go +++ b/peer/conn_test.go @@ -226,6 +226,7 @@ func TestConn(t *testing.T) { }() go func() { server := http.Server{ + ReadHeaderTimeout: time.Minute, Handler: http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { rw.WriteHeader(200) }), diff --git a/peerbroker/proto/peerbroker.pb.go b/peerbroker/proto/peerbroker.pb.go index 931d1c799b..498d250a14 100644 --- a/peerbroker/proto/peerbroker.pb.go +++ b/peerbroker/proto/peerbroker.pb.go @@ -81,6 +81,7 @@ type Exchange struct { unknownFields protoimpl.UnknownFields // Types that are assignable to Message: + // // *Exchange_Sdp // *Exchange_IceCandidate Message isExchange_Message `protobuf_oneof:"message"` diff --git a/peerbroker/proxy.go b/peerbroker/proxy.go index ecaf135863..3e3ccb4417 100644 --- a/peerbroker/proxy.go +++ b/peerbroker/proxy.go @@ -40,16 +40,19 @@ type ProxyOptions struct { // PubSub is used to geodistribute WebRTC handshakes. All negotiation // messages are small in size (<=8KB), and we don't require delivery // guarantees because connections can always be renegotiated. -// ┌────────────────────┐ ┌─────────────────────────────┐ -// │ coderd │ │ coderd │ +// +// ┌────────────────────┐ ┌─────────────────────────────┐ +// │ coderd │ │ coderd │ +// // ┌─────────────────────┐ │//connect │ │ //listen │ // │ client │ │ │ │ │ ┌─────┐ // │ ├──►│Creates a stream ID │◄─►│Subscribe() to the │◄──┤agent│ // │NegotiateConnection()│ │and Publish() to the│ │channel. Parse the stream ID │ └─────┘ // └─────────────────────┘ │ channel: │ │from payloads to create new │ -// │ │ │NegotiateConnection() streams│ -// ││ │or write to existing ones. │ -// └────────────────────┘ └─────────────────────────────┘ +// +// │ │ │NegotiateConnection() streams│ +// ││ │or write to existing ones. │ +// └────────────────────┘ └─────────────────────────────┘ func ProxyDial(client proto.DRPCPeerBrokerClient, options ProxyOptions) (io.Closer, error) { proxyDial := &proxyDial{ channelID: options.ChannelID, diff --git a/provisioner/terraform/provision_test.go b/provisioner/terraform/provision_test.go index 7b3542c49e..a9bd00cad9 100644 --- a/provisioner/terraform/provision_test.go +++ b/provisioner/terraform/provision_test.go @@ -61,12 +61,11 @@ func setupProvisioner(t *testing.T, opts *provisionerServeOptions) (context.Cont } func TestProvision_Cancel(t *testing.T) { + t.Parallel() if runtime.GOOS == "windows" { t.Skip("This test uses interrupts and is not supported on Windows") } - t.Parallel() - cwd, err := os.Getwd() require.NoError(t, err) fakeBin := filepath.Join(cwd, "testdata", "bin", "terraform_fake_cancel.sh") diff --git a/provisionerd/proto/provisionerd.pb.go b/provisionerd/proto/provisionerd.pb.go index ccb028111f..85aeaf79b3 100644 --- a/provisionerd/proto/provisionerd.pb.go +++ b/provisionerd/proto/provisionerd.pb.go @@ -119,6 +119,7 @@ type AcquiredJob struct { UserName string `protobuf:"bytes,4,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"` TemplateSourceArchive []byte `protobuf:"bytes,5,opt,name=template_source_archive,json=templateSourceArchive,proto3" json:"template_source_archive,omitempty"` // Types that are assignable to Type: + // // *AcquiredJob_WorkspaceBuild_ // *AcquiredJob_TemplateImport_ // *AcquiredJob_TemplateDryRun_ @@ -250,6 +251,7 @@ type FailedJob struct { JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"` Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` // Types that are assignable to Type: + // // *FailedJob_WorkspaceBuild_ // *FailedJob_TemplateImport_ // *FailedJob_TemplateDryRun_ @@ -360,6 +362,7 @@ type CompletedJob struct { JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"` // Types that are assignable to Type: + // // *CompletedJob_WorkspaceBuild_ // *CompletedJob_TemplateImport_ // *CompletedJob_TemplateDryRun_ diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index ce1ba84037..fb2c9024a0 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -713,6 +713,7 @@ type Agent struct { Directory string `protobuf:"bytes,7,opt,name=directory,proto3" json:"directory,omitempty"` Apps []*App `protobuf:"bytes,8,rep,name=apps,proto3" json:"apps,omitempty"` // Types that are assignable to Auth: + // // *Agent_Token // *Agent_InstanceId Auth isAgent_Auth `protobuf_oneof:"auth"` @@ -1244,6 +1245,7 @@ type Parse_Response struct { unknownFields protoimpl.UnknownFields // Types that are assignable to Type: + // // *Parse_Response_Log // *Parse_Response_Complete Type isParse_Response_Type `protobuf_oneof:"type"` @@ -1536,6 +1538,7 @@ type Provision_Request struct { unknownFields protoimpl.UnknownFields // Types that are assignable to Type: + // // *Provision_Request_Start // *Provision_Request_Cancel Type isProvision_Request_Type `protobuf_oneof:"type"` @@ -1679,6 +1682,7 @@ type Provision_Response struct { unknownFields protoimpl.UnknownFields // Types that are assignable to Type: + // // *Provision_Response_Log // *Provision_Response_Complete Type isProvision_Response_Type `protobuf_oneof:"type"` diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index dcb0b962d1..8cea09d09f 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -337,6 +337,7 @@ type TypescriptType struct { // typescriptType this function returns a typescript type for a given // golang type. // Eg: +// // []byte returns "string" func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { switch ty := ty.(type) { diff --git a/site/site_test.go b/site/site_test.go index 72008b4941..c04505bd03 100644 --- a/site/site_test.go +++ b/site/site_test.go @@ -466,6 +466,7 @@ func TestServeAPIResponse(t *testing.T) { require.NoError(t, err) resp, err := http.DefaultClient.Do(req) require.NoError(t, err) + defer resp.Body.Close() var body struct { Code int `json:"code"` Message string `json:"message"`