Skip to content

Commit 93ca420

Browse files
committed
Merge remote-tracking branch 'origin/main' into issue#14856
2 parents 10d718f + 23f61c6 commit 93ca420

Some content is hidden

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

51 files changed

+1452
-332
lines changed

.github/workflows/ci.yaml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ jobs:
466466
api-key: ${{ secrets.DATADOG_API_KEY }}
467467

468468
test-go-race:
469-
runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-latest' }}
469+
runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }}
470470
needs: changes
471471
if: needs.changes.outputs.go == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main'
472472
timeout-minutes: 25
@@ -487,9 +487,13 @@ jobs:
487487
- name: Setup Terraform
488488
uses: ./.github/actions/setup-tf
489489

490+
# We run race tests with reduced parallelism because they use more CPU and we were finding
491+
# instances where tests appear to hang for multiple seconds, resulting in flaky tests when
492+
# short timeouts are used.
493+
# c.f. discussion on https://github.com/coder/coder/pull/15106
490494
- name: Run Tests
491495
run: |
492-
gotestsum --junitfile="gotests.xml" -- -race ./...
496+
gotestsum --junitfile="gotests.xml" -- -race -parallel 4 -p 4 ./...
493497
494498
- name: Upload test stats to Datadog
495499
timeout-minutes: 1

.github/workflows/pr-deploy.yaml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,6 @@ jobs:
4444
with:
4545
egress-policy: audit
4646

47-
- name: Harden Runner
48-
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
49-
with:
50-
egress-policy: audit
51-
52-
- name: Harden Runner
53-
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
54-
with:
55-
egress-policy: audit
56-
5747
- name: Checkout
5848
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
5949

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,7 @@ test-postgres-docker:
817817

818818
# Make sure to keep this in sync with test-go-race from .github/workflows/ci.yaml.
819819
test-race:
820-
$(GIT_FLAGS) gotestsum --junitfile="gotests.xml" -- -race -count=1 ./...
820+
$(GIT_FLAGS) gotestsum --junitfile="gotests.xml" -- -race -count=1 -parallel 4 -p 4 ./...
821821
.PHONY: test-race
822822

823823
test-tailnet-integration:

agent/agent.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,11 +1134,19 @@ func (a *agent) trackGoroutine(fn func()) error {
11341134
}
11351135

11361136
func (a *agent) createTailnet(ctx context.Context, agentID uuid.UUID, derpMap *tailcfg.DERPMap, derpForceWebSockets, disableDirectConnections bool) (_ *tailnet.Conn, err error) {
1137+
// Inject `CODER_AGENT_HEADER` into the DERP header.
1138+
var header http.Header
1139+
if client, ok := a.client.(*agentsdk.Client); ok {
1140+
if headerTransport, ok := client.SDK.HTTPClient.Transport.(*codersdk.HeaderTransport); ok {
1141+
header = headerTransport.Header
1142+
}
1143+
}
11371144
network, err := tailnet.NewConn(&tailnet.Options{
11381145
ID: agentID,
11391146
Addresses: a.wireguardAddresses(agentID),
11401147
DERPMap: derpMap,
11411148
DERPForceWebSockets: derpForceWebSockets,
1149+
DERPHeader: &header,
11421150
Logger: a.logger.Named("net.tailnet"),
11431151
ListenPort: a.tailnetListenPort,
11441152
BlockEndpoints: disableDirectConnections,

cli/agent_test.go

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"fmt"
66
"net/http"
7-
"net/http/httptest"
87
"os"
98
"path/filepath"
109
"runtime"
@@ -18,6 +17,7 @@ import (
1817

1918
"github.com/coder/coder/v2/agent"
2019
"github.com/coder/coder/v2/cli/clitest"
20+
"github.com/coder/coder/v2/coderd"
2121
"github.com/coder/coder/v2/coderd/coderdtest"
2222
"github.com/coder/coder/v2/coderd/database"
2323
"github.com/coder/coder/v2/coderd/database/dbfake"
@@ -232,42 +232,92 @@ func TestWorkspaceAgent(t *testing.T) {
232232
require.Equal(t, codersdk.AgentSubsystemEnvbox, resources[0].Agents[0].Subsystems[0])
233233
require.Equal(t, codersdk.AgentSubsystemExectrace, resources[0].Agents[0].Subsystems[1])
234234
})
235-
t.Run("Header", func(t *testing.T) {
235+
t.Run("Headers&DERPHeaders", func(t *testing.T) {
236236
t.Parallel()
237237

238-
var url string
239-
var called int64
240-
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
241-
assert.Equal(t, "wow", r.Header.Get("X-Testing"))
242-
assert.Equal(t, "Ethan was Here!", r.Header.Get("Cool-Header"))
243-
assert.Equal(t, "very-wow-"+url, r.Header.Get("X-Process-Testing"))
244-
assert.Equal(t, "more-wow", r.Header.Get("X-Process-Testing2"))
245-
atomic.AddInt64(&called, 1)
246-
w.WriteHeader(http.StatusGone)
238+
// Create a coderd API instance the hard way since we need to change the
239+
// handler to inject our custom /derp handler.
240+
dv := coderdtest.DeploymentValues(t)
241+
dv.DERP.Config.BlockDirect = true
242+
setHandler, cancelFunc, serverURL, newOptions := coderdtest.NewOptions(t, &coderdtest.Options{
243+
DeploymentValues: dv,
244+
})
245+
246+
// We set the handler after server creation for the access URL.
247+
coderAPI := coderd.New(newOptions)
248+
setHandler(coderAPI.RootHandler)
249+
provisionerCloser := coderdtest.NewProvisionerDaemon(t, coderAPI)
250+
t.Cleanup(func() {
251+
_ = provisionerCloser.Close()
252+
})
253+
client := codersdk.New(serverURL)
254+
t.Cleanup(func() {
255+
cancelFunc()
256+
_ = provisionerCloser.Close()
257+
_ = coderAPI.Close()
258+
client.HTTPClient.CloseIdleConnections()
259+
})
260+
261+
var (
262+
admin = coderdtest.CreateFirstUser(t, client)
263+
member, memberUser = coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
264+
called int64
265+
derpCalled int64
266+
)
267+
268+
setHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
269+
// Ignore client requests
270+
if r.Header.Get("X-Testing") == "agent" {
271+
assert.Equal(t, "Ethan was Here!", r.Header.Get("Cool-Header"))
272+
assert.Equal(t, "very-wow-"+client.URL.String(), r.Header.Get("X-Process-Testing"))
273+
assert.Equal(t, "more-wow", r.Header.Get("X-Process-Testing2"))
274+
if strings.HasPrefix(r.URL.Path, "/derp") {
275+
atomic.AddInt64(&derpCalled, 1)
276+
} else {
277+
atomic.AddInt64(&called, 1)
278+
}
279+
}
280+
coderAPI.RootHandler.ServeHTTP(w, r)
247281
}))
248-
defer srv.Close()
249-
url = srv.URL
282+
r := dbfake.WorkspaceBuild(t, coderAPI.Database, database.Workspace{
283+
OrganizationID: memberUser.OrganizationIDs[0],
284+
OwnerID: memberUser.ID,
285+
}).WithAgent().Do()
286+
250287
coderURLEnv := "$CODER_URL"
251288
if runtime.GOOS == "windows" {
252289
coderURLEnv = "%CODER_URL%"
253290
}
254291

255292
logDir := t.TempDir()
256-
inv, _ := clitest.New(t,
293+
agentInv, _ := clitest.New(t,
257294
"agent",
258295
"--auth", "token",
259-
"--agent-token", "fake-token",
260-
"--agent-url", srv.URL,
296+
"--agent-token", r.AgentToken,
297+
"--agent-url", client.URL.String(),
261298
"--log-dir", logDir,
262-
"--agent-header", "X-Testing=wow",
299+
"--agent-header", "X-Testing=agent",
263300
"--agent-header", "Cool-Header=Ethan was Here!",
264301
"--agent-header-command", "printf X-Process-Testing=very-wow-"+coderURLEnv+"'\\r\\n'X-Process-Testing2=more-wow",
265302
)
303+
clitest.Start(t, agentInv)
304+
coderdtest.NewWorkspaceAgentWaiter(t, client, r.Workspace.ID).
305+
MatchResources(matchAgentWithVersion).Wait()
306+
307+
ctx := testutil.Context(t, testutil.WaitLong)
308+
clientInv, root := clitest.New(t,
309+
"-v",
310+
"--no-feature-warning",
311+
"--no-version-warning",
312+
"ping", r.Workspace.Name,
313+
"-n", "1",
314+
)
315+
clitest.SetupConfig(t, member, root)
316+
err := clientInv.WithContext(ctx).Run()
317+
require.NoError(t, err)
266318

267-
clitest.Start(t, inv)
268-
require.Eventually(t, func() bool {
269-
return atomic.LoadInt64(&called) > 0
270-
}, testutil.WaitShort, testutil.IntervalFast)
319+
require.Greater(t, atomic.LoadInt64(&called), int64(0), "expected coderd to be reached with custom headers")
320+
require.Greater(t, atomic.LoadInt64(&derpCalled), int64(0), "expected /derp to be called with custom headers")
271321
})
272322
}
273323

cli/clistat/container.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
const (
1313
procMounts = "/proc/mounts"
1414
procOneCgroup = "/proc/1/cgroup"
15+
sysCgroupType = "/sys/fs/cgroup/cgroup.type"
1516
kubernetesDefaultServiceAccountToken = "/var/run/secrets/kubernetes.io/serviceaccount/token" //nolint:gosec
1617
)
1718

@@ -65,6 +66,17 @@ func IsContainerized(fs afero.Fs) (ok bool, err error) {
6566
}
6667
}
6768

69+
// Adapted from https://github.com/systemd/systemd/blob/88bbf187a9b2ebe0732caa1e886616ae5f8186da/src/basic/virt.c#L603-L605
70+
// The file `/sys/fs/cgroup/cgroup.type` does not exist on the root cgroup.
71+
// If this file exists we can be sure we're in a container.
72+
cgTypeExists, err := afero.Exists(fs, sysCgroupType)
73+
if err != nil {
74+
return false, xerrors.Errorf("check file exists %s: %w", sysCgroupType, err)
75+
}
76+
if cgTypeExists {
77+
return true, nil
78+
}
79+
6880
// If we get here, we are _probably_ not running in a container.
6981
return false, nil
7082
}

cli/clistat/stat_internal_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,12 @@ func TestIsContainerized(t *testing.T) {
309309
Expected: true,
310310
Error: "",
311311
},
312+
{
313+
Name: "Docker (Cgroupns=private)",
314+
FS: fsContainerCgroupV2PrivateCgroupns,
315+
Expected: true,
316+
Error: "",
317+
},
312318
} {
313319
tt := tt
314320
t.Run(tt.Name, func(t *testing.T) {
@@ -374,6 +380,12 @@ proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0`,
374380
cgroupV2MemoryUsageBytes: "536870912",
375381
cgroupV2MemoryStat: "inactive_file 268435456",
376382
}
383+
fsContainerCgroupV2PrivateCgroupns = map[string]string{
384+
procOneCgroup: "0::/",
385+
procMounts: `overlay / overlay rw,relatime,lowerdir=/some/path:/some/path,upperdir=/some/path:/some/path,workdir=/some/path:/some/path 0 0
386+
proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0`,
387+
sysCgroupType: "domain",
388+
}
377389
fsContainerCgroupV1 = map[string]string{
378390
procOneCgroup: "0::/docker/aa86ac98959eeedeae0ecb6e0c9ddd8ae8b97a9d0fdccccf7ea7a474f4e0bb1f",
379391
procMounts: `overlay / overlay rw,relatime,lowerdir=/some/path:/some/path,upperdir=/some/path:/some/path,workdir=/some/path:/some/path 0 0

cli/configssh_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"os"
1111
"os/exec"
1212
"path/filepath"
13+
"runtime"
1314
"strconv"
1415
"strings"
1516
"sync"
@@ -63,6 +64,10 @@ func sshConfigFileRead(t *testing.T, name string) string {
6364
func TestConfigSSH(t *testing.T) {
6465
t.Parallel()
6566

67+
if runtime.GOOS == "windows" {
68+
t.Skip("See coder/internal#117")
69+
}
70+
6671
const hostname = "test-coder."
6772
const expectedKey = "ConnectionAttempts"
6873
const removeKey = "ConnectTimeout"

coderd/database/migrations/000266_update_forgot_password_notification.down.sql

Whitespace-only changes.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
UPDATE notification_templates
2+
SET
3+
title_template = E'Reset your password for Coder',
4+
body_template = E'Hi {{.UserName}},\n\nUse the link below to reset your password.\n\nIf you did not make this request, you can ignore this message.',
5+
actions = '[{
6+
"label": "Reset password",
7+
"url": "{{ base_url }}/reset-password/change?otp={{.Labels.one_time_passcode}}&email={{ .UserEmail }}"
8+
}]'::jsonb
9+
WHERE
10+
id = '62f86a30-2330-4b61-a26d-311ff3b608cf'

coderd/database/migrations/000267_fix_password_reset_notification_link.down.sql

Whitespace-only changes.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
UPDATE notification_templates
2+
SET
3+
title_template = E'Reset your password for Coder',
4+
body_template = E'Hi {{.UserName}},\n\nUse the link below to reset your password.\n\nIf you did not make this request, you can ignore this message.',
5+
actions = '[{
6+
"label": "Reset password",
7+
"url": "{{base_url}}/reset-password/change?otp={{.Labels.one_time_passcode}}&email={{.UserEmail | urlquery}}"
8+
}]'::jsonb
9+
WHERE
10+
id = '62f86a30-2330-4b61-a26d-311ff3b608cf'

coderd/database/queries.sql.go

Lines changed: 8 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/insights.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ WITH
661661
AND date_trunc('minute', was.created_at) = mb.minute_bucket
662662
AND was.template_id = mb.template_id
663663
AND was.user_id = mb.user_id
664-
AND was.connection_median_latency_ms >= 0
664+
AND was.connection_median_latency_ms > 0
665665
GROUP BY
666666
mb.start_time, mb.template_id, mb.user_id
667667
)

0 commit comments

Comments
 (0)