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

Commit7a9addf

Browse files
authored
Add new tokens command for managing API tokens (#170)
1 parent9ead247 commit7a9addf

File tree

6 files changed

+246
-8
lines changed

6 files changed

+246
-8
lines changed

‎ci/integration/statictokens_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package integration
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"os/exec"
8+
"strings"
9+
"testing"
10+
11+
"cdr.dev/coder-cli/pkg/tcli"
12+
)
13+
14+
funcTestStaticAuth(t*testing.T) {
15+
t.Parallel()
16+
t.Skip()
17+
run(t,"static-auth-test",func(t*testing.T,ctx context.Context,c*tcli.ContainerRunner) {
18+
headlessLogin(ctx,t,c)
19+
20+
c.Run(ctx,"coder tokens ls").Assert(t,
21+
tcli.Success(),
22+
)
23+
24+
varresult*tcli.CommandResult
25+
tokenName:=randString(5)
26+
c.Run(ctx,"coder tokens create "+tokenName).Assert(t,
27+
tcli.Success(),
28+
tcli.GetResult(&result),
29+
)
30+
31+
// remove loging credentials
32+
c.Run(ctx,"rm -rf ~/.config/coder").Assert(t,
33+
tcli.Success(),
34+
)
35+
36+
// make requests with token environment variable authentication
37+
cmd:=exec.CommandContext(ctx,"sh","-c",
38+
fmt.Sprintf("export CODER_URL=%s && export CODER_TOKEN=$(cat) && coder envs ls",os.Getenv("CODER_URL")),
39+
)
40+
cmd.Stdin=strings.NewReader(string(result.Stdout))
41+
c.RunCmd(cmd).Assert(t,
42+
tcli.Success(),
43+
)
44+
45+
// should error when the environment variabels aren't set
46+
c.Run(ctx,"coder envs ls").Assert(t,
47+
tcli.Error(),
48+
)
49+
})
50+
}

‎coder-sdk/request.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func (c Client) requestBody(ctx context.Context, method, path string, in, out in
5151
// Responses in the 100 are handled by the http lib, in the 200 range, we have a success.
5252
// Consider anything at or above 300 to be an error.
5353
ifresp.StatusCode>299 {
54-
returnfmt.Errorf("unexpected status code: %w",bodyError(resp))
54+
returnfmt.Errorf("unexpected status code %d: %w",resp.StatusCode,bodyError(resp))
5555
}
5656

5757
// If we expect a payload, process it as json.

‎coder-sdk/tokens.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package coder
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"time"
7+
)
8+
9+
typeAPITokenstruct {
10+
IDstring`json:"id"`
11+
Namestring`json:"name"`
12+
Applicationbool`json:"application"`
13+
UserIDstring`json:"user_id"`
14+
LastUsed time.Time`json:"last_used"`
15+
}
16+
17+
typeCreateAPITokenReqstruct {
18+
Namestring`json:"name"`
19+
}
20+
21+
typecreateAPITokenRespstruct {
22+
Keystring`json:"key"`
23+
}
24+
25+
func (cClient)CreateAPIToken(ctx context.Context,userIDstring,reqCreateAPITokenReq) (tokenstring,_error) {
26+
varrespcreateAPITokenResp
27+
err:=c.requestBody(ctx,http.MethodPost,"/api/api-keys/"+userID,req,&resp)
28+
iferr!=nil {
29+
return"",err
30+
}
31+
returnresp.Key,nil
32+
}
33+
34+
func (cClient)APITokens(ctx context.Context,userIDstring) ([]APIToken,error) {
35+
vartokens []APIToken
36+
iferr:=c.requestBody(ctx,http.MethodGet,"/api/api-keys/"+userID,nil,&tokens);err!=nil {
37+
returnnil,err
38+
}
39+
returntokens,nil
40+
}
41+
42+
func (cClient)APITokenByID(ctx context.Context,userID,tokenIDstring) (*APIToken,error) {
43+
vartokenAPIToken
44+
iferr:=c.requestBody(ctx,http.MethodGet,"/api/api-keys/"+userID+"/"+tokenID,nil,&token);err!=nil {
45+
returnnil,err
46+
}
47+
return&token,nil
48+
}
49+
50+
func (cClient)DeleteAPIToken(ctx context.Context,userID,tokenIDstring)error {
51+
returnc.requestBody(ctx,http.MethodDelete,"/api/api-keys/"+userID+"/"+tokenID,nil,nil)
52+
}
53+
54+
func (cClient)RegenerateAPIToken(ctx context.Context,userID,tokenIDstring) (tokenstring,_error) {
55+
varrespcreateAPITokenResp
56+
iferr:=c.requestBody(ctx,http.MethodPost,"/api/api-keys/"+userID+"/"+tokenID+"/regen",nil,&resp);err!=nil {
57+
return"",err
58+
}
59+
returnresp.Key,nil
60+
}

‎internal/cmd/auth.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"net/http"
77
"net/url"
8+
"os"
89

910
"golang.org/x/xerrors"
1011

@@ -19,15 +20,26 @@ var errNeedLogin = clog.Fatal(
1920
clog.Hintf(`did you run "coder login [https://coder.domain.com]"?`),
2021
)
2122

23+
consttokenEnv="CODER_TOKEN"
24+
consturlEnv="CODER_URL"
25+
2226
funcnewClient(ctx context.Context) (*coder.Client,error) {
23-
sessionToken,err:=config.Session.Read()
24-
iferr!=nil {
25-
returnnil,errNeedLogin
26-
}
27+
var (
28+
errerror
29+
sessionToken=os.Getenv(tokenEnv)
30+
rawURL=os.Getenv(urlEnv)
31+
)
2732

28-
rawURL,err:=config.URL.Read()
29-
iferr!=nil {
30-
returnnil,errNeedLogin
33+
ifsessionToken==""||rawURL=="" {
34+
sessionToken,err=config.Session.Read()
35+
iferr!=nil {
36+
returnnil,errNeedLogin
37+
}
38+
39+
rawURL,err=config.URL.Read()
40+
iferr!=nil {
41+
returnnil,errNeedLogin
42+
}
3143
}
3244

3345
u,err:=url.Parse(rawURL)

‎internal/cmd/cmd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func Make() *cobra.Command {
3030
envsCmd(),
3131
syncCmd(),
3232
urlCmd(),
33+
tokensCmd(),
3334
resourceCmd(),
3435
completionCmd(),
3536
genDocsCmd(app),

‎internal/cmd/tokens.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
6+
"cdr.dev/coder-cli/coder-sdk"
7+
"cdr.dev/coder-cli/pkg/tablewriter"
8+
"github.com/spf13/cobra"
9+
)
10+
11+
functokensCmd()*cobra.Command {
12+
cmd:=&cobra.Command{
13+
Use:"tokens",
14+
Short:"manage Coder API tokens for the active user",
15+
Hidden:true,
16+
Long:"Create and manage API Tokens for authenticating the CLI.\n"+
17+
"Statically authenticate using the token value with the "+"`"+"CODER_TOKEN"+"`"+" and "+"`"+"CODER_URL"+"`"+" environment variables.",
18+
}
19+
cmd.AddCommand(
20+
lsTokensCmd(),
21+
createTokensCmd(),
22+
rmTokenCmd(),
23+
regenTokenCmd(),
24+
)
25+
returncmd
26+
}
27+
28+
funclsTokensCmd()*cobra.Command {
29+
return&cobra.Command{
30+
Use:"ls",
31+
Short:"show the user's active API tokens",
32+
RunE:func(cmd*cobra.Command,args []string)error {
33+
ctx:=cmd.Context()
34+
client,err:=newClient(ctx)
35+
iferr!=nil {
36+
returnerr
37+
}
38+
39+
tokens,err:=client.APITokens(ctx,coder.Me)
40+
iferr!=nil {
41+
returnerr
42+
}
43+
44+
err=tablewriter.WriteTable(len(tokens),func(iint)interface{} {returntokens[i] })
45+
iferr!=nil {
46+
returnerr
47+
}
48+
49+
returnnil
50+
},
51+
}
52+
}
53+
54+
funccreateTokensCmd()*cobra.Command {
55+
return&cobra.Command{
56+
Use:"create [token_name]",
57+
Short:"create generates a new API token and prints it to stdout",
58+
Args:cobra.ExactArgs(1),
59+
RunE:func(cmd*cobra.Command,args []string)error {
60+
ctx:=cmd.Context()
61+
client,err:=newClient(ctx)
62+
iferr!=nil {
63+
returnerr
64+
}
65+
token,err:=client.CreateAPIToken(ctx,coder.Me, coder.CreateAPITokenReq{
66+
Name:args[0],
67+
})
68+
iferr!=nil {
69+
returnerr
70+
}
71+
fmt.Println(token)
72+
returnnil
73+
},
74+
}
75+
}
76+
77+
funcrmTokenCmd()*cobra.Command {
78+
return&cobra.Command{
79+
Use:"rm [token_id]",
80+
Short:"remove an API token by its unique ID",
81+
Args:cobra.ExactArgs(1),
82+
RunE:func(cmd*cobra.Command,args []string)error {
83+
ctx:=cmd.Context()
84+
client,err:=newClient(ctx)
85+
iferr!=nil {
86+
returnerr
87+
}
88+
iferr=client.DeleteAPIToken(ctx,coder.Me,args[0]);err!=nil {
89+
returnerr
90+
}
91+
returnnil
92+
},
93+
}
94+
}
95+
96+
funcregenTokenCmd()*cobra.Command {
97+
return&cobra.Command{
98+
Use:"regen [token_id]",
99+
Short:"regenerate an API token by its unique ID and print the new token to stdout",
100+
Args:cobra.ExactArgs(1),
101+
RunE:func(cmd*cobra.Command,args []string)error {
102+
ctx:=cmd.Context()
103+
client,err:=newClient(ctx)
104+
iferr!=nil {
105+
returnerr
106+
}
107+
token,err:=client.RegenerateAPIToken(ctx,coder.Me,args[0])
108+
iferr!=nil {
109+
returnnil
110+
}
111+
fmt.Println(token)
112+
returnnil
113+
},
114+
}
115+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp