Skip to content

Commit dd6dd84

Browse files
committed
Merge branch 'main' of https://github.com/coder/coder into bq/remove-schedule-banner-service
2 parents 8d1ee30 + 63a4f5f commit dd6dd84

37 files changed

+757
-649
lines changed

agent/agentssh/agentssh.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -252,16 +252,16 @@ func (s *Server) sessionStart(session ssh.Session, extraEnv []string) (retErr er
252252
if !strings.HasPrefix(kv, MagicSessionTypeEnvironmentVariable) {
253253
continue
254254
}
255-
magicType = strings.TrimPrefix(kv, MagicSessionTypeEnvironmentVariable+"=")
255+
magicType = strings.ToLower(strings.TrimPrefix(kv, MagicSessionTypeEnvironmentVariable+"="))
256256
env = append(env[:index], env[index+1:]...)
257257
}
258258

259259
// Always force lowercase checking to be case-insensitive.
260-
switch strings.ToLower(magicType) {
261-
case strings.ToLower(MagicSessionTypeVSCode):
260+
switch magicType {
261+
case MagicSessionTypeVSCode:
262262
s.connCountVSCode.Add(1)
263263
defer s.connCountVSCode.Add(-1)
264-
case strings.ToLower(MagicSessionTypeJetBrains):
264+
case MagicSessionTypeJetBrains:
265265
s.connCountJetBrains.Add(1)
266266
defer s.connCountJetBrains.Add(-1)
267267
case "":

coderd/coderdtest/coderdtest.go

+27
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,25 @@ func CreateTemplate(t testing.TB, client *codersdk.Client, organization uuid.UUI
762762
return template
763763
}
764764

765+
// CreateGroup creates a group with the given name and members.
766+
func CreateGroup(t testing.TB, client *codersdk.Client, organizationID uuid.UUID, name string, members ...codersdk.User) codersdk.Group {
767+
t.Helper()
768+
group, err := client.CreateGroup(context.Background(), organizationID, codersdk.CreateGroupRequest{
769+
Name: name,
770+
})
771+
require.NoError(t, err, "failed to create group")
772+
memberIDs := make([]string, 0)
773+
for _, member := range members {
774+
memberIDs = append(memberIDs, member.ID.String())
775+
}
776+
group, err = client.PatchGroup(context.Background(), group.ID, codersdk.PatchGroupRequest{
777+
AddUsers: memberIDs,
778+
})
779+
780+
require.NoError(t, err, "failed to add members to group")
781+
return group
782+
}
783+
765784
// UpdateTemplateVersion creates a new template version with the "echo" provisioner
766785
// and associates it with the given templateID.
767786
func UpdateTemplateVersion(t testing.TB, client *codersdk.Client, organizationID uuid.UUID, res *echo.Responses, templateID uuid.UUID) codersdk.TemplateVersion {
@@ -787,6 +806,14 @@ func UpdateActiveTemplateVersion(t testing.TB, client *codersdk.Client, template
787806
require.NoError(t, err)
788807
}
789808

809+
// UpdateTemplateMeta updates the template meta for the given template.
810+
func UpdateTemplateMeta(t testing.TB, client *codersdk.Client, templateID uuid.UUID, meta codersdk.UpdateTemplateMeta) codersdk.Template {
811+
t.Helper()
812+
updated, err := client.UpdateTemplateMeta(context.Background(), templateID, meta)
813+
require.NoError(t, err)
814+
return updated
815+
}
816+
790817
// AwaitTemplateVersionJobRunning waits for the build to be picked up by a provisioner.
791818
func AwaitTemplateVersionJobRunning(t testing.TB, client *codersdk.Client, version uuid.UUID) codersdk.TemplateVersion {
792819
t.Helper()

coderd/externalauth/externalauth.go

+69-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net/http"
1010
"net/url"
1111
"regexp"
12+
"strings"
1213
"time"
1314

1415
"golang.org/x/oauth2"
@@ -494,7 +495,36 @@ func ConvertConfig(entries []codersdk.ExternalAuthConfig, accessURL *url.URL) ([
494495

495496
// applyDefaultsToConfig applies defaults to the config entry.
496497
func applyDefaultsToConfig(config *codersdk.ExternalAuthConfig) {
497-
defaults := defaults[codersdk.EnhancedExternalAuthProvider(config.Type)]
498+
configType := codersdk.EnhancedExternalAuthProvider(config.Type)
499+
if configType == "bitbucket" {
500+
// For backwards compatibility, we need to support the "bitbucket" string.
501+
configType = codersdk.EnhancedExternalAuthProviderBitBucketCloud
502+
defer func() {
503+
// The config type determines the config ID (if unset). So change the legacy
504+
// type to the correct new type after the defaults have been configured.
505+
config.Type = string(codersdk.EnhancedExternalAuthProviderBitBucketCloud)
506+
}()
507+
}
508+
// If static defaults exist, apply them.
509+
if defaults, ok := staticDefaults[configType]; ok {
510+
copyDefaultSettings(config, defaults)
511+
return
512+
}
513+
514+
// Dynamic defaults
515+
switch codersdk.EnhancedExternalAuthProvider(config.Type) {
516+
case codersdk.EnhancedExternalAuthProviderBitBucketServer:
517+
copyDefaultSettings(config, bitbucketServerDefaults(config))
518+
return
519+
default:
520+
// No defaults for this type. We still want to run this apply with
521+
// an empty set of defaults.
522+
copyDefaultSettings(config, codersdk.ExternalAuthConfig{})
523+
return
524+
}
525+
}
526+
527+
func copyDefaultSettings(config *codersdk.ExternalAuthConfig, defaults codersdk.ExternalAuthConfig) {
498528
if config.AuthURL == "" {
499529
config.AuthURL = defaults.AuthURL
500530
}
@@ -542,7 +572,43 @@ func applyDefaultsToConfig(config *codersdk.ExternalAuthConfig) {
542572
}
543573
}
544574

545-
var defaults = map[codersdk.EnhancedExternalAuthProvider]codersdk.ExternalAuthConfig{
575+
func bitbucketServerDefaults(config *codersdk.ExternalAuthConfig) codersdk.ExternalAuthConfig {
576+
defaults := codersdk.ExternalAuthConfig{
577+
DisplayName: "Bitbucket Server",
578+
Scopes: []string{"PUBLIC_REPOS", "REPO_READ", "REPO_WRITE"},
579+
DisplayIcon: "/icon/bitbucket.svg",
580+
}
581+
// Bitbucket servers will have some base url, e.g. https://bitbucket.coder.com.
582+
// We will grab this from the Auth URL. This choice is a bit arbitrary,
583+
// but we need to require at least 1 field to be populated.
584+
if config.AuthURL == "" {
585+
// No auth url, means we cannot guess the urls.
586+
return defaults
587+
}
588+
589+
auth, err := url.Parse(config.AuthURL)
590+
if err != nil {
591+
// We need a valid URL to continue with.
592+
return defaults
593+
}
594+
595+
// Populate Regex, ValidateURL, and TokenURL.
596+
// Default regex should be anything using the same host as the auth url.
597+
defaults.Regex = fmt.Sprintf(`^(https?://)?%s(/.*)?$`, strings.ReplaceAll(auth.Host, ".", `\.`))
598+
599+
tokenURL := auth.ResolveReference(&url.URL{Path: "/rest/oauth2/latest/token"})
600+
defaults.TokenURL = tokenURL.String()
601+
602+
// validate needs to return a 200 when logged in and a 401 when unauthenticated.
603+
// This endpoint returns the count of the number of PR's in the authenticated
604+
// user's inbox. Which will work perfectly for our use case.
605+
validate := auth.ResolveReference(&url.URL{Path: "/rest/api/latest/inbox/pull-requests/count"})
606+
defaults.ValidateURL = validate.String()
607+
608+
return defaults
609+
}
610+
611+
var staticDefaults = map[codersdk.EnhancedExternalAuthProvider]codersdk.ExternalAuthConfig{
546612
codersdk.EnhancedExternalAuthProviderAzureDevops: {
547613
AuthURL: "https://app.vssps.visualstudio.com/oauth2/authorize",
548614
TokenURL: "https://app.vssps.visualstudio.com/oauth2/token",
@@ -551,7 +617,7 @@ var defaults = map[codersdk.EnhancedExternalAuthProvider]codersdk.ExternalAuthCo
551617
Regex: `^(https?://)?dev\.azure\.com(/.*)?$`,
552618
Scopes: []string{"vso.code_write"},
553619
},
554-
codersdk.EnhancedExternalAuthProviderBitBucket: {
620+
codersdk.EnhancedExternalAuthProviderBitBucketCloud: {
555621
AuthURL: "https://bitbucket.org/site/oauth2/authorize",
556622
TokenURL: "https://bitbucket.org/site/oauth2/access_token",
557623
ValidateURL: "https://api.bitbucket.org/2.0/user",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package externalauth
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
8+
"github.com/coder/coder/v2/codersdk"
9+
)
10+
11+
func Test_bitbucketServerConfigDefaults(t *testing.T) {
12+
t.Parallel()
13+
14+
bbType := string(codersdk.EnhancedExternalAuthProviderBitBucketServer)
15+
tests := []struct {
16+
name string
17+
config *codersdk.ExternalAuthConfig
18+
expected codersdk.ExternalAuthConfig
19+
}{
20+
{
21+
// Very few fields are statically defined for Bitbucket Server.
22+
name: "EmptyBitbucketServer",
23+
config: &codersdk.ExternalAuthConfig{
24+
Type: bbType,
25+
},
26+
expected: codersdk.ExternalAuthConfig{
27+
Type: bbType,
28+
ID: bbType,
29+
DisplayName: "Bitbucket Server",
30+
Scopes: []string{"PUBLIC_REPOS", "REPO_READ", "REPO_WRITE"},
31+
DisplayIcon: "/icon/bitbucket.svg",
32+
},
33+
},
34+
{
35+
// Only the AuthURL is required for defaults to work.
36+
name: "AuthURL",
37+
config: &codersdk.ExternalAuthConfig{
38+
Type: bbType,
39+
AuthURL: "https://bitbucket.example.com/login/oauth/authorize",
40+
},
41+
expected: codersdk.ExternalAuthConfig{
42+
Type: bbType,
43+
ID: bbType,
44+
AuthURL: "https://bitbucket.example.com/login/oauth/authorize",
45+
TokenURL: "https://bitbucket.example.com/rest/oauth2/latest/token",
46+
ValidateURL: "https://bitbucket.example.com/rest/api/latest/inbox/pull-requests/count",
47+
Scopes: []string{"PUBLIC_REPOS", "REPO_READ", "REPO_WRITE"},
48+
Regex: `^(https?://)?bitbucket\.example\.com(/.*)?$`,
49+
DisplayName: "Bitbucket Server",
50+
DisplayIcon: "/icon/bitbucket.svg",
51+
},
52+
},
53+
{
54+
// Ensure backwards compatibility. The type should update to "bitbucket-cloud",
55+
// but the ID and other fields should remain the same.
56+
name: "BitbucketLegacy",
57+
config: &codersdk.ExternalAuthConfig{
58+
Type: "bitbucket",
59+
},
60+
expected: codersdk.ExternalAuthConfig{
61+
Type: string(codersdk.EnhancedExternalAuthProviderBitBucketCloud),
62+
ID: "bitbucket", // Legacy ID remains unchanged
63+
AuthURL: "https://bitbucket.org/site/oauth2/authorize",
64+
TokenURL: "https://bitbucket.org/site/oauth2/access_token",
65+
ValidateURL: "https://api.bitbucket.org/2.0/user",
66+
DisplayName: "BitBucket",
67+
DisplayIcon: "/icon/bitbucket.svg",
68+
Regex: `^(https?://)?bitbucket\.org(/.*)?$`,
69+
Scopes: []string{"account", "repository:write"},
70+
},
71+
},
72+
}
73+
for _, tt := range tests {
74+
tt := tt
75+
t.Run(tt.name, func(t *testing.T) {
76+
t.Parallel()
77+
applyDefaultsToConfig(tt.config)
78+
require.Equal(t, tt.expected, *tt.config)
79+
})
80+
}
81+
}

coderd/workspaceagents.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -2452,7 +2452,8 @@ func createExternalAuthResponse(typ, token string, extra pqtype.NullRawMessage)
24522452
Username: "oauth2",
24532453
Password: token,
24542454
}
2455-
case string(codersdk.EnhancedExternalAuthProviderBitBucket):
2455+
case string(codersdk.EnhancedExternalAuthProviderBitBucketCloud), string(codersdk.EnhancedExternalAuthProviderBitBucketServer):
2456+
// The string "bitbucket" was a legacy parameter that needs to still be supported.
24562457
// https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/#Cloning-a-repository-with-an-access-token
24572458
resp = agentsdk.ExternalAuthResponse{
24582459
Username: "x-token-auth",

codersdk/externalauth.go

+8-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ func (e EnhancedExternalAuthProvider) Git() bool {
2121
switch e {
2222
case EnhancedExternalAuthProviderGitHub,
2323
EnhancedExternalAuthProviderGitLab,
24-
EnhancedExternalAuthProviderBitBucket,
24+
EnhancedExternalAuthProviderBitBucketCloud,
25+
EnhancedExternalAuthProviderBitBucketServer,
2526
EnhancedExternalAuthProviderAzureDevops:
2627
return true
2728
default:
@@ -33,9 +34,12 @@ const (
3334
EnhancedExternalAuthProviderAzureDevops EnhancedExternalAuthProvider = "azure-devops"
3435
EnhancedExternalAuthProviderGitHub EnhancedExternalAuthProvider = "github"
3536
EnhancedExternalAuthProviderGitLab EnhancedExternalAuthProvider = "gitlab"
36-
EnhancedExternalAuthProviderBitBucket EnhancedExternalAuthProvider = "bitbucket"
37-
EnhancedExternalAuthProviderSlack EnhancedExternalAuthProvider = "slack"
38-
EnhancedExternalAuthProviderJFrog EnhancedExternalAuthProvider = "jfrog"
37+
// EnhancedExternalAuthProviderBitBucketCloud is the Bitbucket Cloud provider.
38+
// Not to be confused with the self-hosted 'EnhancedExternalAuthProviderBitBucketServer'
39+
EnhancedExternalAuthProviderBitBucketCloud EnhancedExternalAuthProvider = "bitbucket-cloud"
40+
EnhancedExternalAuthProviderBitBucketServer EnhancedExternalAuthProvider = "bitbucket-server"
41+
EnhancedExternalAuthProviderSlack EnhancedExternalAuthProvider = "slack"
42+
EnhancedExternalAuthProviderJFrog EnhancedExternalAuthProvider = "jfrog"
3943
)
4044

4145
type ExternalAuth struct {

enterprise/cli/features_test.go

+7-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/stretchr/testify/require"
1010

1111
"github.com/coder/coder/v2/cli/clitest"
12+
"github.com/coder/coder/v2/coderd/coderdtest"
1213
"github.com/coder/coder/v2/codersdk"
1314
"github.com/coder/coder/v2/enterprise/coderd/coderdenttest"
1415
"github.com/coder/coder/v2/pty/ptytest"
@@ -18,9 +19,10 @@ func TestFeaturesList(t *testing.T) {
1819
t.Parallel()
1920
t.Run("Table", func(t *testing.T) {
2021
t.Parallel()
21-
client, _ := coderdenttest.New(t, &coderdenttest.Options{DontAddLicense: true})
22+
client, admin := coderdenttest.New(t, &coderdenttest.Options{DontAddLicense: true})
23+
anotherClient, _ := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
2224
inv, conf := newCLI(t, "features", "list")
23-
clitest.SetupConfig(t, client, conf)
25+
clitest.SetupConfig(t, anotherClient, conf)
2426
pty := ptytest.New(t).Attach(inv)
2527
clitest.Start(t, inv)
2628
pty.ExpectMatch("user_limit")
@@ -29,9 +31,10 @@ func TestFeaturesList(t *testing.T) {
2931
t.Run("JSON", func(t *testing.T) {
3032
t.Parallel()
3133

32-
client, _ := coderdenttest.New(t, &coderdenttest.Options{DontAddLicense: true})
34+
client, admin := coderdenttest.New(t, &coderdenttest.Options{DontAddLicense: true})
35+
anotherClient, _ := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
3336
inv, conf := newCLI(t, "features", "list", "-o", "json")
34-
clitest.SetupConfig(t, client, conf)
37+
clitest.SetupConfig(t, anotherClient, conf)
3538
doneChan := make(chan struct{})
3639

3740
buf := bytes.NewBuffer(nil)

enterprise/cli/groupcreate_test.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010

1111
"github.com/coder/coder/v2/cli/clitest"
1212
"github.com/coder/coder/v2/cli/cliui"
13+
"github.com/coder/coder/v2/coderd/coderdtest"
14+
"github.com/coder/coder/v2/coderd/rbac"
1315
"github.com/coder/coder/v2/codersdk"
1416
"github.com/coder/coder/v2/enterprise/coderd/coderdenttest"
1517
"github.com/coder/coder/v2/enterprise/coderd/license"
@@ -22,11 +24,12 @@ func TestCreateGroup(t *testing.T) {
2224
t.Run("OK", func(t *testing.T) {
2325
t.Parallel()
2426

25-
client, _ := coderdenttest.New(t, &coderdenttest.Options{LicenseOptions: &coderdenttest.LicenseOptions{
27+
client, admin := coderdenttest.New(t, &coderdenttest.Options{LicenseOptions: &coderdenttest.LicenseOptions{
2628
Features: license.Features{
2729
codersdk.FeatureTemplateRBAC: 1,
2830
},
2931
}})
32+
anotherClient, _ := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID, rbac.RoleUserAdmin())
3033

3134
var (
3235
groupName = "test"
@@ -40,7 +43,7 @@ func TestCreateGroup(t *testing.T) {
4043

4144
pty := ptytest.New(t)
4245
inv.Stdout = pty.Output()
43-
clitest.SetupConfig(t, client, conf)
46+
clitest.SetupConfig(t, anotherClient, conf)
4447

4548
err := inv.Run()
4649
require.NoError(t, err)

0 commit comments

Comments
 (0)