feat(authz): autocli query support (backport #16986) (#16988)

Co-authored-by: Julien Robert <julien@rbrt.fr>
This commit is contained in:
mergify[bot]
2023-07-13 15:33:55 +00:00
committed by GitHub
co-authored by Julien Robert
parent 4076c6a918
commit bc7221f5c5
7 changed files with 98 additions and 850 deletions
-195
View File
@@ -1,195 +0,0 @@
package cli
import (
"fmt"
"strings"
"github.com/spf13/cobra"
"cosmossdk.io/core/address"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/authz"
bank "github.com/cosmos/cosmos-sdk/x/bank/types"
)
// GetQueryCmd returns the cli query commands for this module
func GetQueryCmd(ac address.Codec) *cobra.Command {
authorizationQueryCmd := &cobra.Command{
Use: authz.ModuleName,
Short: "Querying commands for the authz module",
Long: "",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
authorizationQueryCmd.AddCommand(
GetCmdQueryGrants(ac),
GetQueryGranterGrants(ac),
GetQueryGranteeGrants(ac),
)
return authorizationQueryCmd
}
// GetCmdQueryGrants implements the query authorization command.
func GetCmdQueryGrants(ac address.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "grants [granter-addr] [grantee-addr] [msg-type-url]?",
Args: cobra.RangeArgs(2, 3),
Short: "query grants for a granter-grantee pair and optionally a msg-type-url",
Long: strings.TrimSpace(
fmt.Sprintf(`Query authorization grants for a granter-grantee pair. If msg-type-url
is set, it will select grants only for that msg type.
Examples:
$ %s query %s grants cosmos1skj.. cosmos1skjwj..
$ %s query %s grants cosmos1skjw.. cosmos1skjwj.. %s
`,
version.AppName, authz.ModuleName,
version.AppName, authz.ModuleName, bank.SendAuthorization{}.MsgTypeURL()),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := authz.NewQueryClient(clientCtx)
_, err = ac.StringToBytes(args[0])
if err != nil {
return err
}
_, err = ac.StringToBytes(args[1])
if err != nil {
return err
}
msgAuthorized := ""
if len(args) == 3 {
msgAuthorized = args[2]
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
res, err := queryClient.Grants(
cmd.Context(),
&authz.QueryGrantsRequest{
Granter: args[0],
Grantee: args[1],
MsgTypeUrl: msgAuthorized,
Pagination: pageReq,
},
)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "grants")
return cmd
}
// GetQueryGranterGrants returns cmd to query for all grants for a granter.
func GetQueryGranterGrants(ac address.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "grants-by-granter [granter-addr]",
Args: cobra.ExactArgs(1),
Short: "query authorization grants granted by granter",
Long: strings.TrimSpace(
fmt.Sprintf(`Query authorization grants granted by granter.
Examples:
$ %s q %s grants-by-granter cosmos1skj..
`,
version.AppName, authz.ModuleName),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
_, err = ac.StringToBytes(args[0])
if err != nil {
return err
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
queryClient := authz.NewQueryClient(clientCtx)
res, err := queryClient.GranterGrants(
cmd.Context(),
&authz.QueryGranterGrantsRequest{
Granter: args[0],
Pagination: pageReq,
},
)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "granter-grants")
return cmd
}
// GetQueryGranteeGrants returns cmd to query for all grants for a grantee.
func GetQueryGranteeGrants(ac address.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "grants-by-grantee [grantee-addr]",
Args: cobra.ExactArgs(1),
Short: "query authorization grants granted to a grantee",
Long: strings.TrimSpace(
fmt.Sprintf(`Query authorization grants granted to a grantee.
Examples:
$ %s q %s grants-by-grantee cosmos1skj..
`,
version.AppName, authz.ModuleName),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
_, err = ac.StringToBytes(args[0])
if err != nil {
return err
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
queryClient := authz.NewQueryClient(clientCtx)
res, err := queryClient.GranteeGrants(
cmd.Context(),
&authz.QueryGranteeGrantsRequest{
Grantee: args[0],
Pagination: pageReq,
},
)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "grantee-grants")
return cmd
}
-315
View File
@@ -1,315 +0,0 @@
package cli_test
import (
"fmt"
"time"
sdkmath "cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client/flags"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz"
"github.com/cosmos/cosmos-sdk/x/authz/client/cli"
authzclitestutil "github.com/cosmos/cosmos-sdk/x/authz/client/testutil"
)
func (s *CLITestSuite) TestQueryAuthorizations() {
val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)
grantee := s.grantee[0]
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
_, err := authzclitestutil.CreateGrant(
s.clientCtx,
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val[0].Address),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(10))).String()),
},
)
s.Require().NoError(err)
testCases := []struct {
name string
args []string
expectErr bool
expErrMsg string
}{
{
"Error: Invalid grantee",
[]string{
val[0].Address.String(),
"invalid grantee",
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
true,
"decoding bech32 failed: invalid character in string: ' '",
},
{
"Error: Invalid granter",
[]string{
"invalid granter",
grantee.String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
true,
"decoding bech32 failed: invalid character in string: ' '",
},
{
"Valid txn (json)",
[]string{
val[0].Address.String(),
grantee.String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
``,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryGrants(addresscodec.NewBech32Codec("cosmos"))
resp, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
s.Require().Contains(string(resp.Bytes()), tc.expErrMsg)
} else {
s.Require().NoError(err)
var grants authz.QueryGrantsResponse
err = s.clientCtx.Codec.UnmarshalJSON(resp.Bytes(), &grants)
s.Require().NoError(err)
}
})
}
}
func (s *CLITestSuite) TestQueryAuthorization() {
val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)
grantee := s.grantee[0]
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
_, err := authzclitestutil.CreateGrant(
s.clientCtx,
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val[0].Address),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(10))).String()),
},
)
s.Require().NoError(err)
testCases := []struct {
name string
args []string
expectErr bool
}{
{
"Error: Invalid grantee",
[]string{
val[0].Address.String(),
"invalid grantee",
typeMsgSend,
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
true,
},
{
"Error: Invalid granter",
[]string{
"invalid granter",
grantee.String(),
typeMsgSend,
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
true,
},
{
"Valid txn (json)",
[]string{
val[0].Address.String(),
grantee.String(),
typeMsgSend,
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
},
{
"Valid txn with allowed list (json)",
[]string{
val[0].Address.String(),
s.grantee[3].String(),
typeMsgSend,
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryGrants(addresscodec.NewBech32Codec("cosmos"))
_, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
}
})
}
}
func (s *CLITestSuite) TestQueryGranteeGrants() {
val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)
grantee := s.grantee[0]
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
require := s.Require()
_, err := authzclitestutil.CreateGrant(
s.clientCtx,
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val[0].Address),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(10))).String()),
},
)
s.Require().NoError(err)
testCases := []struct {
name string
args []string
expectErr bool
expectedErr string
}{
{
"invalid address",
[]string{
"invalid-address",
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
true,
"decoding bech32 failed",
},
{
"valid case",
[]string{
grantee.String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
"",
},
{
"valid case with pagination",
[]string{
grantee.String(),
"--limit=2",
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
"",
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
cmd := cli.GetQueryGranteeGrants(addresscodec.NewBech32Codec("cosmos"))
out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expectErr {
require.Error(err)
require.Contains(out.String(), tc.expectedErr)
} else {
require.NoError(err)
var grants authz.QueryGranteeGrantsResponse
require.NoError(s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), &grants))
}
})
}
}
func (s *CLITestSuite) TestQueryGranterGrants() {
val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)
grantee := s.grantee[0]
require := s.Require()
testCases := []struct {
name string
args []string
expectErr bool
expectedErr string
}{
{
"invalid address",
[]string{
"invalid-address",
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
true,
"decoding bech32 failed",
},
{
"no authorization found",
[]string{
grantee.String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
"",
},
{
"valid case",
[]string{
val[0].Address.String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
"",
},
{
"valid case with pagination",
[]string{
val[0].Address.String(),
"--limit=2",
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
"",
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
cmd := cli.GetQueryGranterGrants(addresscodec.NewBech32Codec("cosmos"))
out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expectErr {
require.Error(err)
require.Contains(out.String(), tc.expectedErr)
} else {
require.NoError(err)
var grants authz.QueryGranterGrantsResponse
require.NoError(s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), &grants))
}
})
}
}