Skip to content

Commit

Permalink
service-token add-access - Support orgs
Browse files Browse the repository at this point in the history
This adds support for adding org level access via the CLI. Previously, it only worked at DB level.

Also, fixed the formatting.

**Before:**
```
DATABASE     ACCESSES
------------ ------------------------------------------------
tweeter      delete_branch, delete_database, read_database,
             write_database
rsix-other   create_branch
mike         create_databases, delete_databases
```

**After:**
(Notice the headings now make sense)
```
RESOURCE NAME   RESOURCE TYPE   ACCESSES
--------------- --------------- ------------------------------------------------
tweeter         Database        delete_branch, delete_database, read_database,
                                write_database
rsix-other      Database        create_branch
mike            Organization    create_databases, delete_databases
```
  • Loading branch information
mscoutermarsh committed Dec 8, 2023
1 parent ec6e3bc commit d139af5
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 23 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ require (
github.com/mitchellh/go-homedir v1.1.0
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
github.com/pkg/errors v0.9.1
github.com/planetscale/planetscale-go v0.93.1-0.20231128084905-be5d5eb26e2f
github.com/planetscale/planetscale-go v0.94.0
github.com/planetscale/sql-proxy v0.13.0
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/planetscale/planetscale-go v0.51.0/go.mod h1:+rGpW2u7iQZZx4O/nFj4MZe4xIS22CVegEgl1IkTExQ=
github.com/planetscale/planetscale-go v0.93.1-0.20231128084905-be5d5eb26e2f h1:BrNKNknUpfXYzb7syB99WGiVwN0yOFTq8c/3pFjxX1Q=
github.com/planetscale/planetscale-go v0.93.1-0.20231128084905-be5d5eb26e2f/go.mod h1:hDSA/dClhuKuW8dNhKN9vQW8E5fo034Rb6qGTf86/yI=
github.com/planetscale/planetscale-go v0.94.0 h1:/G9161noNN7/LSpBnhiULez+RQEQSs2mTVUadfABV6s=
github.com/planetscale/planetscale-go v0.94.0/go.mod h1:hDSA/dClhuKuW8dNhKN9vQW8E5fo034Rb6qGTf86/yI=
github.com/planetscale/sql-proxy v0.13.0 h1:NDjcdqgoNzwbZQTyoIDEoI+K7keC5RRKvdML2roAMn4=
github.com/planetscale/sql-proxy v0.13.0/go.mod h1:4Sk6JdoBqQhHv9V4FCOC27YIM3EjU8cLIsw5HqxN8x4=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand Down
22 changes: 14 additions & 8 deletions internal/cmd/token/addaccess.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@ func AddAccessCmd(ch *cmdutil.Helper) *cobra.Command {
cmd := &cobra.Command{
Use: "add-access <token> <access> <access> ...",
Short: "add access to a service token in the organization",
Example: `The add-access command grants a service token specific access on a specific database.
Example: `The add-access command grants a service token access on a database or organization.
For example, to give a service token the ability to create, read and delete branches on a specific database:
pscale service-token add-access <token id> read_branch delete_branch create_branch --database <database name>
To give a service token the ability to create and delete databases within the current organization:
pscale service-token add-access <token id> delete_databases create_databases
For a complete list of the access permissions that can be granted to a token, see: https://api-docs.planetscale.com/reference/service-tokens#access-permissions.`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
Expand All @@ -37,21 +41,24 @@ For a complete list of the access permissions that can be granted to a token, se

req := &planetscale.AddServiceTokenAccessRequest{
ID: token,
Database: ch.Config.Database,
Organization: ch.Config.Organization,
Accesses: perms,
}

end := ch.Printer.PrintProgress(fmt.Sprintf("Adding access %s to database %s",
printer.BoldBlue(strings.Join(perms, ", ")), printer.BoldBlue(ch.Config.Database)))
if ch.Config.Database != "" {
req.Database = ch.Config.Database
}

end := ch.Printer.PrintProgress(fmt.Sprintf("Adding access %s to token %s",
printer.BoldBlue(strings.Join(perms, ", ")), printer.BoldBlue(token)))
defer end()

access, err := client.ServiceTokens.AddAccess(ctx, req)
if err != nil {
switch cmdutil.ErrCode(err) {
case planetscale.ErrNotFound:
return fmt.Errorf("token %s does not exist in database %s and organization %s.\nPlease run 'pscale service-token list' to see a list of tokens",
printer.BoldBlue(token), printer.BoldBlue(ch.Config.Database), printer.BoldBlue(ch.Config.Organization))
return fmt.Errorf("token %s does not exist in organization %s.\nPlease run 'pscale service-token list' to see a list of tokens",
printer.BoldBlue(token), printer.BoldBlue(ch.Config.Organization))
default:
return cmdutil.HandleError(err)
}
Expand All @@ -63,8 +70,7 @@ For a complete list of the access permissions that can be granted to a token, se
},
}

cmd.PersistentFlags().StringVar(&ch.Config.Database, "database", ch.Config.Database, "The database this project is using")
cmd.MarkPersistentFlagRequired("database") // nolint:errcheck
cmd.PersistentFlags().StringVar(&ch.Config.Database, "database", ch.Config.Database, "The database to add access to")

return cmd
}
76 changes: 72 additions & 4 deletions internal/cmd/token/addaccess_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ func TestServiceToken_AddAccessCmd(t *testing.T) {
{
ID: "id-1",
Access: "read_branch",
Resource: ps.Database{Name: db},
Resource: ps.ServiceTokenResource{Name: db, Type: "Database"},
},
{
ID: "id-2",
Access: "delete_branch",
Resource: ps.Database{Name: db},
Resource: ps.ServiceTokenResource{Name: db, Type: "Database"},
},
}

Expand Down Expand Up @@ -76,8 +76,76 @@ func TestServiceToken_AddAccessCmd(t *testing.T) {

res := []*ServiceTokenAccess{
{
Database: db,
Accesses: accesses,
ResourceName: db,
ResourceType: "Database",
Accesses: accesses,
},
}
c.Assert(buf.String(), qt.JSONEquals, res)
}

func TestServiceToken_AddAccess_Organization(t *testing.T) {
c := qt.New(t)

var buf bytes.Buffer
format := printer.JSON
p := printer.NewPrinter(&format)
p.SetResourceOutput(&buf)

org := "planetscale"
token := "123456"
accesses := []string{"create_databases", "delete_databases"}

orig := []*ps.ServiceTokenAccess{
{
ID: "id-1",
Access: "create_databases",
Resource: ps.ServiceTokenResource{Name: org, Type: "Organization"},
},
{
ID: "id-2",
Access: "delete_databases",
Resource: ps.ServiceTokenResource{Name: org, Type: "Organization"},
},
}

svc := &mock.ServiceTokenService{
AddAccessFn: func(ctx context.Context, req *ps.AddServiceTokenAccessRequest) ([]*ps.ServiceTokenAccess, error) {
c.Assert(req.Organization, qt.Equals, org)
c.Assert(req.ID, qt.Equals, token)
c.Assert(req.Accesses, qt.DeepEquals, accesses)

return orig, nil
},
}

ch := &cmdutil.Helper{
Printer: p,
Config: &config.Config{
Organization: org,
},
Client: func() (*ps.Client, error) {
return &ps.Client{
ServiceTokens: svc,
}, nil
},
}

args := []string{token}
args = append(args, accesses...)

cmd := AddAccessCmd(ch)
cmd.SetArgs(args)
err := cmd.Execute()

c.Assert(err, qt.IsNil)
c.Assert(svc.AddAccessFnInvoked, qt.IsTrue)

res := []*ServiceTokenAccess{
{
ResourceName: org,
ResourceType: "Organization",
Accesses: accesses,
},
}
c.Assert(buf.String(), qt.JSONEquals, res)
Expand Down
19 changes: 11 additions & 8 deletions internal/cmd/token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,21 +77,24 @@ func toServiceTokens(serviceTokens []*ps.ServiceToken) []*ServiceToken {
return snapshots
}

// ServiceTokenAccess returns a table and json serializiable service token
// ServiceTokenAccess returns a table and json serializable service token
type ServiceTokenAccess struct {
Database string `header:"database" json:"database"`
Accesses []string `header:"accesses" json:"accesses"`
ResourceName string `header:"resource_name" json:"resource_name"`
ResourceType string `header:"resource_type" json:"resource_type"`
Accesses []string `header:"accesses" json:"accesses"`
}

func toServiceTokenAccesses(st []*ps.ServiceTokenAccess) []*ServiceTokenAccess {
data := map[string]*ServiceTokenAccess{}
for _, v := range st {
if db, ok := data[v.Resource.Name]; ok {
resourceId := v.Resource.Name + "/" + v.Resource.Type
if db, ok := data[resourceId]; ok {
db.Accesses = append(db.Accesses, v.Access)
} else {
data[v.Resource.Name] = &ServiceTokenAccess{
Database: v.Resource.Name,
Accesses: []string{v.Access},
data[resourceId] = &ServiceTokenAccess{
ResourceName: v.Resource.Name,
ResourceType: v.Resource.Type,
Accesses: []string{v.Access},
}
}
}
Expand All @@ -103,7 +106,7 @@ func toServiceTokenAccesses(st []*ps.ServiceTokenAccess) []*ServiceTokenAccess {
return out
}

// ServiceTokenGrant erturns a table and json serializable service token grant
// ServiceTokenGrant returns a table and json serializable service token grant
type ServiceTokenGrant struct {
ResourceName string `header:"resource_name" json:"resource_name"`
ResourceType string `header:"resource_type" json:"resource_type"`
Expand Down

0 comments on commit d139af5

Please sign in to comment.