diff --git a/cmd/soft/hook.go b/cmd/soft/hook.go index 52619c409ac8d84105062c22bc9fc8ea97dad14d..4054303c5f927c7fb464b19ed18475d8f1686619 100644 --- a/cmd/soft/hook.go +++ b/cmd/soft/hook.go @@ -141,9 +141,6 @@ func commonInit() (c *gossh.Client, s *gossh.Session, err error) { return } - // Use absolute path. - cfg.DataPath = filepath.Dir(configPath) - // Git runs the hook within the repository's directory. // Get the working directory to determine the repository name. wd, err := os.Getwd() @@ -161,7 +158,7 @@ func commonInit() (c *gossh.Client, s *gossh.Session, err error) { return } repoName := strings.TrimPrefix(wd, rs) - repoName = strings.TrimPrefix(repoName, fmt.Sprintf("%c", os.PathSeparator)) + repoName = strings.TrimPrefix(repoName, string(os.PathSeparator)) c, err = newClient(cfg) if err != nil { return diff --git a/server/backend/sqlite/user.go b/server/backend/sqlite/user.go index 1afa8085fcac43779cba4dbdc3e2657aa185bde6..9f7e48273d3e12ffa31821debae11ca1855ae5db 100644 --- a/server/backend/sqlite/user.go +++ b/server/backend/sqlite/user.go @@ -118,10 +118,7 @@ func (d *SqliteBackend) AccessLevel(repo string, username string) backend.Access // // It implements backend.Backend. func (d *SqliteBackend) AccessLevelByPublicKey(repo string, pk ssh.PublicKey) backend.AccessLevel { - if ik, _, err := backend.ParseAuthorizedKey(d.cfg.InternalPublicKey); err == nil && backend.KeysEqual(ik, pk) { - return backend.AdminAccess - } - for _, k := range d.cfg.InitialAdminKeys { + for _, k := range append(d.cfg.InitialAdminKeys, d.cfg.InternalPublicKey) { ik, _, err := backend.ParseAuthorizedKey(k) if err == nil && backend.KeysEqual(pk, ik) { return backend.AdminAccess diff --git a/server/cmd/hook.go b/server/cmd/hook.go index 87a9184cb46e988aa5646a328dca6654f1b4a0b8..7e520e5c8dc0a774c25a0eb0a15845219fbf820d 100644 --- a/server/cmd/hook.go +++ b/server/cmd/hook.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/charmbracelet/keygen" + "github.com/charmbracelet/soft-serve/server/backend" "github.com/charmbracelet/soft-serve/server/hooks" "github.com/charmbracelet/ssh" "github.com/spf13/cobra" @@ -122,7 +123,7 @@ func checkIfInternal(cmd *cobra.Command, _ []string) error { logger.Errorf("failed to read internal key: %v", err) return err } - if !ssh.KeysEqual(pk, kp.PublicKey()) { + if !backend.KeysEqual(pk, kp.PublicKey()) { return ErrUnauthorized } return nil diff --git a/server/config/config.go b/server/config/config.go index b72dae3c31e91ac3dcef59ee84fd97db2cab789e..3935b5b12252f06e6f67821e57a22da94bbfba80 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -1,6 +1,8 @@ package config import ( + "errors" + "fmt" "os" "path/filepath" "strings" @@ -104,41 +106,8 @@ type Config struct { ClientPublicKey string `yaml:"-"` } -// ParseConfig parses the configuration from the given file. -func ParseConfig(path string) (*Config, error) { - cfg := &Config{} - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer f.Close() // nolint: errcheck - if err := yaml.NewDecoder(f).Decode(cfg); err != nil { - return nil, err - } - - if err := cfg.init(); err != nil { - return nil, err - } - - return cfg, nil -} - -// WriteConfig writes the configuration to the given file. -func WriteConfig(path string, cfg *Config) error { - if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil { - return err - } - return os.WriteFile(path, []byte(newConfigFile(cfg)), 0o600) // nolint: errcheck -} - -// DefaultConfig returns a Config with the values populated with the defaults -// or specified environment variables. -func DefaultConfig() *Config { - dataPath := os.Getenv("SOFT_SERVE_DATA_PATH") - if dataPath == "" { - dataPath = "data" - } - +func parseConfig(path string) (*Config, error) { + dataPath := filepath.Dir(path) cfg := &Config{ Name: "Soft Serve", DataPath: dataPath, @@ -166,20 +135,65 @@ func DefaultConfig() *Config { }, } - cp := filepath.Join(cfg.DataPath, "config.yaml") - f, err := os.Open(cp) - if err == nil { - defer f.Close() // nolint: errcheck - if err := yaml.NewDecoder(f).Decode(cfg); err != nil { - log.Error("failed to decode config", "err", err) - } + f, err := os.Open(path) + if err != nil { + return cfg, err + } + + defer f.Close() // nolint: errcheck + if err := yaml.NewDecoder(f).Decode(cfg); err != nil { + return cfg, fmt.Errorf("decode config: %w", err) } // Override with environment variables if err := env.Parse(cfg, env.Options{ Prefix: "SOFT_SERVE_", }); err != nil { - log.Fatal(err) + return cfg, fmt.Errorf("parse environment variables: %w", err) + } + + // Reset datapath to config dir. + // This is necessary because the environment variable may be set to + // a different directory. + cfg.DataPath = dataPath + + return cfg, nil +} + +// ParseConfig parses the configuration from the given file. +func ParseConfig(path string) (*Config, error) { + cfg, err := parseConfig(path) + if err != nil { + return nil, err + } + + if err := cfg.validate(); err != nil { + return nil, err + } + + return cfg, nil +} + +// WriteConfig writes the configuration to the given file. +func WriteConfig(path string, cfg *Config) error { + if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil { + return err + } + return os.WriteFile(path, []byte(newConfigFile(cfg)), 0o600) // nolint: errcheck +} + +// DefaultConfig returns a Config with the values populated with the defaults +// or specified environment variables. +func DefaultConfig() *Config { + dataPath := os.Getenv("SOFT_SERVE_DATA_PATH") + if dataPath == "" { + dataPath = "data" + } + + cp := filepath.Join(dataPath, "config.yaml") + cfg, err := parseConfig(cp) + if err != nil && !errors.Is(err, os.ErrNotExist) { + log.Errorf("failed to parse config: %v", err) } // Write config if it doesn't exist @@ -189,7 +203,7 @@ func DefaultConfig() *Config { } } - if err := cfg.init(); err != nil { + if err := cfg.validate(); err != nil { log.Fatal(err) } @@ -202,7 +216,7 @@ func (c *Config) WithBackend(backend backend.Backend) *Config { return c } -func (c *Config) init() error { +func (c *Config) validate() error { // Use absolute paths if !filepath.IsAbs(c.DataPath) { dp, err := filepath.Abs(c.DataPath)