10000 feat: add `external-auth` cli by kylecarbs · Pull Request #10052 · coder/coder · GitHub
[go: up one dir, main page]

Skip to content

feat: add external-auth cli #10052

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

Merged
merged 10 commits into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Add external-auth subcommand
  • Loading branch information
kylecarbs committed Oct 9, 2023
commit 64f22416f0fd99de8192ed882e226792403485ed
61 changes: 47 additions & 14 deletions cli/externalauth.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
package cli

import "github.com/coder/coder/v2/cli/clibase"
import (
"os/signal"

"golang.org/x/xerrors"

"github.com/coder/coder/v2/cli/clibase"
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/codersdk/agentsdk"
)

func (r *RootCmd) externalAuth() *clibase.Cmd {
return &clibase.Cmd{
Expand All @@ -10,27 +18,20 @@ func (r *RootCmd) externalAuth() *clibase.Cmd {
Handler: func(i *clibase.Invocation) error {
return i.Command.HelpHandler(i)
},
}
}

func (r *RootCmd) externalAuthList() *clibase.Cmd {
return &clibase.Cmd{
Use: "list",
Short: "List external authentication providers",
Long: "List external authentication.",
Handler: func(i *clibase.Invocation) error {
return i.Command.HelpHandler(i)
Children: []*clibase.Cmd{
r.externalAuthAccessToken(),
},
}
}

func (r *RootCmd) externalAuthAccessToken() *clibase.Cmd {
var silent bool
return &clibase.Cmd{
Use: "access-token",
Use: "access-token <provider>",
Short: "Print auth for an external provider",
Long: "Print an access-token for an external auth provider. " +
"The access-token will be validated and sent to stdout with exit code 0. " +
"If a valid access-token cannot be obtained, the URL to authenticate will be sent to stderr with exit code 1\n" + formatExamples(
"If a valid access-token cannot be obtained, the URL to authenticate will be sent to stdout with exit code 1\n" + formatExamples(
example{
Description: "Ensure that the user is authenticated with GitHub before cloning.",
Command: `#!/usr/bin/env sh
Expand All @@ -48,9 +49,41 @@ fi
Name: "Silent",
Flag: "s",
Description: "Do not print the URL or access token.",
Value: clibase.BoolOf(&silent),
}},

Handler: func(i *clibase.Invocation) error {
Handler: func(inv *clibase.Invocation) error {
ctx := inv.Context()

ctx, stop := signal.NotifyContext(ctx, InterruptSignals...)
defer stop()

client, err := r.createAgentClient()
if err != nil {
return xerrors.Errorf("create agent client: %w", err)
}

token, err := client.ExternalAuth(ctx, agentsdk.ExternalAuthRequest{
ID: inv.Args[0],
})
if err != nil {
return xerrors.Errorf("get external auth token: %w", err)
}

if !silent {
if token.URL != "" {
_, err = inv.Stdout.Write([]byte(token.URL))
} else {
_, err = inv.Stdout.Write([]byte(token.AccessToken))
}
if err != nil {
return err
}
}

if token.URL != "" {
return cliui.Canceled
}
return nil
},
}
Expand Down
49 changes: 49 additions & 0 deletions cli/externalauth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package cli_test

import (
"context"
"net/http"
"net/http/httptest"
"testing"

"github.com/coder/coder/v2/cli/clitest"
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/coderd/httpapi"
"github.com/coder/coder/v2/codersdk/agentsdk"
"github.com/coder/coder/v2/pty/ptytest"
)

func TestExternalAuth(t *testing.T) {
t.Parallel()
t.Run("CanceledWithURL", func(t *testing.T) {
t.Parallel()
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
httpapi.Write(context.Background(), w, http.StatusOK, agentsdk.ExternalAuthResponse{
URL: "https://github.com",
})
}))
t.Cleanup(srv.Close)
url := srv.URL
inv, _ := clitest.New(t, "--agent-url", url, "external-auth", "access-token", "github")
pty := ptytest.New(t)
inv.Stdout = pty.Output()
waiter := clitest.StartWithWaiter(t, inv)
pty.ExpectMatch("https://github.com")
waiter.RequireIs(cliui.Canceled)
})
t.Run("SuccessWithToken", func(t *testing.T) {
t.Parallel()
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
httpapi.Write(context.Background(), w, http.StatusOK, agentsdk.ExternalAuthResponse{
AccessToken: "bananas",
})
}))
t.Cleanup(srv.Close)
url := srv.URL
inv, _ := clitest.New(t, "--agent-url", url, "external-auth", "access-token", "github")
pty := ptytest.New(t)
inv.Stdout = pty.Output()
clitest.Start(t, inv)
pty.ExpectMatch("bananas")
})
}
1 change: 1 addition & 0 deletions cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ func (r *RootCmd) Core() []*clibase.Cmd {
// Please re-sort this list alphabetically if you change it!
return []*clibase.Cmd{
r.dotfiles(),
r.externalAuth(),
r.login(),
r.logout(),
r.netcheck(),
Expand Down
5 changes: 2 additions & 3 deletions coderd/apidoc/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions coderd/apidoc/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions docs/api/agents.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Coder — A tool for provisioning self-hosted development environments with Terr
| [<code>create</code>](./cli/create.md) | Create a workspace |
| [<code>delete</code>](./cli/delete.md) | Delete a workspace |
| [<code>dotfiles</code>](./cli/dotfiles.md) | Personalize your workspace by applying a canonical dotfiles repository |
| [<code>external-auth</code>](./cli/external-auth.md) | Manage external authentication |
| [<code>features</code>](./cli/features.md) | List Enterprise features |
| [<code>groups</code>](./cli/groups.md) | Manage groups |
| [<code>licenses</code>](./cli/licenses.md) | Add, delete, and list licenses |
Expand Down
23 changes: 23 additions & 0 deletions docs/cli/external-auth.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions docs/cli/external-auth_access-token.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,16 @@
"description": "Personalize your workspace by applying a canonical dotfiles repository",
"path": "cli/dotfiles.md"
},
{
"title": "external-auth",
"description": "Manage external authentication",
"path": "cli/external-auth.md"
},
{
"title": "external-auth access-token",
"description": "Print auth for an external provider",
"path": "cli/external-auth_access-token.md"
},
{
"title": "features",
"description": "List Enterprise features",
Expand Down
0