Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7f226d4

Browse files
authored
feat: add support forcoder_git_auth data source (#6334)
* Add git auth providers schema* Pipe git auth providers to the schema* Add git auth providers to the API* Add gitauth endpoint to query authenticated state* Add endpoint to query git state* Use BroadcastChannel to automatically authenticate with Git* Add error validation for submitting the create workspace form* Fix panic on template dry-run* Add tests for the template version Git auth endpoint* Show error if no gitauth is configured* Add gitauth to cliui* Fix unused method receiver* Fix linting errors* Fix dbauthz querier test* Fix make gen* Add JavaScript test for git auth* Fix bad error message* Fix provisionerd test raceSeehttps://github.com/coder/coder/actions/runs/4277960646/jobs/7447232814* Fix requested changes* Add comment to CreateWorkspacePageView
1 parent3d8b77d commit7f226d4

File tree

64 files changed

+2768
-841
lines changed

Some content is hidden

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

64 files changed

+2768
-841
lines changed

‎cli/cliui/gitauth.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package cliui
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io"
7+
"time"
8+
9+
"github.com/briandowns/spinner"
10+
11+
"github.com/coder/coder/codersdk"
12+
)
13+
14+
typeGitAuthOptionsstruct {
15+
Fetchfunc(context.Context) ([]codersdk.TemplateVersionGitAuth,error)
16+
FetchInterval time.Duration
17+
}
18+
19+
funcGitAuth(ctx context.Context,writer io.Writer,optsGitAuthOptions)error {
20+
ifopts.FetchInterval==0 {
21+
opts.FetchInterval=500*time.Millisecond
22+
}
23+
gitAuth,err:=opts.Fetch(ctx)
24+
iferr!=nil {
25+
returnerr
26+
}
27+
28+
spin:=spinner.New(spinner.CharSets[78],100*time.Millisecond,spinner.WithColor("fgHiGreen"))
29+
spin.Writer=writer
30+
spin.ForceOutput=true
31+
spin.Suffix=" Waiting for Git authentication..."
32+
deferspin.Stop()
33+
34+
ticker:=time.NewTicker(opts.FetchInterval)
35+
deferticker.Stop()
36+
for_,auth:=rangegitAuth {
37+
ifauth.Authenticated {
38+
returnnil
39+
}
40+
41+
_,_=fmt.Fprintf(writer,"You must authenticate with %s to create a workspace with this template. Visit:\n\n\t%s\n\n",auth.Type.Pretty(),auth.AuthenticateURL)
42+
43+
ticker.Reset(opts.FetchInterval)
44+
spin.Start()
45+
for {
46+
select {
47+
case<-ctx.Done():
48+
returnctx.Err()
49+
case<-ticker.C:
50+
}
51+
gitAuth,err:=opts.Fetch(ctx)
52+
iferr!=nil {
53+
returnerr
54+
}
55+
varauthedbool
56+
for_,a:=rangegitAuth {
57+
if!a.Authenticated||a.ID!=auth.ID {
58+
continue
59+
}
60+
authed=true
61+
break
62+
}
63+
// The user authenticated with the provider!
64+
ifauthed {
65+
break
66+
}
67+
}
68+
spin.Stop()
69+
_,_=fmt.Fprintf(writer,"Successfully authenticated with %s!\n\n",auth.Type.Pretty())
70+
}
71+
returnnil
72+
}

‎cli/cliui/gitauth_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package cliui_test
2+
3+
import (
4+
"context"
5+
"net/url"
6+
"sync/atomic"
7+
"testing"
8+
"time"
9+
10+
"github.com/spf13/cobra"
11+
"github.com/stretchr/testify/assert"
12+
13+
"github.com/coder/coder/cli/cliui"
14+
"github.com/coder/coder/codersdk"
15+
"github.com/coder/coder/pty/ptytest"
16+
"github.com/coder/coder/testutil"
17+
)
18+
19+
funcTestGitAuth(t*testing.T) {
20+
t.Parallel()
21+
22+
ctx,cancel:=context.WithTimeout(context.Background(),testutil.WaitShort)
23+
defercancel()
24+
25+
ptty:=ptytest.New(t)
26+
cmd:=&cobra.Command{
27+
RunE:func(cmd*cobra.Command,args []string)error {
28+
varfetched atomic.Bool
29+
returncliui.GitAuth(cmd.Context(),cmd.OutOrStdout(), cliui.GitAuthOptions{
30+
Fetch:func(ctx context.Context) ([]codersdk.TemplateVersionGitAuth,error) {
31+
deferfetched.Store(true)
32+
return []codersdk.TemplateVersionGitAuth{{
33+
ID:"github",
34+
Type:codersdk.GitProviderGitHub,
35+
Authenticated:fetched.Load(),
36+
AuthenticateURL:"https://example.com/gitauth/github?redirect="+url.QueryEscape("/gitauth?notify"),
37+
}},nil
38+
},
39+
FetchInterval:time.Millisecond,
40+
})
41+
},
42+
}
43+
cmd.SetOutput(ptty.Output())
44+
cmd.SetIn(ptty.Input())
45+
done:=make(chanstruct{})
46+
gofunc() {
47+
deferclose(done)
48+
err:=cmd.Execute()
49+
assert.NoError(t,err)
50+
}()
51+
ptty.ExpectMatchContext(ctx,"You must authenticate with")
52+
ptty.ExpectMatchContext(ctx,"https://example.com/gitauth/github")
53+
ptty.ExpectMatchContext(ctx,"Successfully authenticated with GitHub")
54+
<-done
55+
}

‎cli/create.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cli
22

33
import (
4+
"context"
45
"fmt"
56
"io"
67
"time"
@@ -324,6 +325,15 @@ PromptRichParamLoop:
324325
_,_=fmt.Fprintln(cmd.OutOrStdout())
325326
}
326327

328+
err=cliui.GitAuth(ctx,cmd.OutOrStdout(), cliui.GitAuthOptions{
329+
Fetch:func(ctx context.Context) ([]codersdk.TemplateVersionGitAuth,error) {
330+
returnclient.TemplateVersionGitAuth(ctx,templateVersion.ID)
331+
},
332+
})
333+
iferr!=nil {
334+
returnnil,xerrors.Errorf("template version git auth: %w",err)
335+
}
336+
327337
// Run a dry-run with the given parameters to check correctness
328338
dryRun,err:=client.CreateTemplateVersionDryRun(cmd.Context(),templateVersion.ID, codersdk.CreateTemplateVersionDryRunRequest{
329339
WorkspaceName:args.NewWorkspaceName,

‎cli/create_test.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,21 @@ package cli_test
33
import (
44
"context"
55
"fmt"
6+
"net/http"
7+
"net/url"
68
"os"
9+
"regexp"
710
"testing"
811
"time"
912

1013
"github.com/stretchr/testify/assert"
1114
"github.com/stretchr/testify/require"
15+
"golang.org/x/oauth2"
1216

1317
"github.com/coder/coder/cli/clitest"
1418
"github.com/coder/coder/coderd/coderdtest"
19+
"github.com/coder/coder/coderd/database"
20+
"github.com/coder/coder/coderd/gitauth"
1521
"github.com/coder/coder/codersdk"
1622
"github.com/coder/coder/provisioner/echo"
1723
"github.com/coder/coder/provisionersdk/proto"
@@ -603,6 +609,61 @@ func TestCreateValidateRichParameters(t *testing.T) {
603609
})
604610
}
605611

612+
funcTestCreateWithGitAuth(t*testing.T) {
613+
t.Parallel()
614+
echoResponses:=&echo.Responses{
615+
Parse:echo.ParseComplete,
616+
ProvisionPlan: []*proto.Provision_Response{
617+
{
618+
Type:&proto.Provision_Response_Complete{
619+
Complete:&proto.Provision_Complete{
620+
GitAuthProviders: []string{"github"},
621+
},
622+
},
623+
},
624+
},
625+
ProvisionApply: []*proto.Provision_Response{{
626+
Type:&proto.Provision_Response_Complete{
627+
Complete:&proto.Provision_Complete{},
628+
},
629+
}},
630+
}
631+
632+
client:=coderdtest.New(t,&coderdtest.Options{
633+
GitAuthConfigs: []*gitauth.Config{{
634+
OAuth2Config:&oauth2Config{},
635+
ID:"github",
636+
Regex:regexp.MustCompile(`github\.com`),
637+
Type:codersdk.GitProviderGitHub,
638+
}},
639+
IncludeProvisionerDaemon:true,
640+
})
641+
user:=coderdtest.CreateFirstUser(t,client)
642+
version:=coderdtest.CreateTemplateVersion(t,client,user.OrganizationID,echoResponses)
643+
coderdtest.AwaitTemplateVersionJob(t,client,version.ID)
644+
template:=coderdtest.CreateTemplate(t,client,user.OrganizationID,version.ID)
645+
646+
cmd,root:=clitest.New(t,"create","my-workspace","--template",template.Name)
647+
clitest.SetupConfig(t,client,root)
648+
doneChan:=make(chanstruct{})
649+
pty:=ptytest.New(t)
650+
cmd.SetIn(pty.Input())
651+
cmd.SetOut(pty.Output())
652+
gofunc() {
653+
deferclose(doneChan)
654+
err:=cmd.Execute()
655+
assert.NoError(t,err)
656+
}()
657+
658+
pty.ExpectMatch("You must authenticate with GitHub to create a workspace")
659+
resp:=coderdtest.RequestGitAuthCallback(t,"github",client)
660+
_=resp.Body.Close()
661+
require.Equal(t,http.StatusTemporaryRedirect,resp.StatusCode)
662+
pty.ExpectMatch("Confirm create?")
663+
pty.WriteLine("yes")
664+
<-doneChan
665+
}
666+
606667
funccreateTestParseResponseWithDefault(defaultValuestring) []*proto.Parse_Response {
607668
return []*proto.Parse_Response{{
608669
Type:&proto.Parse_Response_Complete{
@@ -638,3 +699,31 @@ func createTestParseResponseWithDefault(defaultValue string) []*proto.Parse_Resp
638699
},
639700
}}
640701
}
702+
703+
typeoauth2Configstruct{}
704+
705+
func (*oauth2Config)AuthCodeURL(statestring,_...oauth2.AuthCodeOption)string {
706+
return"/?state="+url.QueryEscape(state)
707+
}
708+
709+
func (*oauth2Config)Exchange(context.Context,string,...oauth2.AuthCodeOption) (*oauth2.Token,error) {
710+
return&oauth2.Token{
711+
AccessToken:"token",
712+
RefreshToken:"refresh",
713+
Expiry:database.Now().Add(time.Hour),
714+
},nil
715+
}
716+
717+
func (*oauth2Config)TokenSource(context.Context,*oauth2.Token) oauth2.TokenSource {
718+
return&oauth2TokenSource{}
719+
}
720+
721+
typeoauth2TokenSourcestruct{}
722+
723+
func (*oauth2TokenSource)Token() (*oauth2.Token,error) {
724+
return&oauth2.Token{
725+
AccessToken:"token",
726+
RefreshToken:"refresh",
727+
Expiry:database.Now().Add(time.Hour),
728+
},nil
729+
}

‎cmd/cliui/main.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import (
55
"errors"
66
"fmt"
77
"io"
8+
"net/url"
89
"os"
910
"strings"
11+
"sync/atomic"
1012
"time"
1113

1214
"github.com/spf13/cobra"
@@ -235,6 +237,41 @@ func main() {
235237
},
236238
})
237239

240+
root.AddCommand(&cobra.Command{
241+
Use:"git-auth",
242+
RunE:func(cmd*cobra.Command,args []string)error {
243+
varcount atomic.Int32
244+
vargithubAuthed atomic.Bool
245+
vargitlabAuthed atomic.Bool
246+
gofunc() {
247+
// Sleep to display the loading indicator.
248+
time.Sleep(time.Second)
249+
// Swap to true to display success and move onto GitLab.
250+
githubAuthed.Store(true)
251+
// Show the loading indicator again...
252+
time.Sleep(time.Second*2)
253+
// Complete the auth!
254+
gitlabAuthed.Store(true)
255+
}()
256+
returncliui.GitAuth(cmd.Context(),cmd.OutOrStdout(), cliui.GitAuthOptions{
257+
Fetch:func(ctx context.Context) ([]codersdk.TemplateVersionGitAuth,error) {
258+
count.Add(1)
259+
return []codersdk.TemplateVersionGitAuth{{
260+
ID:"github",
261+
Type:codersdk.GitProviderGitHub,
262+
Authenticated:githubAuthed.Load(),
263+
AuthenticateURL:"https://example.com/gitauth/github?redirect="+url.QueryEscape("/gitauth?notify"),
264+
}, {
265+
ID:"gitlab",
266+
Type:codersdk.GitProviderGitLab,
267+
Authenticated:gitlabAuthed.Load(),
268+
AuthenticateURL:"https://example.com/gitauth/gitlab?redirect="+url.QueryEscape("/gitauth?notify"),
269+
}},nil
270+
},
271+
})
272+
},
273+
})
274+
238275
err:=root.Execute()
239276
iferr!=nil {
240277
_,_=fmt.Println(err.Error())

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp