Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Christenson II committed Nov 22, 2023
2 parents 1fd7dc2 + ea60669 commit 60f801c
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 81 deletions.
24 changes: 23 additions & 1 deletion internal/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,29 @@ func WaitUntilUserLogsIn(ctx context.Context, httpClient *http.Client, state Sta
}
}

var RequiredScopes = []string{
"openid",
"offline_access", // for retrieving refresh token
"create:clients", "delete:clients", "read:clients", "update:clients",
"read:client_grants",
"create:resource_servers", "delete:resource_servers", "read:resource_servers", "update:resource_servers",
"create:roles", "delete:roles", "read:roles", "update:roles",
"create:rules", "delete:rules", "read:rules", "update:rules",
"create:users", "delete:users", "read:users", "update:users",
"read:branding", "update:branding",
"read:email_templates", "update:email_templates",
"read:email_provider",
"read:connections", "update:connections",
"read:client_keys", "read:logs", "read:tenant_settings",
"read:custom_domains", "create:custom_domains", "update:custom_domains", "delete:custom_domains",
"read:anomaly_blocks", "delete:anomaly_blocks",
"create:log_streams", "delete:log_streams", "read:log_streams", "update:log_streams",
"create:actions", "delete:actions", "read:actions", "update:actions",
"create:organizations", "delete:organizations", "read:organizations", "update:organizations", "read:organization_members", "read:organization_member_roles", "read:organization_connections",
"read:prompts", "update:prompts",
"read:attack_protection", "update:attack_protection",
}

// GetDeviceCode kicks-off the device authentication flow by requesting
// a device code from Auth0. The returned state contains the
// URI for the next step of the flow.
Expand Down Expand Up @@ -212,7 +235,6 @@ func GetAccessTokenFromClientCreds(ctx context.Context, args ClientCredentials)
TokenURL: u.String() + "/oauth/token",
EndpointParams: url.Values{
"client_id": {args.ClientID},
"scope": {strings.Join(RequiredScopesForClientCreds(), " ")},
"audience": {u.String() + "/api/v2/"},
},
}
Expand Down
37 changes: 0 additions & 37 deletions internal/auth/scopes.go

This file was deleted.

22 changes: 21 additions & 1 deletion internal/cli/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ func deployActionCmd(cli *cli) *cobra.Command {
auth0 actions deploy <action-id> --json`,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
if err := actionID.Pick(cmd, &inputs.ID, cli.actionPickerOptions); err != nil {
if err := actionID.Pick(cmd, &inputs.ID, cli.undeployedActionPickerOptions); err != nil {
return err
}
} else {
Expand Down Expand Up @@ -498,6 +498,26 @@ func (c *cli) actionPickerOptions(ctx context.Context) (pickerOptions, error) {
return opts, nil
}

func (c *cli) undeployedActionPickerOptions(ctx context.Context) (pickerOptions, error) {
list, err := c.api.Action.List(ctx, management.Parameter("deployed", "false"))
if err != nil {
return nil, err
}

var opts pickerOptions
for _, r := range list.Actions {
label := fmt.Sprintf("%s %s", r.GetName(), ansi.Faint("("+r.GetID()+")"))

opts = append(opts, pickerOption{value: r.GetID(), label: label})
}

if len(opts) == 0 {
return nil, errors.New("There are currently no actions to deploy.")
}

return opts, nil
}

func (c *cli) actionEditorHint() {
c.renderer.Infof("%s Once you close the editor, the action will be saved. To cancel, press CTRL+C.", ansi.Faint("Hint:"))
}
Expand Down
79 changes: 79 additions & 0 deletions internal/cli/actions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,85 @@ func TestActionsPickerOptions(t *testing.T) {
}
}

func TestUndeployedActionsPickerOptions(t *testing.T) {
tests := []struct {
name string
actions []*management.Action
apiError error
assertOutput func(t testing.TB, options pickerOptions)
assertError func(t testing.TB, err error)
}{
{
name: "happy path",
actions: []*management.Action{
{
ID: auth0.String("some-id-1"),
Name: auth0.String("some-name-1"),
},
{
ID: auth0.String("some-id-2"),
Name: auth0.String("some-name-2"),
},
},
assertOutput: func(t testing.TB, options pickerOptions) {
assert.Len(t, options, 2)
assert.Equal(t, "some-name-1 (some-id-1)", options[0].label)
assert.Equal(t, "some-id-1", options[0].value)
assert.Equal(t, "some-name-2 (some-id-2)", options[1].label)
assert.Equal(t, "some-id-2", options[1].value)
},
assertError: func(t testing.TB, err error) {
t.Fail()
},
},
{
name: "no actions",
actions: []*management.Action{},
assertOutput: func(t testing.TB, options pickerOptions) {
t.Fail()
},
assertError: func(t testing.TB, err error) {
assert.ErrorContains(t, err, "There are currently no actions to deploy.")
},
},
{
name: "API error",
apiError: errors.New("error"),
assertOutput: func(t testing.TB, options pickerOptions) {
t.Fail()
},
assertError: func(t testing.TB, err error) {
assert.Error(t, err)
},
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

actionAPI := mock.NewMockActionAPI(ctrl)
actionAPI.EXPECT().
List(gomock.Any(), gomock.Any()).
Return(&management.ActionList{
Actions: test.actions}, test.apiError)

cli := &cli{
api: &auth0.API{Action: actionAPI},
}

options, err := cli.undeployedActionPickerOptions(context.Background())

if err != nil {
test.assertError(t, err)
} else {
test.assertOutput(t, options)
}
})
}
}

func TestActionsInputSecretsToActionSecrets(t *testing.T) {
t.Run("it should map input secrets to action payload", func(t *testing.T) {
input := map[string]string{
Expand Down
67 changes: 48 additions & 19 deletions internal/cli/organizations.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,8 +523,7 @@ func listMembersOrganizationCmd(cli *cli) *cobra.Command {
}

if len(args) == 0 {
err := organizationID.Pick(cmd, &inputs.ID, cli.organizationPickerOptions)
if err != nil {
if err := organizationID.Pick(cmd, &inputs.ID, cli.organizationPickerOptions); err != nil {
return err
}
} else {
Expand All @@ -535,8 +534,11 @@ func listMembersOrganizationCmd(cli *cli) *cobra.Command {
if err != nil {
return err
}

sortMembers(members)

cli.renderer.MembersList(members)

return nil
},
}
Expand Down Expand Up @@ -584,9 +586,9 @@ func listRolesOrganizationCmd(cli *cli) *cobra.Command {
if inputs.Number < 1 || inputs.Number > 1000 {
return fmt.Errorf("number flag invalid, please pass a number between 1 and 1000")
}

if len(args) == 0 {
err := organizationID.Pick(cmd, &inputs.OrgID, cli.organizationPickerOptions)
if err != nil {
if err := organizationID.Pick(cmd, &inputs.OrgID, cli.organizationPickerOptions); err != nil {
return err
}
} else {
Expand All @@ -597,12 +599,16 @@ func listRolesOrganizationCmd(cli *cli) *cobra.Command {
if err != nil {
return err
}

roleMap, err := cli.getOrgMemberRolesWithSpinner(cmd.Context(), inputs.OrgID, members)
if err != nil {
return err
}

roles := cli.convertOrgRolesToManagementRoles(roleMap)

cli.renderer.RoleList(roles)

return nil
},
}
Expand Down Expand Up @@ -775,15 +781,17 @@ func (cli *cli) getOrgMembers(
output = append(output, member)
}
return output, members.HasNext(), nil
})

},
)
if err != nil {
return nil, fmt.Errorf("Unable to list members of an organization with ID '%s': %w", orgID, err)
return nil, fmt.Errorf("failed to list members of an organization with ID %q: %w", orgID, err)
}

var typedList []management.OrganizationMember
for _, item := range list {
typedList = append(typedList, item.(management.OrganizationMember))
}

return typedList, nil
}

Expand All @@ -796,66 +804,87 @@ func sortMembers(members []management.OrganizationMember) {
func (cli *cli) getOrgMembersWithSpinner(context context.Context, orgID string, number int,
) ([]management.OrganizationMember, error) {
var members []management.OrganizationMember
err := ansi.Spinner("Getting members of organization", func() error {
var errInner error
members, errInner = cli.getOrgMembers(context, orgID, number)
return errInner

err := ansi.Waiting(func() (err error) {
members, err = cli.getOrgMembers(context, orgID, number)
return err
})

return members, err
}

func (cli *cli) getOrgMemberRolesWithSpinner(ctx context.Context, orgID string, members []management.OrganizationMember,
) (map[string]management.OrganizationMemberRole, error) {
roleMap := make(map[string]management.OrganizationMemberRole)
err := ansi.Spinner("Getting roles for each member", func() error {

err := ansi.Waiting(func() (err error) {
for _, member := range members {
userID := member.GetUserID()
roleList, errInner := cli.api.Organization.MemberRoles(ctx, orgID, userID)
if errInner != nil {
return errInner

roleList, err := cli.api.Organization.MemberRoles(ctx, orgID, userID)
if err != nil {
return err
}

for _, role := range roleList.Roles {
roleID := role.GetID()
if _, exists := roleMap[roleID]; !exists {
roleMap[roleID] = role
}
}
}

return nil
})

return roleMap, err
}

func (cli *cli) convertOrgRolesToManagementRoles(roleMap map[string]management.OrganizationMemberRole,
) []*management.Role {
var roles []*management.Role
for _, role := range roleMap {
roles = append(roles, &management.Role{ID: role.ID, Name: role.Name, Description: role.Description})
roles = append(roles, &management.Role{
ID: role.ID,
Name: role.Name,
Description: role.Description,
})
}

sort.Slice(roles, func(i, j int) bool {
return strings.ToLower(roles[i].GetName()) < strings.ToLower(roles[j].GetName())
})

return roles
}

func (cli *cli) getOrgRoleMembersWithSpinner(ctx context.Context, orgID string, roleID string, members []management.OrganizationMember,
func (cli *cli) getOrgRoleMembersWithSpinner(
ctx context.Context,
orgID string,
roleID string,
members []management.OrganizationMember,
) ([]management.OrganizationMember, error) {
var roleMembers []management.OrganizationMember
errSpinner := ansi.Spinner("Getting roles assigned to organization members", func() error {

err := ansi.Waiting(func() (err error) {
for _, member := range members {
userID := member.GetUserID()

roleList, err := cli.api.Organization.MemberRoles(ctx, orgID, userID)
if err != nil {
return err
}

for _, role := range roleList.Roles {
id := role.GetID()
if id == roleID {
roleMembers = append(roleMembers, member)
}
}
}

return nil
})
return roleMembers, errSpinner

return roleMembers, err
}
Loading

0 comments on commit 60f801c

Please sign in to comment.