• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mongodb / mongodb-atlas-cli / 16670272475

01 Aug 2025 08:27AM UTC coverage: 57.953% (-7.1%) from 65.017%
16670272475

Pull #4071

github

fmenezes
lint
Pull Request #4071: chore: remove unit tag from tests

23613 of 40745 relevant lines covered (57.95%)

2.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.1
/internal/cli/dbusers/create.go
1
// Copyright 2021 MongoDB Inc
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package dbusers
16

17
import (
18
        "context"
19
        "errors"
20
        "fmt"
21

22
        "github.com/AlecAivazis/survey/v2"
23
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli"
24
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/config"
25
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/convert"
26
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/flag"
27
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/store"
28
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/telemetry"
29
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/usage"
30
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/validate"
31
        "github.com/spf13/cobra"
32
        atlasv2 "go.mongodb.org/atlas-sdk/v20250312005/admin"
33
)
34

35
//go:generate go tool go.uber.org/mock/mockgen -typed -destination=create_mock_test.go -package=dbusers . DatabaseUserCreator
36

37
type DatabaseUserCreator interface {
38
        CreateDatabaseUser(*atlasv2.CloudDatabaseUser) (*atlasv2.CloudDatabaseUser, error)
39
}
40

41
type CreateOpts struct {
42
        cli.ProjectOpts
43
        cli.OutputOpts
44
        cli.InputOpts
45
        username    string
46
        password    string
47
        x509Type    string
48
        awsIamType  string
49
        ldapType    string
50
        oidcType    string
51
        deleteAfter string
52
        description string
53
        roles       []string
54
        scopes      []string
55
        store       DatabaseUserCreator
56
}
57

58
const (
59
        user             = "USER"
60
        role             = "ROLE"
61
        group            = "GROUP"
62
        groupIDP         = "IDP_GROUP"
63
        X509TypeManaged  = "MANAGED"
64
        X509TypeCustomer = "CUSTOMER"
65
        none             = "NONE"
66
        createTemplate   = "Database user '{{.Username}}' successfully created.\n"
67
)
68

69
var (
70
        validX509Flags   = []string{none, X509TypeManaged, X509TypeCustomer}
71
        validAWSIAMFlags = []string{none, role, user}
72
        validLDAPFlags   = []string{none, group, user}
73
        validOIDCFlags   = []string{none, groupIDP, user}
74
)
75

76
func (opts *CreateOpts) isX509Set() bool {
1✔
77
        return opts.x509Type != "" && opts.x509Type != none
1✔
78
}
1✔
79

80
func (opts *CreateOpts) isAWSIAMSet() bool {
1✔
81
        return opts.awsIamType != "" && opts.awsIamType != none
1✔
82
}
1✔
83

84
func (opts *CreateOpts) isLDAPSet() bool {
1✔
85
        return opts.ldapType != "" && opts.ldapType != none
1✔
86
}
1✔
87

88
func (opts *CreateOpts) isOIDCSet() bool {
1✔
89
        return opts.oidcType != "" && opts.oidcType != none
1✔
90
}
1✔
91

92
func (opts *CreateOpts) isExternal() bool {
1✔
93
        return opts.isX509Set() || opts.isAWSIAMSet() || opts.isLDAPSet()
1✔
94
}
1✔
95

96
func (opts *CreateOpts) initStore(ctx context.Context) func() error {
1✔
97
        return func() error {
2✔
98
                var err error
1✔
99
                opts.store, err = store.New(store.AuthenticatedPreset(config.Default()), store.WithContext(ctx))
1✔
100
                return err
1✔
101
        }
1✔
102
}
103

104
func (opts *CreateOpts) Run() error {
1✔
105
        u := opts.newDatabaseUser()
1✔
106

1✔
107
        r, err := opts.store.CreateDatabaseUser(u)
1✔
108
        if err != nil {
1✔
109
                return err
×
110
        }
×
111

112
        return opts.Print(r)
1✔
113
}
114

115
func (opts *CreateOpts) newDatabaseUser() *atlasv2.CloudDatabaseUser {
1✔
116
        authDB := convert.AdminDB
1✔
117

1✔
118
        if opts.isExternal() && opts.ldapType != group {
2✔
119
                authDB = convert.ExternalAuthDB
1✔
120
        }
1✔
121

122
        roles := convert.BuildAtlasRoles(opts.roles)
1✔
123
        scopes := convert.BuildAtlasScopes(opts.scopes)
1✔
124
        u := &atlasv2.CloudDatabaseUser{
1✔
125
                Roles:           &roles,
1✔
126
                Scopes:          &scopes,
1✔
127
                GroupId:         opts.ConfigProjectID(),
1✔
128
                Username:        opts.username,
1✔
129
                DeleteAfterDate: convert.ParseDeleteAfter(opts.deleteAfter),
1✔
130
                DatabaseName:    authDB,
1✔
131
        }
1✔
132

1✔
133
        if opts.password != "" {
2✔
134
                u.Password = &opts.password
1✔
135
        }
1✔
136
        if opts.x509Type != "" {
2✔
137
                u.X509Type = &opts.x509Type
1✔
138
        }
1✔
139
        if opts.awsIamType != "" {
2✔
140
                u.AwsIAMType = &opts.awsIamType
1✔
141
        }
1✔
142
        if opts.ldapType != "" {
2✔
143
                u.LdapAuthType = &opts.ldapType
1✔
144
        }
1✔
145

146
        if opts.oidcType != "" {
2✔
147
                u.OidcAuthType = &opts.oidcType
1✔
148
        }
1✔
149

150
        if opts.description != "" {
1✔
151
                u.Description = &opts.description
×
152
        }
×
153

154
        return u
1✔
155
}
156

157
func (opts *CreateOpts) Prompt() error {
1✔
158
        if opts.isExternal() || opts.isOIDCSet() || opts.password != "" {
2✔
159
                return nil
1✔
160
        }
1✔
161

162
        if !opts.IsTerminalInput() {
2✔
163
                _, err := fmt.Fscanln(opts.InReader, &opts.password)
1✔
164
                return err
1✔
165
        }
1✔
166

167
        prompt := &survey.Password{
×
168
                Message: "Password:",
×
169
        }
×
170
        return telemetry.TrackAskOne(prompt, &opts.password)
×
171
}
172

173
func (opts *CreateOpts) validate() error {
1✔
174
        if len(opts.roles) == 0 {
1✔
175
                return errors.New("missing role for the user")
×
176
        }
×
177

178
        if opts.isExternal() && opts.password != "" {
1✔
179
                return errors.New("can't supply both $external authentication and password")
×
180
        }
×
181

182
        if err := validate.FlagInSlice(opts.x509Type, flag.X509Type, validX509Flags); err != nil {
1✔
183
                return err
×
184
        }
×
185
        if err := validate.FlagInSlice(opts.awsIamType, flag.AWSIAMType, validAWSIAMFlags); err != nil {
1✔
186
                return err
×
187
        }
×
188

189
        if err := validate.FlagInSlice(opts.oidcType, flag.OIDCType, validOIDCFlags); err != nil {
1✔
190
                return err
×
191
        }
×
192

193
        return validate.FlagInSlice(opts.ldapType, flag.LDAPType, validLDAPFlags)
1✔
194
}
195

196
// CreateBuilder
197
// atlas dbuser(s) create
198
//
199
//        --username username --password password
200
//        --role roleName@dbName
201
//        --scope resourceName@resourceType
202
//        [--projectId projectId]
203
//        [--x509Type NONE|MANAGED|CUSTOMER]
204
//        [--awsIAMType NONE|ROLE|USER]
205
//        [--ldapType NONE|USER|GROUP]
206
func CreateBuilder() *cobra.Command {
1✔
207
        opts := &CreateOpts{}
1✔
208
        cmd := &cobra.Command{
1✔
209
                Use:   "create [builtInRole]...",
1✔
210
                Short: "Create a database user for your project.",
1✔
211
                Long: `If you set --ldapType, --x509Type, --oidcType and --awsIAMType to NONE, Atlas authenticates this user through SCRAM-SHA. To learn more, see https://www.mongodb.com/docs/manual/core/security-scram/.
1✔
212

1✔
213
` + fmt.Sprintf(usage.RequiredRole, "Project Owner"),
1✔
214
                Example: `  # Create an Atlas database admin user named myAdmin for the project with ID 5e2211c17a3e5a48f5497de3:
1✔
215
  atlas dbusers create atlasAdmin --username myAdmin  --projectId 5e2211c17a3e5a48f5497de3
1✔
216

1✔
217
  # Create a database user named myUser with read/write access to any database for the project with ID 5e2211c17a3e5a48f5497de3:
1✔
218
  atlas dbusers create readWriteAnyDatabase --username myUser --projectId 5e2211c17a3e5a48f5497de3
1✔
219

1✔
220
  # Create a database user named myUser with multiple roles for the project with ID 5e2211c17a3e5a48f5497de3:
1✔
221
  atlas dbusers create --username myUser --role clusterMonitor,backup --projectId 5e2211c17a3e5a48f5497de3
1✔
222

1✔
223
  # Create a database user named myUser with multiple scopes for the project with ID 5e2211c17a3e5a48f5497de3:
1✔
224
  atlas dbusers create --username myUser --role clusterMonitor --scope <REPLICA-SET ID>,<storeName> --projectId 5e2211c17a3e5a48f5497de3`,
1✔
225
                Args: cobra.OnlyValidArgs,
1✔
226
                Annotations: map[string]string{
1✔
227
                        "builtInRoleDesc": "Atlas built-in role that you want to assign to the user.",
1✔
228
                        "output":          createTemplate,
1✔
229
                },
1✔
230
                ValidArgs: []string{"atlasAdmin", "readWriteAnyDatabase", "readAnyDatabase", "clusterMonitor", "backup", "dbAdminAnyDatabase", "enableSharding"},
1✔
231
                PreRunE: func(cmd *cobra.Command, args []string) error {
2✔
232
                        opts.roles = append(opts.roles, args...)
1✔
233

1✔
234
                        return opts.PreRunE(
1✔
235
                                opts.ValidateProjectID,
1✔
236
                                opts.initStore(cmd.Context()),
1✔
237
                                opts.InitOutput(cmd.OutOrStdout(), createTemplate),
1✔
238
                                opts.InitInput(cmd.InOrStdin()),
1✔
239
                                opts.validate,
1✔
240
                        )
1✔
241
                },
1✔
242
                RunE: func(_ *cobra.Command, _ []string) error {
1✔
243
                        if err := opts.Prompt(); err != nil {
1✔
244
                                return err
×
245
                        }
×
246
                        return opts.Run()
1✔
247
                },
248
        }
249

250
        cmd.Flags().StringVarP(&opts.username, flag.Username, flag.UsernameShort, "", usage.DBUsername)
1✔
251
        cmd.Flags().StringVarP(&opts.password, flag.Password, flag.PasswordShort, "", usage.DBUserPassword)
1✔
252
        cmd.Flags().StringVar(&opts.deleteAfter, flag.DeleteAfter, "", usage.BDUsersDeleteAfter)
1✔
253
        cmd.Flags().StringVar(&opts.description, flag.Description, "", usage.DBUserDescription)
1✔
254
        cmd.Flags().StringSliceVar(&opts.roles, flag.Role, []string{}, usage.RolesExtended)
1✔
255
        cmd.Flags().StringSliceVar(&opts.scopes, flag.Scope, []string{}, usage.Scopes)
1✔
256
        cmd.Flags().StringVar(&opts.x509Type, flag.X509Type, none, usage.X509Type)
1✔
257
        cmd.Flags().StringVar(&opts.awsIamType, flag.AWSIAMType, none, usage.AWSIAMType)
1✔
258
        cmd.Flags().StringVar(&opts.ldapType, flag.LDAPType, none, usage.LDAPType)
1✔
259
        cmd.Flags().StringVar(&opts.oidcType, flag.OIDCType, none, usage.OIDCType)
1✔
260

1✔
261
        cmd.MarkFlagsMutuallyExclusive(flag.AWSIAMType, flag.LDAPType, flag.X509Type, flag.OIDCType)
1✔
262
        cmd.MarkFlagsMutuallyExclusive(flag.Password, flag.OIDCType)
1✔
263

1✔
264
        opts.AddProjectOptsFlags(cmd)
1✔
265
        opts.AddOutputOptFlags(cmd)
1✔
266

1✔
267
        _ = cmd.MarkFlagRequired(flag.Username)
1✔
268

1✔
269
        return cmd
1✔
270
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc