Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Aug 30, 2024. It is now read-only.
/coder-v1-cliPublic archive

Commitb5487cb

Browse files
committed
Add more secret creation input paths
* --from-literal* --from-file* fallback to stdin prompt
1 parent3d90829 commitb5487cb

File tree

7 files changed

+180
-87
lines changed

7 files changed

+180
-87
lines changed

‎ci/integration/integration_test.go

Lines changed: 1 addition & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ package integration
33
import (
44
"context"
55
"encoding/json"
6-
"fmt"
76
"math/rand"
8-
"regexp"
97
"testing"
108
"time"
119

@@ -89,65 +87,6 @@ func TestCoderCLI(t *testing.T) {
8987
)
9088
}
9189

92-
funcTestSecrets(t*testing.T) {
93-
t.Parallel()
94-
ctx,cancel:=context.WithTimeout(context.Background(),time.Minute*5)
95-
defercancel()
96-
97-
c,err:=tcli.NewContainerRunner(ctx,&tcli.ContainerConfig{
98-
Image:"codercom/enterprise-dev",
99-
Name:"secrets-cli-tests",
100-
BindMounts:map[string]string{
101-
binpath:"/bin/coder",
102-
},
103-
})
104-
assert.Success(t,"new run container",err)
105-
deferc.Close()
106-
107-
headlessLogin(ctx,t,c)
108-
109-
c.Run(ctx,"coder secrets ls").Assert(t,
110-
tcli.Success(),
111-
)
112-
113-
name,value:=randString(8),randString(8)
114-
115-
c.Run(ctx,"coder secrets create").Assert(t,
116-
tcli.Error(),
117-
tcli.StdoutEmpty(),
118-
tcli.StderrMatches("required flag"),
119-
)
120-
121-
c.Run(ctx,fmt.Sprintf("coder secrets create --name %s --value %s",name,value)).Assert(t,
122-
tcli.Success(),
123-
tcli.StderrEmpty(),
124-
)
125-
126-
c.Run(ctx,"coder secrets ls").Assert(t,
127-
tcli.Success(),
128-
tcli.StderrEmpty(),
129-
tcli.StdoutMatches("Value"),
130-
tcli.StdoutMatches(regexp.QuoteMeta(name)),
131-
)
132-
133-
c.Run(ctx,"coder secrets view "+name).Assert(t,
134-
tcli.Success(),
135-
tcli.StderrEmpty(),
136-
tcli.StdoutMatches(regexp.QuoteMeta(value)),
137-
)
138-
139-
c.Run(ctx,"coder secrets rm").Assert(t,
140-
tcli.Error(),
141-
)
142-
c.Run(ctx,"coder secrets rm "+name).Assert(t,
143-
tcli.Success(),
144-
)
145-
c.Run(ctx,"coder secrets view "+name).Assert(t,
146-
tcli.Error(),
147-
tcli.StdoutEmpty(),
148-
)
149-
}
150-
15190
funcstdoutUnmarshalsJSON(targetinterface{}) tcli.Assertion {
15291
returnfunc(t*testing.T,r*tcli.CommandResult) {
15392
slog.Helper()
@@ -159,7 +98,7 @@ func stdoutUnmarshalsJSON(target interface{}) tcli.Assertion {
15998
varseededRand=rand.New(rand.NewSource(time.Now().UnixNano()))
16099

161100
funcrandString(lengthint)string {
162-
constcharset="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
101+
constcharset="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
163102
b:=make([]byte,length)
164103
fori:=rangeb {
165104
b[i]=charset[seededRand.Intn(len(charset))]

‎ci/integration/secrets_test.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package integration
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"regexp"
7+
"testing"
8+
"time"
9+
10+
"cdr.dev/coder-cli/ci/tcli"
11+
"cdr.dev/slog/sloggers/slogtest/assert"
12+
)
13+
14+
funcTestSecrets(t*testing.T) {
15+
t.Parallel()
16+
ctx,cancel:=context.WithTimeout(context.Background(),time.Minute*5)
17+
defercancel()
18+
19+
c,err:=tcli.NewContainerRunner(ctx,&tcli.ContainerConfig{
20+
Image:"codercom/enterprise-dev",
21+
Name:"secrets-cli-tests",
22+
BindMounts:map[string]string{
23+
binpath:"/bin/coder",
24+
},
25+
})
26+
assert.Success(t,"new run container",err)
27+
deferc.Close()
28+
29+
headlessLogin(ctx,t,c)
30+
31+
c.Run(ctx,"coder secrets ls").Assert(t,
32+
tcli.Success(),
33+
)
34+
35+
name,value:=randString(8),randString(8)
36+
37+
c.Run(ctx,"coder secrets create").Assert(t,
38+
tcli.Error(),
39+
tcli.StdoutEmpty(),
40+
)
41+
42+
// this tests the "Value:" prompt fallback
43+
c.Run(ctx,fmt.Sprintf("echo %s | coder secrets create %s --from-prompt",value,name)).Assert(t,
44+
tcli.Success(),
45+
tcli.StderrEmpty(),
46+
)
47+
48+
c.Run(ctx,"coder secrets ls").Assert(t,
49+
tcli.Success(),
50+
tcli.StderrEmpty(),
51+
tcli.StdoutMatches("Value"),
52+
tcli.StdoutMatches(regexp.QuoteMeta(name)),
53+
)
54+
55+
c.Run(ctx,"coder secrets view "+name).Assert(t,
56+
tcli.Success(),
57+
tcli.StderrEmpty(),
58+
tcli.StdoutMatches(regexp.QuoteMeta(value)),
59+
)
60+
61+
c.Run(ctx,"coder secrets rm").Assert(t,
62+
tcli.Error(),
63+
)
64+
c.Run(ctx,"coder secrets rm "+name).Assert(t,
65+
tcli.Success(),
66+
)
67+
c.Run(ctx,"coder secrets view "+name).Assert(t,
68+
tcli.Error(),
69+
tcli.StdoutEmpty(),
70+
)
71+
72+
name,value=randString(8),randString(8)
73+
74+
c.Run(ctx,fmt.Sprintf("coder secrets create %s --from-literal %s",name,value)).Assert(t,
75+
tcli.Success(),
76+
tcli.StderrEmpty(),
77+
)
78+
79+
c.Run(ctx,"coder secrets view "+name).Assert(t,
80+
tcli.Success(),
81+
tcli.StdoutMatches(regexp.QuoteMeta(value)),
82+
)
83+
84+
name,value=randString(8),randString(8)
85+
c.Run(ctx,fmt.Sprintf("echo %s > ~/secret.json",value)).Assert(t,
86+
tcli.Success(),
87+
)
88+
c.Run(ctx,fmt.Sprintf("coder secrets create %s --from-literal %s --from-file ~/secret.json",name,value)).Assert(t,
89+
tcli.Error(),
90+
)
91+
c.Run(ctx,fmt.Sprintf("coder secrets create %s --from-file ~/secret.json",name)).Assert(t,
92+
tcli.Success(),
93+
)
94+
//
95+
c.Run(ctx,"coder secrets view "+name).Assert(t,
96+
tcli.Success(),
97+
tcli.StdoutMatches(regexp.QuoteMeta(value)),
98+
)
99+
}

‎cmd/coder/secrets.go

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ package main
22

33
import (
44
"fmt"
5+
"io/ioutil"
56
"os"
67

78
"cdr.dev/coder-cli/internal/entclient"
89
"cdr.dev/coder-cli/internal/x/xtabwriter"
910
"cdr.dev/coder-cli/internal/x/xvalidate"
11+
"github.com/manifoldco/promptui"
1012
"github.com/spf13/pflag"
1113
"golang.org/x/xerrors"
1214

@@ -111,45 +113,79 @@ func (cmd viewSecretsCmd) Run(fl *pflag.FlagSet) {
111113
}
112114

113115
typecreateSecretCmdstruct {
114-
name,value,descriptionstring
115-
}
116-
117-
func (cmd*createSecretCmd)Validate() (e []error) {
118-
ifcmd.name=="" {
119-
e=append(e,xerrors.New("--name is a required flag"))
120-
}
121-
ifcmd.value=="" {
122-
e=append(e,xerrors.New("--value is a required flag"))
123-
}
124-
returne
116+
descriptionstring
117+
fromFilestring
118+
fromLiteralstring
119+
fromPromptbool
125120
}
126121

127122
func (cmd*createSecretCmd)Spec() cli.CommandSpec {
128123
return cli.CommandSpec{
129124
Name:"create",
130-
Usage:`--name MYSQL_KEY --value 123456 --description "MySQL credential for database access"`,
131-
Desc:"insert a new secret",
125+
Usage:`[secret_name] [...flags]`,
126+
Desc:"create a new secret",
127+
}
128+
}
129+
130+
func (cmd*createSecretCmd)Validate(fl*pflag.FlagSet) (e []error) {
131+
ifcmd.fromPrompt&& (cmd.fromLiteral!=""||cmd.fromFile!="") {
132+
e=append(e,xerrors.Errorf("--from-prompt cannot be set along with --from-file or --from-literal"))
132133
}
134+
ifcmd.fromLiteral!=""&&cmd.fromFile!="" {
135+
e=append(e,xerrors.Errorf("--from-literal and --from-file cannot both be set"))
136+
}
137+
if!cmd.fromPrompt&&cmd.fromFile==""&&cmd.fromLiteral=="" {
138+
e=append(e,xerrors.Errorf("one of [--from-literal, --from-file, --from-prompt] is required"))
139+
}
140+
returne
133141
}
134142

135143
func (cmd*createSecretCmd)Run(fl*pflag.FlagSet) {
136144
var (
137145
client=requireAuth()
146+
name=fl.Arg(0)
147+
valuestring
148+
errerror
138149
)
139-
xvalidate.Validate(cmd)
150+
ifname=="" {
151+
exitUsage(fl)
152+
}
153+
xvalidate.Validate(fl,cmd)
154+
155+
ifcmd.fromLiteral!="" {
156+
value=cmd.fromLiteral
157+
}elseifcmd.fromFile!="" {
158+
contents,err:=ioutil.ReadFile(cmd.fromFile)
159+
requireSuccess(err,"failed to read file: %v",err)
160+
value=string(contents)
161+
}else {
162+
prompt:= promptui.Prompt{
163+
Label:"value",
164+
Mask:'*',
165+
Validate:func(sstring)error {
166+
iflen(s)<1 {
167+
returnxerrors.Errorf("a length > 0 is required")
168+
}
169+
returnnil
170+
},
171+
}
172+
value,err=prompt.Run()
173+
requireSuccess(err,"failed to prompt for value: %v",err)
174+
}
140175

141-
err:=client.InsertSecret(entclient.InsertSecretReq{
142-
Name:cmd.name,
143-
Value:cmd.value,
176+
err=client.InsertSecret(entclient.InsertSecretReq{
177+
Name:name,
178+
Value:value,
144179
Description:cmd.description,
145180
})
146181
requireSuccess(err,"failed to insert secret: %v",err)
147182
}
148183

149184
func (cmd*createSecretCmd)RegisterFlags(fl*pflag.FlagSet) {
150-
fl.StringVar(&cmd.name,"name","","the name of the secret")
151-
fl.StringVar(&cmd.value,"value","","the value of the secret")
152-
fl.StringVar(&cmd.description,"description","","a description of the secret")
185+
fl.StringVar(&cmd.fromFile,"from-file","","specify a file from which to read the value of the secret")
186+
fl.StringVar(&cmd.fromLiteral,"from-literal","","specify the value of the secret")
187+
fl.BoolVar(&cmd.fromPrompt,"from-prompt",false,"specify the value of the secret through a prompt")
188+
fl.StringVar(&cmd.description,"description","","specify a description of the secret")
153189
}
154190

155191
typedeleteSecretsCmdstruct{}

‎cmd/coder/users.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ type listCmd struct {
3838
}
3939

4040
func (cmd*listCmd)Run(fl*pflag.FlagSet) {
41-
xvalidate.Validate(cmd)
41+
xvalidate.Validate(fl,cmd)
4242
entClient:=requireAuth()
4343

4444
users,err:=entClient.Users()
@@ -77,7 +77,7 @@ func (cmd *listCmd) Spec() cli.CommandSpec {
7777
}
7878
}
7979

80-
func (cmd*listCmd)Validate() (e []error) {
80+
func (cmd*listCmd)Validate(fl*pflag.FlagSet) (e []error) {
8181
if!(cmd.outputFmt=="json"||cmd.outputFmt=="human") {
8282
e=append(e,fmt.Errorf(`--output must be "json" or "human"`))
8383
}

‎go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ require (
99
github.com/gorilla/websocketv1.4.1
1010
github.com/kirsle/configdirv0.0.0-20170128060238-e45d2f54772f
1111
github.com/klauspost/compressv1.10.8// indirect
12+
github.com/manifoldco/promptuiv0.7.0
1213
github.com/mattn/go-colorablev0.1.6// indirect
1314
github.com/pkg/browserv0.0.0-20180916011732-0a3d74bf9ce4
1415
github.com/rjeczalik/notifyv0.9.2

‎go.sum

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ github.com/alecthomas/kong-hcl v0.1.8-0.20190615233001-b21fea9723c8/go.mod h1:MR
3333
github.com/alecthomas/reprv0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
3434
github.com/alecthomas/reprv0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
3535
github.com/census-instrumentation/opencensus-protov0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
36+
github.com/chzyer/logexv1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
37+
github.com/chzyer/logexv1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
38+
github.com/chzyer/readlinev0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
39+
github.com/chzyer/readlinev0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
40+
github.com/chzyer/testv0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
41+
github.com/chzyer/testv0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
3642
github.com/client9/misspellv0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
3743
github.com/creack/ptyv1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
3844
github.com/creack/ptyv1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@@ -111,6 +117,8 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS
111117
github.com/json-iterator/gov1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
112118
github.com/json-iterator/gov1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
113119
github.com/jstemmer/go-junit-reportv0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
120+
github.com/juju/ansitermv0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=
121+
github.com/juju/ansitermv0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
114122
github.com/kirsle/configdirv0.0.0-20170128060238-e45d2f54772f h1:dKccXx7xA56UNqOcFIbuqFjAWPVtP688j5QMgmo6OHU=
115123
github.com/kirsle/configdirv0.0.0-20170128060238-e45d2f54772f/go.mod h1:4rEELDSfUAlBSyUjPG0JnaNGjf13JySHFeRdD/3dLP0=
116124
github.com/kisielk/gotoolv1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -125,6 +133,10 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
125133
github.com/kr/textv0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
126134
github.com/leodido/go-urnv1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
127135
github.com/leodido/go-urnv1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
136+
github.com/lunixbochs/vtcleanv0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw=
137+
github.com/lunixbochs/vtcleanv0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
138+
github.com/manifoldco/promptuiv0.7.0 h1:3l11YT8tm9MnwGFQ4kETwkzpAwY2Jt9lCrumCUW4+z4=
139+
github.com/manifoldco/promptuiv0.7.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ=
128140
github.com/mattn/go-colorablev0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
129141
github.com/mattn/go-colorablev0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
130142
github.com/mattn/go-colorablev0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
@@ -225,6 +237,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03i
225237
golang.org/x/syncv0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
226238
golang.org/x/sysv0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
227239
golang.org/x/sysv0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
240+
golang.org/x/sysv0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
228241
golang.org/x/sysv0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
229242
golang.org/x/sysv0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
230243
golang.org/x/sysv0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

‎internal/x/xvalidate/errors.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ package xvalidate
22

33
import (
44
"bytes"
5+
"fmt"
6+
7+
"github.com/spf13/pflag"
58

69
"go.coder.com/flog"
710
)
@@ -81,16 +84,18 @@ func combineErrors(errs ...error) error {
8184

8285
// Validator is a command capable of validating its flags
8386
typeValidatorinterface {
84-
Validate() []error
87+
Validate(fl*pflag.FlagSet) []error
8588
}
8689

8790
// Validate performs validation and exits with a nonzero status code if validation fails.
8891
// The proper errors are printed to stderr.
89-
funcValidate(vValidator) {
90-
errs:=v.Validate()
92+
funcValidate(fl*pflag.FlagSet,vValidator) {
93+
errs:=v.Validate(fl)
9194

9295
err:=combineErrors(errs...)
9396
iferr!=nil {
97+
fl.Usage()
98+
fmt.Println("")
9499
flog.Fatal("failed to validate this command\n%v",err)
95100
}
96101
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp