Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
35 changes: 34 additions & 1 deletion cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import (
"strings"

"github.com/jongio/grut/internal/config"
"github.com/jongio/grut/internal/keymap"
toml "github.com/pelletier/go-toml/v2"
"github.com/spf13/cobra"
)

type (
configLoadFunc func() (*config.Config, error)
configPathFunc func() string
keymapLoadFunc func(string) (*keymap.Keymap, error)
)

func newConfigCmd() *cobra.Command {
Expand All @@ -33,21 +35,52 @@ func newConfigCmdWithDeps(load configLoadFunc, path configPathFunc) *cobra.Comma
}

func newConfigCheckCmd(load configLoadFunc, path configPathFunc) *cobra.Command {
return newConfigCheckCmdWithKeymap(load, path, keymap.NewKeymap)
}

func newConfigCheckCmdWithKeymap(load configLoadFunc, path configPathFunc, loadKeymap keymapLoadFunc) *cobra.Command {
return &cobra.Command{
Use: "check",
Short: "Validate the active grut configuration",
RunE: func(cmd *cobra.Command, args []string) error {
cfgPath := path()
if _, err := load(); err != nil {
cfg, err := load()
if err != nil {
fmt.Fprintf(cmd.OutOrStdout(), "Config: %s\n", cfgPath)
return fmt.Errorf("config check failed: %w", err)
}
if err := checkKeybindings(cmd, cfg, cfgPath, loadKeymap); err != nil {
return err
}
fmt.Fprintf(cmd.OutOrStdout(), "Config: %s\nOK\n", cfgPath)
return nil
},
}
}

const defaultKeybindingScheme = "default"

func checkKeybindings(cmd *cobra.Command, cfg *config.Config, cfgPath string, loadKeymap keymapLoadFunc) error {
scheme := cfg.General.KeybindingScheme
if scheme == "" {
scheme = defaultKeybindingScheme
}
km, err := loadKeymap(scheme)
if err != nil {
fmt.Fprintf(cmd.OutOrStdout(), "Config: %s\n", cfgPath)
return fmt.Errorf("config check failed: keybindings: %w", err)
}
conflicts := keymap.DetectConflicts(km.Bindings())
if len(conflicts) == 0 {
return nil
}
fmt.Fprintf(cmd.OutOrStdout(), "Config: %s\nKeybinding conflicts:\n", cfgPath)
for _, conflict := range conflicts {
fmt.Fprintf(cmd.OutOrStdout(), "- %s\n", conflict.String())
}
return fmt.Errorf("config check failed: %d keybinding conflict(s) found", len(conflicts))
}

// newConfigGetCmd builds the "config get" subcommand, which prints a single
// resolved configuration value addressed by a dotted key (for example
// "git.default_branch" or "preview"). Defaults are applied, so a key the user
Expand Down
27 changes: 27 additions & 0 deletions cmd/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"testing"

"github.com/jongio/grut/internal/config"
"github.com/jongio/grut/internal/keymap"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -43,6 +44,32 @@ func TestConfigCheckFailure(t *testing.T) {
assert.Contains(t, out.String(), `C:\Users\me\AppData\Roaming\grut\config.toml`)
}

func TestConfigCheckReportsKeybindingConflicts(t *testing.T) {
cmd := newConfigCheckCmdWithKeymap(
func() (*config.Config, error) {
return &config.Config{General: config.GeneralConfig{KeybindingScheme: "custom"}}, nil
},
func() string { return `C:\Users\me\AppData\Roaming\grut\config.toml` },
func(string) (*keymap.Keymap, error) {
return keymap.NewKeymapFromBindings([]keymap.Binding{
{Key: "x", Mode: keymap.ModePanel, Action: "one"},
{Key: "x", Mode: keymap.ModePanel, Action: "two"},
}), nil
},
)
var out bytes.Buffer
cmd.SetOut(&out)

err := cmd.Execute()

require.Error(t, err)
assert.Contains(t, err.Error(), "keybinding conflict")
assert.Contains(t, out.String(), "Keybinding conflicts")
assert.Contains(t, out.String(), `key "x"`)
assert.Contains(t, out.String(), "one")
assert.Contains(t, out.String(), "two")
}

func TestRootRegistersConfigCheck(t *testing.T) {
root, cleanup := newRootCommand()
defer cleanup()
Expand Down
5 changes: 4 additions & 1 deletion internal/update/cosign.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ const (

// maxCosignArtifactSize limits cosign artifact downloads to 256 KiB.
maxCosignArtifactSize int64 = 256 << 10

// pemTypeCertificate is the PEM block type for X.509 certificates.
pemTypeCertificate = "CERTIFICATE"
)

// Fulcio OIDC extension OIDs per the Sigstore Fulcio certificate specification.
Expand Down Expand Up @@ -160,7 +163,7 @@ func parseSigstoreBundle(data []byte) ([]byte, []byte, error) {
}

certPEM := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Type: pemTypeCertificate,
Bytes: derBytes,
})

Expand Down
Loading