Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
51 changes: 26 additions & 25 deletions cmd/src/auth.go
Original file line number Diff line number Diff line change
@@ -1,37 +1,38 @@
package main

import (
"flag"
"fmt"
)
"context"

var authCommands commander
"github.com/sourcegraph/src-cli/internal/clicompat"
"github.com/urfave/cli/v3"
)

func init() {
usage := `'src auth' provides authentication-related helper commands.
const authExamples = `
Authentication-related helper commands.

Usage:
Examples:

src auth command [command options]
Print the active auth token:

The commands are:
$ src auth token
sgp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

token prints the current authentication token or Authorization header
Print the current Authorization header:

Use "src auth [command] -h" for more information about a command.
$ src auth token --header
Authorization: token sgp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
`

flagSet := flag.NewFlagSet("auth", flag.ExitOnError)
handler := func(args []string) error {
authCommands.run(flagSet, "src auth", usage, args)
return nil
}

commands = append(commands, &command{
flagSet: flagSet,
handler: handler,
usageFunc: func() {
fmt.Println(usage)
},
})
}
var authCommand = clicompat.Wrap(&cli.Command{
Name: "auth",
Usage: "authentication helper commands",
UsageText: "src auth [command options]",
Description: authExamples,
HideVersion: true,
Commands: []*cli.Command{
authTokenCommand,
},
Action: func(ctx context.Context, cmd *cli.Command) error {
return cli.ShowSubcommandHelp(cmd)
},
})
68 changes: 42 additions & 26 deletions cmd/src/auth_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package main

import (
"context"
"flag"
"fmt"

"github.com/sourcegraph/sourcegraph/lib/errors"

"github.com/sourcegraph/src-cli/internal/clicompat"
"github.com/sourcegraph/src-cli/internal/oauth"
"github.com/urfave/cli/v3"
)

var (
Expand All @@ -21,37 +22,52 @@ type oauthTokenRefresher interface {
GetToken(ctx context.Context) (oauth.Token, error)
}

func init() {
flagSet := flag.NewFlagSet("token", flag.ExitOnError)
header := flagSet.Bool("header", false, "print the token as an Authorization header")
usageFunc := func() {
fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src auth token':\n\n")
fmt.Fprintf(flag.CommandLine.Output(), "Print the current authentication token.\n")
fmt.Fprintf(flag.CommandLine.Output(), "Use --header to print a complete Authorization header instead.\n\n")
flagSet.PrintDefaults()
}
const authTokenExamples = `
Print the current authentication token.

handler := func(args []string) error {
if err := flagSet.Parse(args); err != nil {
return err
}
Use --header to print a complete Authorization header instead.

Examples:

Raw token output:

$ src auth token
sgp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Authorization header output:

token, err := resolveAuthToken(context.Background(), cfg)
$ src auth token --header
Authorization: token sgp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

If you are authenticated with OAuth instead of SRC_ACCESS_TOKEN, the header uses the Bearer scheme:

$ src auth token --header
Authorization: Bearer eyJhbGciOi...
`

var authTokenCommand = clicompat.Wrap(&cli.Command{
Name: "token",
Usage: "prints the current authentication token or Authorization header",
UsageText: "src auth token [options]",
Description: authTokenExamples,
HideVersion: true,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "header",
Usage: "print the token as an Authorization header",
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
token, err := resolveAuthToken(ctx, cfg)
if err != nil {
return err
}

token = formatAuthTokenOutput(token, cfg.AuthMode(), *header)
fmt.Println(token)
return nil
}

authCommands = append(authCommands, &command{
flagSet: flagSet,
handler: handler,
usageFunc: usageFunc,
})
}
token = formatAuthTokenOutput(token, cfg.AuthMode(), cmd.Bool("header"))
_, err = fmt.Fprintln(cmd.Writer, token)
return err
},
})

func resolveAuthToken(ctx context.Context, cfg *config) (string, error) {
if err := cfg.requireCIAccessToken(); err != nil {
Expand Down
27 changes: 27 additions & 0 deletions cmd/src/auth_token_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"bytes"
"context"
"fmt"
"net/url"
Expand Down Expand Up @@ -125,6 +126,32 @@ func TestResolveAuthToken(t *testing.T) {
})
}

func TestAuthTokenCommand(t *testing.T) {
reset := stubAuthTokenDependencies(t)
defer reset()

prevCfg := cfg
defer func() { cfg = prevCfg }()

cfg = &config{
accessToken: "access-token",
endpointURL: mustParseURL(t, "https://example.com"),
}

var out bytes.Buffer
cmd := *authTokenCommand
cmd.Writer = &out
cmd.ErrWriter = &out

err := cmd.Run(context.Background(), []string{"token", "--header"})
if err != nil {
t.Fatal(err)
}
if out.String() != "Authorization: token access-token\n" {
t.Fatalf("output = %q, want %q", out.String(), "Authorization: token access-token\n")
}
}

func TestFormatAuthTokenOutput(t *testing.T) {
tests := []struct {
name string
Expand Down
1 change: 1 addition & 0 deletions cmd/src/run_migration_compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (

var migratedCommands = map[string]*cli.Command{
"abc": abcCommand,
"auth": authCommand,
"version": versionCommand,
}

Expand Down
Loading