Skip to content

fix: improve password validation #15376

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b93dc6b
fix(setup): improve password validation flow on first user setup
defelmnq Oct 18, 2024
cf31dde
fix(setup): improve password validation flow on first user setup
defelmnq Oct 18, 2024
309d839
feat(password): WIP
defelmnq Oct 22, 2024
388a58b
feat(password): apply backend logic to all password set fields
defelmnq Oct 22, 2024
f9cce4c
Merge remote-tracking branch 'origin/main' into fix-password-validation
defelmnq Oct 23, 2024
8a5e63f
Merge remote-tracking branch 'origin/main' into fix-password-validation
defelmnq Oct 23, 2024
8f695ab
feat(password): apply backend logic to all password set fields
defelmnq Oct 23, 2024
c103559
feat(password): apply backend logic to all password set fields
defelmnq Oct 23, 2024
dc46019
feat(password): apply backend logic to all password set fields
defelmnq Oct 23, 2024
37072ee
feat(password): apply backend logic to all password set fields
defelmnq Oct 23, 2024
b4b8b06
feat(password): apply backend logic to all password set fields
defelmnq Oct 23, 2024
0efd24f
feat(password): add test for validate password method
defelmnq Oct 23, 2024
a6ee1cc
fix(password): display only if password is set
defelmnq Oct 24, 2024
51b1e51
WIP: Working on testing improvement
defelmnq Oct 24, 2024
e2128e6
site: change logic to generate error instead of helper text on passwo…
defelmnq Oct 24, 2024
f37ef9e
fix storybook
defelmnq Oct 24, 2024
36cadeb
Merge remote-tracking branch 'origin/main' into fix-password-validation
defelmnq Oct 25, 2024
175b4bf
feat(password): add details field to validate password endpoint
defelmnq Oct 28, 2024
f33eac2
feat(password): add details field to validate password endpoint
defelmnq Oct 28, 2024
2e0941b
Extract validation logic to a component
BrunoQuaresma Nov 4, 2024
3869dd5
Merge remote-tracking branch 'origin/main' into fix-password-validation
defelmnq Nov 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(password): apply backend logic to all password set fields
  • Loading branch information
defelmnq committed Oct 23, 2024
commit 388a58b36b46cb39747b2308eb812ce20c17f74a
10 changes: 7 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ jobs:
api-key: ${{ secrets.DATADOG_API_KEY }}

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

# We run race tests with reduced parallelism because they use more CPU and we were finding
# instances where tests appear to hang for multiple seconds, resulting in flaky tests when
# short timeouts are used.
# c.f. discussion on https://github.com/coder/coder/pull/15106
- name: Run Tests
run: |
gotestsum --junitfile="gotests.xml" -- -race ./...
gotestsum --junitfile="gotests.xml" -- -race -parallel 4 -p 4 ./...

- name: Upload test stats to Datadog
timeout-minutes: 1
Expand Down Expand Up @@ -966,7 +970,7 @@ jobs:
uses: google-github-actions/setup-gcloud@f0990588f1e5b5af6827153b93673613abdc6ec7 # v2.1.1

- name: Set up Flux CLI
uses: fluxcd/flux2/action@9b3958825a314eb79495c6993ef397ddbf87f32f # v2.2.1
uses: fluxcd/flux2/action@5350425cdcd5fa015337e09fa502153c0275bd4b # v2.4.0
with:
# Keep this and the github action up to date with the version of flux installed in dogfood cluster
version: "2.2.1"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ jobs:

# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13
with:
sarif_file: results.sarif
10 changes: 5 additions & 5 deletions .github/workflows/security.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
uses: ./.github/actions/setup-go

- name: Initialize CodeQL
uses: github/codeql-action/init@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
uses: github/codeql-action/init@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13
with:
languages: go, javascript

Expand All @@ -47,7 +47,7 @@ jobs:
rm Makefile

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
uses: github/codeql-action/analyze@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13

- name: Send Slack notification on failure
if: ${{ failure() }}
Expand Down Expand Up @@ -124,15 +124,15 @@ jobs:
echo "image=$(cat "$image_job")" >> $GITHUB_OUTPUT

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@5681af892cd0f4997658e2bacc62bd0a894cf564
uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2
with:
image-ref: ${{ steps.build.outputs.image }}
format: sarif
output: trivy-results.sarif
severity: "CRITICAL,HIGH"

- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13
with:
sarif_file: trivy-results.sarif
category: "Trivy"
Expand All @@ -147,7 +147,7 @@ jobs:
# Prisma cloud scan runs last because it fails the entire job if it
# detects vulnerabilities. :|
- name: Run Prisma Cloud image scan
uses: PaloAltoNetworks/prisma-cloud-scan@1f38c94d789ff9b01a4e80070b442294ebd3e362 # v1.4.0
uses: PaloAltoNetworks/prisma-cloud-scan@124b48d8325c23f58a35da0f1b4d9a6b54301d05 # v1.6.7
with:
pcc_console_url: ${{ secrets.PRISMA_CLOUD_URL }}
pcc_user: ${{ secrets.PRISMA_CLOUD_ACCESS_KEY }}
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ test-postgres-docker:

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

test-tailnet-integration:
Expand Down
8 changes: 8 additions & 0 deletions agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -1134,11 +1134,19 @@ func (a *agent) trackGoroutine(fn func()) error {
}

func (a *agent) createTailnet(ctx context.Context, agentID uuid.UUID, derpMap *tailcfg.DERPMap, derpForceWebSockets, disableDirectConnections bool) (_ *tailnet.Conn, err error) {
// Inject `CODER_AGENT_HEADER` into the DERP header.
var header http.Header
if client, ok := a.client.(*agentsdk.Client); ok {
if headerTransport, ok := client.SDK.HTTPClient.Transport.(*codersdk.HeaderTransport); ok {
header = headerTransport.Header
}
}
network, err := tailnet.NewConn(&tailnet.Options{
ID: agentID,
Addresses: a.wireguardAddresses(agentID),
DERPMap: derpMap,
DERPForceWebSockets: derpForceWebSockets,
DERPHeader: &header,
Logger: a.logger.Named("net.tailnet"),
ListenPort: a.tailnetListenPort,
BlockEndpoints: disableDirectConnections,
Expand Down
102 changes: 76 additions & 26 deletions cli/agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"runtime"
Expand All @@ -18,6 +17,7 @@ import (

"github.com/coder/coder/v2/agent"
"github.com/coder/coder/v2/cli/clitest"
"github.com/coder/coder/v2/coderd"
"github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbfake"
Expand All @@ -35,7 +35,7 @@ func TestWorkspaceAgent(t *testing.T) {

client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client)
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OrganizationID: user.OrganizationID,
OwnerID: user.UserID,
}).
Expand Down Expand Up @@ -71,7 +71,7 @@ func TestWorkspaceAgent(t *testing.T) {
AzureCertificates: certificates,
})
user := coderdtest.CreateFirstUser(t, client)
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OrganizationID: user.OrganizationID,
OwnerID: user.UserID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
Expand Down Expand Up @@ -110,7 +110,7 @@ func TestWorkspaceAgent(t *testing.T) {
AWSCertificates: certificates,
})
user := coderdtest.CreateFirstUser(t, client)
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OrganizationID: user.OrganizationID,
OwnerID: user.UserID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
Expand Down Expand Up @@ -151,7 +151,7 @@ func TestWorkspaceAgent(t *testing.T) {
})
owner := coderdtest.CreateFirstUser(t, client)
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OrganizationID: owner.OrganizationID,
OwnerID: memberUser.ID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
Expand Down Expand Up @@ -205,7 +205,7 @@ func TestWorkspaceAgent(t *testing.T) {

client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client)
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OrganizationID: user.OrganizationID,
OwnerID: user.UserID,
}).WithAgent().Do()
Expand All @@ -232,42 +232,92 @@ func TestWorkspaceAgent(t *testing.T) {
require.Equal(t, codersdk.AgentSubsystemEnvbox, resources[0].Agents[0].Subsystems[0])
require.Equal(t, codersdk.AgentSubsystemExectrace, resources[0].Agents[0].Subsystems[1])
})
t.Run("Header", func(t *testing.T) {
t.Run("Headers&DERPHeaders", func(t *testing.T) {
t.Parallel()

var url string
var called int64
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "wow", r.Header.Get("X-Testing"))
assert.Equal(t, "Ethan was Here!", r.Header.Get("Cool-Header"))
assert.Equal(t, "very-wow-"+url, r.Header.Get("X-Process-Testing"))
assert.Equal(t, "more-wow", r.Header.Get("X-Process-Testing2"))
atomic.AddInt64(&called, 1)
w.WriteHeader(http.StatusGone)
// Create a coderd API instance the hard way since we need to change the
// handler to inject our custom /derp handler.
dv := coderdtest.DeploymentValues(t)
dv.DERP.Config.BlockDirect = true
setHandler, cancelFunc, serverURL, newOptions := coderdtest.NewOptions(t, &coderdtest.Options{
DeploymentValues: dv,
})

// We set the handler after server creation for the access URL.
coderAPI := coderd.New(newOptions)
setHandler(coderAPI.RootHandler)
provisionerCloser := coderdtest.NewProvisionerDaemon(t, coderAPI)
t.Cleanup(func() {
_ = provisionerCloser.Close()
})
client := codersdk.New(serverURL)
t.Cleanup(func() {
cancelFunc()
_ = provisionerCloser.Close()
_ = coderAPI.Close()
client.HTTPClient.CloseIdleConnections()
})

var (
admin = coderdtest.CreateFirstUser(t, client)
member, memberUser = coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
called int64
derpCalled int64
)

setHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Ignore client requests
if r.Header.Get("X-Testing") == "agent" {
assert.Equal(t, "Ethan was Here!", r.Header.Get("Cool-Header"))
assert.Equal(t, "very-wow-"+client.URL.String(), r.Header.Get("X-Process-Testing"))
assert.Equal(t, "more-wow", r.Header.Get("X-Process-Testing2"))
if strings.HasPrefix(r.URL.Path, "/derp") {
atomic.AddInt64(&derpCalled, 1)
} else {
atomic.AddInt64(&called, 1)
}
}
coderAPI.RootHandler.ServeHTTP(w, r)
}))
defer srv.Close()
url = srv.URL
r := dbfake.WorkspaceBuild(t, coderAPI.Database, database.WorkspaceTable{
OrganizationID: memberUser.OrganizationIDs[0],
OwnerID: memberUser.ID,
}).WithAgent().Do()

coderURLEnv := "$CODER_URL"
if runtime.GOOS == "windows" {
coderURLEnv = "%CODER_URL%"
}

logDir := t.TempDir()
inv, _ := clitest.New(t,
agentInv, _ := clitest.New(t,
"agent",
"--auth", "token",
"--agent-token", "fake-token",
"--agent-url", srv.URL,
"--agent-token", r.AgentToken,
"--agent-url", client.URL.String(),
"--log-dir", logDir,
"--agent-header", "X-Testing=wow",
"--agent-header", "X-Testing=agent",
"--agent-header", "Cool-Header=Ethan was Here!",
"--agent-header-command", "printf X-Process-Testing=very-wow-"+coderURLEnv+"'\\r\\n'X-Process-Testing2=more-wow",
)
clitest.Start(t, agentInv)
coderdtest.NewWorkspaceAgentWaiter(t, client, r.Workspace.ID).
MatchResources(matchAgentWithVersion).Wait()

ctx := testutil.Context(t, testutil.WaitLong)
clientInv, root := clitest.New(t,
"-v",
"--no-feature-warning",
"--no-version-warning",
"ping", r.Workspace.Name,
"-n", "1",
)
clitest.SetupConfig(t, member, root)
err := clientInv.WithContext(ctx).Run()
require.NoError(t, err)

clitest.Start(t, inv)
require.Eventually(t, func() bool {
return atomic.LoadInt64(&called) > 0
}, testutil.WaitShort, testutil.IntervalFast)
require.Greater(t, atomic.LoadInt64(&called), int64(0), "expected coderd to be reached with custom headers")
require.Greater(t, atomic.LoadInt64(&derpCalled), int64(0), "expected /derp to be called with custom headers")
})
}

Expand Down
12 changes: 12 additions & 0 deletions cli/clistat/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
const (
procMounts = "/proc/mounts"
procOneCgroup = "/proc/1/cgroup"
sysCgroupType = "/sys/fs/cgroup/cgroup.type"
kubernetesDefaultServiceAccountToken = "/var/run/secrets/kubernetes.io/serviceaccount/token" //nolint:gosec
)

Expand Down Expand Up @@ -65,6 +66,17 @@ func IsContainerized(fs afero.Fs) (ok bool, err error) {
}
}

// Adapted from https://github.com/systemd/systemd/blob/88bbf187a9b2ebe0732caa1e886616ae5f8186da/src/basic/virt.c#L603-L605
// The file `/sys/fs/cgroup/cgroup.type` does not exist on the root cgroup.
// If this file exists we can be sure we're in a container.
cgTypeExists, err := afero.Exists(fs, sysCgroupType)
if err != nil {
return false, xerrors.Errorf("check file exists %s: %w", sysCgroupType, err)
}
if cgTypeExists {
return true, nil
}

// If we get here, we are _probably_ not running in a container.
return false, nil
}
12 changes: 12 additions & 0 deletions cli/clistat/stat_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,12 @@ func TestIsContainerized(t *testing.T) {
Expected: true,
Error: "",
},
{
Name: "Docker (Cgroupns=private)",
FS: fsContainerCgroupV2PrivateCgroupns,
Expected: true,
Error: "",
},
} {
tt := tt
t.Run(tt.Name, func(t *testing.T) {
Expand Down Expand Up @@ -374,6 +380,12 @@ proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0`,
cgroupV2MemoryUsageBytes: "536870912",
cgroupV2MemoryStat: "inactive_file 268435456",
}
fsContainerCgroupV2PrivateCgroupns = map[string]string{
procOneCgroup: "0::/",
procMounts: `overlay / overlay rw,relatime,lowerdir=/some/path:/some/path,upperdir=/some/path:/some/path,workdir=/some/path:/some/path 0 0
proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0`,
sysCgroupType: "domain",
}
fsContainerCgroupV1 = map[string]string{
procOneCgroup: "0::/docker/aa86ac98959eeedeae0ecb6e0c9ddd8ae8b97a9d0fdccccf7ea7a474f4e0bb1f",
procMounts: `overlay / overlay rw,relatime,lowerdir=/some/path:/some/path,upperdir=/some/path:/some/path,workdir=/some/path:/some/path 0 0
Expand Down
11 changes: 8 additions & 3 deletions cli/configssh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -63,6 +64,10 @@ func sshConfigFileRead(t *testing.T, name string) string {
func TestConfigSSH(t *testing.T) {
t.Parallel()

if runtime.GOOS == "windows" {
t.Skip("See coder/internal#117")
}

const hostname = "test-coder."
const expectedKey = "ConnectionAttempts"
const removeKey = "ConnectTimeout"
Expand All @@ -78,7 +83,7 @@ func TestConfigSSH(t *testing.T) {
})
owner := coderdtest.CreateFirstUser(t, client)
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OrganizationID: owner.OrganizationID,
OwnerID: memberUser.ID,
}).WithAgent().Do()
Expand Down Expand Up @@ -642,7 +647,7 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) {
client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client)
if tt.hasAgent {
_ = dbfake.WorkspaceBuild(t, db, database.Workspace{
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OrganizationID: user.OrganizationID,
OwnerID: user.UserID,
}).WithAgent().Do()
Expand Down Expand Up @@ -762,7 +767,7 @@ func TestConfigSSH_Hostnames(t *testing.T) {
owner := coderdtest.CreateFirstUser(t, client)
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)

r := dbfake.WorkspaceBuild(t, db, database.Workspace{
r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OrganizationID: owner.OrganizationID,
OwnerID: memberUser.ID,
}).Resource(resources...).Do()
Expand Down
2 changes: 1 addition & 1 deletion cli/favorite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestFavoriteUnfavorite(t *testing.T) {
client, db = coderdtest.NewWithDatabase(t, nil)
owner = coderdtest.CreateFirstUser(t, client)
memberClient, member = coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
ws = dbfake.WorkspaceBuild(t, db, database.Workspace{OwnerID: member.ID, OrganizationID: owner.OrganizationID}).Do()
ws = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{OwnerID: member.ID, OrganizationID: owner.OrganizationID}).Do()
)

inv, root := clitest.New(t, "favorite", ws.Workspace.Name)
Expand Down
Loading
Loading