diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 1e7ef711b..4674cfb65 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -2,6 +2,9 @@ name: Go on: [push, pull_request] +env: + GO_VERSION: 1.19.4 + concurrency: group: one-at-time cancel-in-progress: false @@ -18,7 +21,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.19.3 + go-version: ${{env.GO_VERSION}} - name: Check out the code uses: actions/checkout@v3 @@ -45,7 +48,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.19.3 + go-version: ${{env.GO_VERSION}} - name: Check out the code uses: actions/checkout@v3 @@ -58,8 +61,6 @@ jobs: AUTH0_CLI_CLIENT_DOMAIN: ${{ secrets.AUTH0_CLI_CLIENT_DOMAIN }} AUTH0_CLI_CLIENT_ID: ${{ secrets.AUTH0_CLI_CLIENT_ID }} AUTH0_CLI_CLIENT_SECRET: ${{ secrets.AUTH0_CLI_CLIENT_SECRET }} - AUTH0_CLI_REUSE_CONFIG: ${{ secrets.AUTH0_CLI_REUSE_CONFIG }} - AUTH0_CLI_OVERWRITE: ${{ secrets.AUTH0_CLI_OVERWRITE }} build: name: Build @@ -72,7 +73,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.19.3 + go-version: ${{env.GO_VERSION}} - name: Check out the code uses: actions/checkout@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 69b85de47..ad906263c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,9 @@ on: pull_request: push: +env: + GO_VERSION: 1.19.4 + jobs: goreleaser: runs-on: ubuntu-latest @@ -20,7 +23,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.19.3 + go-version: ${{env.GO_VERSION}} - name: Run GoReleaser uses: goreleaser/goreleaser-action@v3 diff --git a/cmd/build_doc/main.go b/cmd/build_doc/main.go index 70078d453..564ecb716 100644 --- a/cmd/build_doc/main.go +++ b/cmd/build_doc/main.go @@ -1,20 +1,11 @@ package main import ( - "github.com/joeshaw/envdecode" - "github.com/auth0/auth0-cli/internal/cli" ) func main() { - var cfg struct { - Path string `env:"AUTH0_CLI_DOCS_PATH,default=./docs/"` - } - if err := envdecode.StrictDecode(&cfg); err != nil { - panic(err) - } - - err := cli.BuildDoc(cfg.Path) + err := cli.BuildDoc() if err != nil { panic(err) } diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 7358f2c72..673c15ee5 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -212,12 +212,12 @@ GEM jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) minitest (5.16.3) - nokogiri (1.13.9) + nokogiri (1.13.10) mini_portile2 (~> 2.8.0) racc (~> 1.4) - nokogiri (1.13.9-x86_64-darwin) + nokogiri (1.13.10-x86_64-darwin) racc (~> 1.4) - nokogiri (1.13.9-x86_64-linux) + nokogiri (1.13.10-x86_64-linux) racc (~> 1.4) octokit (4.25.1) faraday (>= 1, < 3) @@ -225,7 +225,7 @@ GEM pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (4.0.7) - racc (1.6.0) + racc (1.6.1) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) diff --git a/docs/auth0_login.md b/docs/auth0_login.md index 0c78e2253..e22cb0f2e 100644 --- a/docs/auth0_login.md +++ b/docs/auth0_login.md @@ -7,7 +7,7 @@ Authenticate the Auth0 CLI ### Synopsis -Authenticates the Auth0 CLI either as a user using personal credentials or as a machine using client credentials (client ID/secret). +Authenticates the Auth0 CLI either as a user using personal credentials or as a machine using client credentials. ``` auth0 login [flags] @@ -16,18 +16,16 @@ auth0 login [flags] ### Examples ``` - - auth0 login - auth0 login --domain --client-id --client-secret - +auth0 login +auth0 login --domain --client-id --client-secret ``` ### Options ``` - -i, --client-id string Client ID of the application. - -s, --client-secret string Client Secret of the application. - --domain string Specifies tenant domain when authenticating via client credentials (client ID, client secret) + --client-id string Client ID of the application when authenticating via client credentials. + --client-secret string Client secret of the application when authenticating via client credentials. + --domain string Tenant domain of the application when authenticating via client credentials. -h, --help help for login ``` diff --git a/docs/ci.md b/docs/ci.md deleted file mode 100644 index d54589427..000000000 --- a/docs/ci.md +++ /dev/null @@ -1,25 +0,0 @@ -# Continuous Integration - -## Integration Tests - -Integration tests can be run with: -```bash -make integration -``` - -`make integration` will build and run the `auth0-cli-config-generator` command which is responsible for ensuring that a valid auth0-cli config file exists before the integration tests run. If a valid auth0-cli config file doesn't exist, `auth0-cli-config-generator` will attempt to generate one based off command line flags or/and environment variables. - -`make integration` will then use [commander](https://github.com/commander-cli/commander) to run tests defined in [commander.yaml](./commander.yaml) - -The entities created during integration tests will be cleaned afterwards by the script `integration/test-cleanup.sh`. All the entities prefixed `integration-test-` will be deleted. - -To run integration tests as part of a CI pipeline, several environment variables need to be exported first. When these variables are set, `auth0-cli-config-generator` will generate a valid auth0-cli config file being retrieving a token for the client, removing the need to run `auth0 login`: -```bash -export AUTH0_CLI_CLIENT_NAME="integration" \ - AUTH0_CLI_CLIENT_DOMAIN="example-test-domain.au.auth0.com" \ - AUTH0_CLI_CLIENT_ID="example-client-id" \ - AUTH0_CLI_CLIENT_SECRET="example-client-secret" \ - AUTH0_CLI_REUSE_CONFIG="false" \ - AUTH0_CLI_OVERWRITE="true" -make integration -``` diff --git a/go.mod b/go.mod index 14c53cda2..502c6f286 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/briandowns/spinner v1.19.0 github.com/charmbracelet/glamour v0.6.0 github.com/fsnotify/fsnotify v1.6.0 - github.com/getsentry/sentry-go v0.15.0 + github.com/getsentry/sentry-go v0.16.0 github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.5.9 github.com/google/uuid v1.3.0 diff --git a/go.sum b/go.sum index bc7e16643..7301328b7 100644 --- a/go.sum +++ b/go.sum @@ -104,8 +104,8 @@ github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYF github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/getsentry/sentry-go v0.15.0 h1:CP9bmA7pralrVUedYZsmIHWpq/pBtXTSew7xvVpfLaA= -github.com/getsentry/sentry-go v0.15.0/go.mod h1:RZPJKSw+adu8PBNygiri/A98FqVr2HtRckJk9XVxJ9I= +github.com/getsentry/sentry-go v0.16.0 h1:owk+S+5XcgJLlGR/3+3s6N4d+uKwqYvh/eS0AIMjPWo= +github.com/getsentry/sentry-go v0.16.0/go.mod h1:ZXCloQLj0pG7mja5NK6NPf2V4A88YJ4pNlc2mOHwh6Y= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= diff --git a/internal/auth/auth.go b/internal/auth/auth.go index 2a61fdc1b..9955fe8e3 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -288,7 +288,7 @@ type ClientCredentials struct { } // GetAccessTokenFromClientCreds generates an access token from client credentials -func GetAccessTokenFromClientCreds(args ClientCredentials) (Result, error) { +func GetAccessTokenFromClientCreds(ctx context.Context, args ClientCredentials) (Result, error) { u, err := url.Parse("https://" + args.Domain) if err != nil { return Result{}, err @@ -305,7 +305,7 @@ func GetAccessTokenFromClientCreds(args ClientCredentials) (Result, error) { }, } - resp, err := credsConfig.Token(context.Background()) + resp, err := credsConfig.Token(ctx) if err != nil { return Result{}, err } diff --git a/internal/cli/build_doc.go b/internal/cli/build_doc.go index b3f44d10e..e27e0674b 100644 --- a/internal/cli/build_doc.go +++ b/internal/cli/build_doc.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/cobra/doc" ) -func BuildDoc(path string) error { +func BuildDoc() error { cli := &cli{} rootCmd := &cobra.Command{ @@ -20,8 +20,10 @@ func BuildDoc(path string) error { addPersistentFlags(rootCmd, cli) addSubcommands(rootCmd, cli) + docsPath := "./docs/" + err := doc.GenMarkdownTreeCustom(rootCmd, - path, + docsPath, func(fileName string) string { // prepend to the generated markdown if strings.HasSuffix(fileName, "auth0.md") { diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 51c5e55ac..c98224b15 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -21,6 +21,7 @@ import ( "github.com/spf13/pflag" "github.com/auth0/auth0-cli/internal/analytics" + "github.com/auth0/auth0-cli/internal/ansi" "github.com/auth0/auth0-cli/internal/auth" "github.com/auth0/auth0-cli/internal/auth0" "github.com/auth0/auth0-cli/internal/buildinfo" @@ -109,11 +110,14 @@ func (t *Tenant) hasExpiredToken() bool { func (t *Tenant) regenerateAccessToken(ctx context.Context, c *cli) error { if t.authenticatedWithClientCredentials() { - token, err := auth.GetAccessTokenFromClientCreds(auth.ClientCredentials{ - ClientID: t.ClientID, - ClientSecret: t.ClientSecret, - Domain: t.Domain, - }) + token, err := auth.GetAccessTokenFromClientCreds( + ctx, + auth.ClientCredentials{ + ClientID: t.ClientID, + ClientSecret: t.ClientSecret, + Domain: t.Domain, + }, + ) if err != nil { return err } @@ -208,7 +212,7 @@ func (c *cli) prepareTenant(ctx context.Context) (Tenant, error) { } if scopesChanged(t) && t.authenticatedWithDeviceCodeFlow() { - c.renderer.Warnf("Required scopes have changed. Please log in to re-authorize the CLI.") + c.renderer.Warnf("Required scopes have changed. Please log in to re-authorize the CLI.\n") return RunLoginAsUser(ctx, c) } @@ -218,12 +222,17 @@ func (c *cli) prepareTenant(ctx context.Context) (Tenant, error) { if err := t.regenerateAccessToken(ctx, c); err != nil { if t.authenticatedWithClientCredentials() { - return t, fmt.Errorf("Failed to renew access token. This may occur if the designated application has been deleted or client secret has been rotated. Please re-authenticate by running `auth0 login --as-machine`") + return t, fmt.Errorf( + "failed to fetch access token using client credentials.\n\n"+ + "This may occur if the designated application has been deleted or the client secret has been rotated.\n\n"+ + "Please re-authenticate by running: %s", + ansi.Bold("auth0 login --domain --client-secret "), + ) } - c.renderer.Warnf("Failed to renew access token. Please log in to re-authorize the CLI.") - return RunLoginAsUser(ctx, c) + c.renderer.Warnf("Failed to renew access token. Please log in to re-authorize the CLI.\n") + return RunLoginAsUser(ctx, c) } if err := c.addTenant(t); err != nil { diff --git a/internal/cli/login.go b/internal/cli/login.go index d86bda50b..ffc447f9f 100644 --- a/internal/cli/login.go +++ b/internal/cli/login.go @@ -14,39 +14,47 @@ import ( var ( loginTenantDomain = Flag{ - Name: "Tenant Domain", - LongForm: "domain", - Help: "Specifies tenant domain when authenticating via client credentials (client ID, client secret)", - IsRequired: false, + Name: "Tenant Domain", + LongForm: "domain", + Help: "Tenant domain of the application when authenticating via client credentials.", + IsRequired: false, + AlwaysPrompt: false, } loginClientID = Flag{ - Name: "Client ID", - LongForm: "client-id", - Help: "Client ID of the application.", - IsRequired: false, + Name: "Client ID", + LongForm: "client-id", + Help: "Client ID of the application when authenticating via client credentials.", + IsRequired: false, + AlwaysPrompt: false, } loginClientSecret = Flag{ - Name: "Client Secret", - LongForm: "client-secret", - Help: "Client Secret of the application.", - IsRequired: false, - } - - loginAsUser = Flag{ - Name: "Login as user", - LongForm: "as-user", - Help: "Initializes login as a user via device code flow.", - IsRequired: false, + Name: "Client Secret", + LongForm: "client-secret", + Help: "Client secret of the application when authenticating via client credentials.", + IsRequired: false, + AlwaysPrompt: false, } + + loginAsUser = Flag{ + Name: "Login as user", + LongForm: "as-user", + Help: "Initializes login as a user via device code flow.", + IsRequired: false, + AlwaysPrompt: false, + } ) type LoginInputs struct { Domain string ClientID string ClientSecret string - LoginAsUser bool + LoginAsUser bool +} + +func (i *LoginInputs) shouldLoginAsMachine() bool { + return i.ClientID != "" || i.ClientSecret != "" || i.Domain != "" } func loginCmd(cli *cli) *cobra.Command { @@ -126,7 +134,6 @@ func loginCmd(cli *cli) *cobra.Command { cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) { _ = cmd.Flags().MarkHidden("tenant") _ = cmd.Flags().MarkHidden("json") - _ = cmd.Flags().MarkHidden("no-input") cmd.Parent().HelpFunc()(cmd, args) }) @@ -238,13 +245,18 @@ func RunLoginAsMachine(ctx context.Context, inputs LoginInputs, cli *cli, cmd *c return err } - token, err := auth.GetAccessTokenFromClientCreds(auth.ClientCredentials{ - ClientID: inputs.ClientID, - ClientSecret: inputs.ClientSecret, - Domain: inputs.Domain, - }) + token, err := auth.GetAccessTokenFromClientCreds( + ctx, + auth.ClientCredentials{ + ClientID: inputs.ClientID, + ClientSecret: inputs.ClientSecret, + Domain: inputs.Domain, + }, + ) if err != nil { - return err + return fmt.Errorf( + "failed to fetch access token using client credentials. \n\n"+ + "Ensure that the provided client-id, client-secret and domain are correct. \n\nerror: %w\n", err) } t := Tenant{ @@ -259,5 +271,13 @@ func RunLoginAsMachine(ctx context.Context, inputs LoginInputs, cli *cli, cmd *c return fmt.Errorf("unexpected error when attempting to save tenant data: %w", err) } + cli.renderer.Newline() + cli.renderer.Infof("Successfully logged in.") + cli.renderer.Infof("Tenant: %s", inputs.Domain) + + if err := checkInstallID(cli); err != nil { + return fmt.Errorf("failed to update the config: %w", err) + } + return nil }