mirror of
https://github.com/coder/coder.git
synced 2026-09-21 20:51:01 +08:00
feat: implement feature to create a token on behalf of another user in the cli (#14813)
This PR addresses https://github.com/coder/coder/issues/13160
This commit is contained in:
@@ -12,5 +12,9 @@ OPTIONS:
|
||||
-n, --name string, $CODER_TOKEN_NAME
|
||||
Specify a human-readable name.
|
||||
|
||||
-u, --user string, $CODER_TOKEN_USER
|
||||
Specify the user to create the token for (Only works if logged in user
|
||||
is admin).
|
||||
|
||||
———
|
||||
Run `coder --help` for a list of global options.
|
||||
|
||||
+13
-1
@@ -48,6 +48,7 @@ func (r *RootCmd) createToken() *serpent.Command {
|
||||
var (
|
||||
tokenLifetime time.Duration
|
||||
name string
|
||||
user string
|
||||
)
|
||||
client := new(codersdk.Client)
|
||||
cmd := &serpent.Command{
|
||||
@@ -58,7 +59,11 @@ func (r *RootCmd) createToken() *serpent.Command {
|
||||
r.InitClient(client),
|
||||
),
|
||||
Handler: func(inv *serpent.Invocation) error {
|
||||
res, err := client.CreateToken(inv.Context(), codersdk.Me, codersdk.CreateTokenRequest{
|
||||
userID := codersdk.Me
|
||||
if user != "" {
|
||||
userID = user
|
||||
}
|
||||
res, err := client.CreateToken(inv.Context(), userID, codersdk.CreateTokenRequest{
|
||||
Lifetime: tokenLifetime,
|
||||
TokenName: name,
|
||||
})
|
||||
@@ -87,6 +92,13 @@ func (r *RootCmd) createToken() *serpent.Command {
|
||||
Description: "Specify a human-readable name.",
|
||||
Value: serpent.StringOf(&name),
|
||||
},
|
||||
{
|
||||
Flag: "user",
|
||||
FlagShorthand: "u",
|
||||
Env: "CODER_TOKEN_USER",
|
||||
Description: "Specify the user to create the token for (Only works if logged in user is admin).",
|
||||
Value: serpent.StringOf(&user),
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
|
||||
+47
-2
@@ -17,13 +17,17 @@ import (
|
||||
func TestTokens(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
adminUser := coderdtest.CreateFirstUser(t, client)
|
||||
|
||||
secondUserClient, secondUser := coderdtest.CreateAnotherUser(t, client, adminUser.OrganizationID)
|
||||
_, thirdUser := coderdtest.CreateAnotherUser(t, client, adminUser.OrganizationID)
|
||||
|
||||
ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancelFunc()
|
||||
|
||||
// helpful empty response
|
||||
inv, root := clitest.New(t, "tokens", "ls")
|
||||
//nolint:gocritic // This should be run as the owner user.
|
||||
clitest.SetupConfig(t, client, root)
|
||||
buf := new(bytes.Buffer)
|
||||
inv.Stdout = buf
|
||||
@@ -42,6 +46,19 @@ func TestTokens(t *testing.T) {
|
||||
require.NotEmpty(t, res)
|
||||
id := res[:10]
|
||||
|
||||
// Test creating a token for second user from first user's (admin) session
|
||||
inv, root = clitest.New(t, "tokens", "create", "--name", "token-two", "--user", secondUser.ID.String())
|
||||
clitest.SetupConfig(t, client, root)
|
||||
buf = new(bytes.Buffer)
|
||||
inv.Stdout = buf
|
||||
err = inv.WithContext(ctx).Run()
|
||||
// Test should succeed in creating token for second user
|
||||
require.NoError(t, err)
|
||||
res = buf.String()
|
||||
require.NotEmpty(t, res)
|
||||
secondTokenID := res[:10]
|
||||
|
||||
// Test listing tokens from the first user's (admin) session
|
||||
inv, root = clitest.New(t, "tokens", "ls")
|
||||
clitest.SetupConfig(t, client, root)
|
||||
buf = new(bytes.Buffer)
|
||||
@@ -50,11 +67,39 @@ func TestTokens(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
res = buf.String()
|
||||
require.NotEmpty(t, res)
|
||||
// Result should only contain the token created for the admin user
|
||||
require.Contains(t, res, "ID")
|
||||
require.Contains(t, res, "EXPIRES AT")
|
||||
require.Contains(t, res, "CREATED AT")
|
||||
require.Contains(t, res, "LAST USED")
|
||||
require.Contains(t, res, id)
|
||||
// Result should not contain the token created for the second user
|
||||
require.NotContains(t, res, secondTokenID)
|
||||
|
||||
// Test listing tokens from the second user's session
|
||||
inv, root = clitest.New(t, "tokens", "ls")
|
||||
clitest.SetupConfig(t, secondUserClient, root)
|
||||
buf = new(bytes.Buffer)
|
||||
inv.Stdout = buf
|
||||
err = inv.WithContext(ctx).Run()
|
||||
require.NoError(t, err)
|
||||
res = buf.String()
|
||||
require.NotEmpty(t, res)
|
||||
require.Contains(t, res, "ID")
|
||||
require.Contains(t, res, "EXPIRES AT")
|
||||
require.Contains(t, res, "CREATED AT")
|
||||
require.Contains(t, res, "LAST USED")
|
||||
require.Contains(t, res, id)
|
||||
// Result should contain the token created for the second user
|
||||
require.Contains(t, res, secondTokenID)
|
||||
|
||||
// Test creating a token for third user from second user's (non-admin) session
|
||||
inv, root = clitest.New(t, "tokens", "create", "--name", "token-two", "--user", thirdUser.ID.String())
|
||||
clitest.SetupConfig(t, secondUserClient, root)
|
||||
buf = new(bytes.Buffer)
|
||||
inv.Stdout = buf
|
||||
err = inv.WithContext(ctx).Run()
|
||||
// User (non-admin) should not be able to create a token for another user
|
||||
require.Error(t, err)
|
||||
|
||||
inv, root = clitest.New(t, "tokens", "ls", "--output=json")
|
||||
clitest.SetupConfig(t, client, root)
|
||||
|
||||
Generated
+9
@@ -30,3 +30,12 @@ Specify a duration for the lifetime of the token.
|
||||
| Environment | <code>$CODER_TOKEN_NAME</code> |
|
||||
|
||||
Specify a human-readable name.
|
||||
|
||||
### -u, --user
|
||||
|
||||
| | |
|
||||
| ----------- | ------------------------------ |
|
||||
| Type | <code>string</code> |
|
||||
| Environment | <code>$CODER_TOKEN_USER</code> |
|
||||
|
||||
Specify the user to create the token for (Only works if logged in user is admin).
|
||||
|
||||
Reference in New Issue
Block a user