Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(cmd/celestia): Split subcommands into full subcommands and auxiliary #4131

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cmd/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ func AuthCmd(fsets ...*flag.FlagSet) *cobra.Command {
Short: "Signs and outputs a hex-encoded JWT token with the given permissions.",
Long: "Signs and outputs a hex-encoded JWT token with the given permissions. NOTE: only use this command when " +
"the node has already been initialized and started.",
PreRunE: func(cmd *cobra.Command, _ []string) error {
return ParseMinimumFlags(cmd)
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return errors.New("must specify permissions")
Expand Down
52 changes: 51 additions & 1 deletion cmd/celestia/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@ package main
import (
"bytes"
"context"
"io"
"os"
"reflect"
"testing"

"github.com/cristalhq/jwt/v5"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/celestiaorg/celestia-node/api/rpc/perms"
"github.com/celestiaorg/celestia-node/header"
"github.com/celestiaorg/celestia-node/libs/authtoken"
"github.com/celestiaorg/celestia-node/libs/keystore"
nodemod "github.com/celestiaorg/celestia-node/nodebuilder/node"
)

func TestCompletionHelpString(t *testing.T) {
Expand Down Expand Up @@ -49,7 +56,7 @@ func TestLight(t *testing.T) {
output := &bytes.Buffer{}
rootCmd.SetOut(output)
rootCmd.SetArgs([]string{
"bridge",
"light",
"--node.store", ".celestia-light",
"init",
})
Expand Down Expand Up @@ -102,6 +109,49 @@ func TestBridge(t *testing.T) {
err := rootCmd.ExecuteContext(context.Background())
require.NoError(t, err)
})
// tests that auth admin token generated by node via CLI
// can be verified + contains expected perms
t.Run("auth", func(t *testing.T) {
rootCmd.SetOut(&bytes.Buffer{})
rootCmd.SetArgs([]string{
"bridge",
"--node.store", ".celestia-bridge",
"init",
})
err := rootCmd.ExecuteContext(context.Background())
require.NoError(t, err)

ogStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

rootCmd.SetArgs([]string{
"bridge",
"auth", "admin",
"--node.store", ".celestia-bridge",
})

err = rootCmd.ExecuteContext(context.Background())
require.NoError(t, err)

err = w.Close()
require.NoError(t, err)
os.Stdout = ogStdout

ks, err := keystore.NewFSKeystore(".celestia-bridge/keys", nil)
require.NoError(t, err)
key, err := ks.Get(nodemod.SecretName)
require.NoError(t, err)
verifier, err := jwt.NewVerifierHS(jwt.HS256, key.Body)
require.NoError(t, err)

token, err := io.ReadAll(r)
require.NoError(t, err)

permissions, err := authtoken.ExtractSignedPermissions(verifier, string(token))
require.NoError(t, err)
assert.Equal(t, permissions, perms.AllPerms)
})

t.Cleanup(func() {
if err := os.Chdir(testDir); err != nil {
Expand Down
16 changes: 13 additions & 3 deletions cmd/celestia/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,21 @@ import (
cmdnode "github.com/celestiaorg/celestia-node/cmd"
)

// WithSubcommands returns the set of commands that require the full flagset.
func WithSubcommands() func(*cobra.Command, []*pflag.FlagSet) {
return func(c *cobra.Command, flags []*pflag.FlagSet) {
c.AddCommand(
cmdnode.Init(flags...),
cmdnode.Start(cmdnode.WithFlagSet(flags)),
)
}
}

// WithAuxiliarySubcommands returns the set of commands that require only the
// minimum flagset for node store determination.
func WithAuxiliarySubcommands() func(*cobra.Command, []*pflag.FlagSet) {
return func(c *cobra.Command, flags []*pflag.FlagSet) {
c.AddCommand(
cmdnode.AuthCmd(flags...),
cmdnode.ResetStore(flags...),
cmdnode.RemoveConfigCmd(flags...),
Expand All @@ -24,9 +34,9 @@ func WithSubcommands() func(*cobra.Command, []*pflag.FlagSet) {
}

func init() {
bridgeCmd := cmdnode.NewBridge(WithSubcommands())
lightCmd := cmdnode.NewLight(WithSubcommands())
fullCmd := cmdnode.NewFull(WithSubcommands())
bridgeCmd := cmdnode.NewBridge(WithSubcommands(), WithAuxiliarySubcommands())
lightCmd := cmdnode.NewLight(WithSubcommands(), WithAuxiliarySubcommands())
fullCmd := cmdnode.NewFull(WithSubcommands(), WithAuxiliarySubcommands())
rootCmd.AddCommand(
bridgeCmd,
lightCmd,
Expand Down
6 changes: 6 additions & 0 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ func RemoveConfigCmd(fsets ...*flag.FlagSet) *cobra.Command {
Use: "config-remove",
Short: "Deletes the node's config",
Args: cobra.NoArgs,
PreRunE: func(cmd *cobra.Command, _ []string) error {
return ParseMinimumFlags(cmd)
},
RunE: func(cmd *cobra.Command, _ []string) error {
ctx := cmd.Context()
return nodebuilder.RemoveConfig(StorePath(ctx))
Expand All @@ -31,6 +34,9 @@ func UpdateConfigCmd(fsets ...*flag.FlagSet) *cobra.Command {
Long: "Updates the node's outdated config with default values from newly-added fields. Check the config " +
" afterwards to ensure all old custom values were preserved.",
Args: cobra.NoArgs,
PreRunE: func(cmd *cobra.Command, _ []string) error {
return ParseMinimumFlags(cmd)
},
RunE: func(cmd *cobra.Command, _ []string) error {
ctx := cmd.Context()
return nodebuilder.UpdateConfig(NodeType(ctx), StorePath(ctx))
Expand Down
26 changes: 22 additions & 4 deletions cmd/flags_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,24 @@ const (
nodeConfigFlag = "node.config"
)

// NodeFlags gives a set of hardcoded Node package flags.
func NodeFlags() *flag.FlagSet {
func NodeStoreFlag() *flag.FlagSet {
flags := &flag.FlagSet{}

flags.String(
nodeStoreFlag,
"",
"The path to root/home directory of your Celestia Node Store",
)

return flags
}

// NodeFlags gives a set of hardcoded Node package flags.
func NodeFlags() *flag.FlagSet {
flags := &flag.FlagSet{}

flags.AddFlagSet(NodeStoreFlag())

flags.String(
nodeConfigFlag,
"",
Expand All @@ -36,8 +45,7 @@ func NodeFlags() *flag.FlagSet {
return flags
}

// ParseNodeFlags parses Node flags from the given cmd and applies values to Env.
func ParseNodeFlags(ctx context.Context, cmd *cobra.Command, network p2p.Network) (context.Context, error) {
func ParseNodeStore(ctx context.Context, cmd *cobra.Command, network p2p.Network) (context.Context, error) {
store := cmd.Flag(nodeStoreFlag).Value.String()
if store == "" {
tp := NodeType(ctx)
Expand All @@ -47,7 +55,17 @@ func ParseNodeFlags(ctx context.Context, cmd *cobra.Command, network p2p.Network
return ctx, err
}
}

ctx = WithStorePath(ctx, store)
return ctx, nil
}

// ParseNodeFlags parses Node flags from the given cmd and applies values to Env.
func ParseNodeFlags(ctx context.Context, cmd *cobra.Command, network p2p.Network) (context.Context, error) {
ctx, err := ParseNodeStore(ctx, cmd, network)
if err != nil {
return ctx, err
}

nodeConfig := cmd.Flag(nodeConfigFlag).Value.String()
if nodeConfig != "" {
Expand Down
7 changes: 4 additions & 3 deletions cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import (
// Init constructs a CLI command to initialize Celestia Node of any type with the given flags.
func Init(fsets ...*flag.FlagSet) *cobra.Command {
cmd := &cobra.Command{
Use: "init",
Short: "Initialization for Celestia Node. Passed flags have persisted effect.",
Args: cobra.NoArgs,
Use: "init",
Short: "Initialization for Celestia Node. Passed flags have persisted effect.",
Args: cobra.NoArgs,
PreRunE: PreRunEnv,
RunE: func(cmd *cobra.Command, _ []string) error {
ctx := cmd.Context()

Expand Down
90 changes: 34 additions & 56 deletions cmd/node.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package cmd

import (
"fmt"
"strings"

"github.com/spf13/cobra"
"github.com/spf13/pflag"

Expand All @@ -14,79 +17,54 @@ import (
"github.com/celestiaorg/celestia-node/nodebuilder/state"
)

func NewBridge(options ...func(*cobra.Command, []*pflag.FlagSet)) *cobra.Command {
flags := []*pflag.FlagSet{
NodeFlags(),
p2p.Flags(),
MiscFlags(),
core.Flags(),
rpc.Flags(),
gateway.Flags(),
state.Flags(),
pruner.Flags(),
}
cmd := &cobra.Command{
Use: "bridge [subcommand]",
Args: cobra.NoArgs,
Short: "Manage your Bridge node",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return PersistentPreRunEnv(cmd, node.Bridge, args)
},
}
for _, option := range options {
option(cmd, flags)
}
return cmd
func NewBridge(addFullFlags, addMinFlags func(*cobra.Command, []*pflag.FlagSet)) *cobra.Command {
return createTopLevelCmd(node.Bridge, addFullFlags, addMinFlags)
}

func NewFull(addFullFlags, addMinFlags func(*cobra.Command, []*pflag.FlagSet)) *cobra.Command {
return createTopLevelCmd(node.Full, addFullFlags, addMinFlags)
}

func NewLight(addFullFlags, addMinFlags func(*cobra.Command, []*pflag.FlagSet)) *cobra.Command {
return createTopLevelCmd(node.Light, addFullFlags, addMinFlags)
}

func NewLight(options ...func(*cobra.Command, []*pflag.FlagSet)) *cobra.Command {
flags := []*pflag.FlagSet{
func createTopLevelCmd(
nodeType node.Type,
addFullFlags,
addMinFlags func(*cobra.Command, []*pflag.FlagSet),
) *cobra.Command {
fullFlags := []*pflag.FlagSet{
NodeFlags(),
p2p.Flags(),
header.Flags(),
MiscFlags(),
core.Flags(),
rpc.Flags(),
gateway.Flags(),
state.Flags(),
pruner.Flags(),
}
cmd := &cobra.Command{
Use: "light [subcommand]",
Args: cobra.NoArgs,
Short: "Manage your Light node",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return PersistentPreRunEnv(cmd, node.Light, args)
},
}
for _, option := range options {
option(cmd, flags)
if nodeType != node.Bridge {
fullFlags = append(fullFlags, header.Flags())
}
return cmd
}

func NewFull(options ...func(*cobra.Command, []*pflag.FlagSet)) *cobra.Command {
flags := []*pflag.FlagSet{
NodeFlags(),
p2p.Flags(),
header.Flags(),
MiscFlags(),
core.Flags(),
rpc.Flags(),
gateway.Flags(),
state.Flags(),
pruner.Flags(),
minFlags := []*pflag.FlagSet{
NodeStoreFlag(),
p2p.NetworkFlag(),
}

cmd := &cobra.Command{
Use: "full [subcommand]",
Use: fmt.Sprintf("%s [subcommand]", strings.ToLower(nodeType.String())),
Args: cobra.NoArgs,
Short: "Manage your Full node",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return PersistentPreRunEnv(cmd, node.Full, args)
Short: fmt.Sprintf("Manage your %s node", strings.ToLower(nodeType.String())),
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
ctx := WithNodeType(cmd.Context(), nodeType)
cmd.SetContext(ctx)
},
}
for _, option := range options {
option(cmd, flags)
}

addFullFlags(cmd, fullFlags)
addMinFlags(cmd, minFlags)

return cmd
}
3 changes: 3 additions & 0 deletions cmd/reset_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ func ResetStore(fsets ...*flag.FlagSet) *cobra.Command {
Use: "unsafe-reset-store",
Short: "Resets the node's store to a new state. Leaves the keystore and config intact.",
Args: cobra.NoArgs,
PreRunE: func(cmd *cobra.Command, _ []string) error {
return ParseMinimumFlags(cmd)
},
RunE: func(cmd *cobra.Command, _ []string) error {
ctx := cmd.Context()

Expand Down
1 change: 1 addition & 0 deletions cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Options passed on start override configuration options only on start and are not
Aliases: []string{"run", "daemon"},
Args: cobra.NoArgs,
SilenceUsage: true,
PreRunE: PreRunEnv,
RunE: func(cmd *cobra.Command, _ []string) (err error) {
ctx := cmd.Context()

Expand Down
22 changes: 20 additions & 2 deletions cmd/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,31 @@
return decoded, nil
}

func PersistentPreRunEnv(cmd *cobra.Command, nodeType node.Type, _ []string) error {
func ParseMinimumFlags(cmd *cobra.Command) error {
ctx := cmd.Context()

Check failure on line 79 in cmd/util.go

View workflow job for this annotation

GitHub Actions / go-ci / Lint

ineffectual assignment to ctx (ineffassign)

net, err := p2p.ParseNetwork(cmd)
if err != nil {
return err
}
ctx = WithNetwork(cmd.Context(), net)

Check failure on line 85 in cmd/util.go

View workflow job for this annotation

GitHub Actions / go-ci / Lint

ineffectual assignment to ctx (ineffassign)

ctx, err = ParseNodeStore(cmd.Context(), cmd, net)
if err != nil {
return err
}

cmd.SetContext(ctx)
return nil
}

func PreRunEnv(cmd *cobra.Command, _ []string) error {
var (
ctx = cmd.Context()
err error
)

ctx = WithNodeType(ctx, nodeType)
nodeType := NodeType(ctx)

parsedNetwork, err := p2p.ParseNetwork(cmd)
if err != nil {
Expand Down
Loading
Loading