551317953c72552439ec70ad778c2efa2faff25c

Author
Ayman Bagabas <ayman.bagabas@gmail.com>
Committer
Ayman Bagabas <ayman.bagabas@gmail.com>
Date

Message

fix(config): parse initial admin keys paths

Diff

  1diff --git a/.gitignore b/.gitignore
  2index ae70eac83c310247658c36ab11f4e764026d29b1..041a83d7fdefbb79b4786c8b5d52cde3f56ad771 100644
  3--- a/.gitignore
  4+++ b/.gitignore
  5@@ -3,7 +3,6 @@ cmd/soft/soft
  6 .ssh
  7 .repos
  8 dist
  9-testdata
 10 data/
 11 completions/
 12 manpages/
 13diff --git a/server/config/config.go b/server/config/config.go
 14index 36a5bddcd8449369c9f13bf33c55e67cd47ccf09..13ecd1268a79c32ebf67cf7551e922c090ba29cf 100644
 15--- a/server/config/config.go
 16+++ b/server/config/config.go
 17@@ -143,6 +143,9 @@ func parseConfig(path string) (*Config, error) {
 18 		}
 19 	}
 20 
 21+	// Merge initial admin keys from both config file and environment variables.
 22+	initialAdminKeys := append([]string{}, cfg.InitialAdminKeys...)
 23+
 24 	// Override with environment variables
 25 	if err := env.Parse(cfg, env.Options{
 26 		Prefix: "SOFT_SERVE_",
 27@@ -150,13 +153,31 @@ func parseConfig(path string) (*Config, error) {
 28 		return cfg, fmt.Errorf("parse environment variables: %w", err)
 29 	}
 30 
 31+	// Merge initial admin keys from environment variables.
 32+	if initialAdminKeysEnv := os.Getenv("SOFT_SERVE_INITIAL_ADMIN_KEYS"); initialAdminKeysEnv != "" {
 33+		cfg.InitialAdminKeys = append(cfg.InitialAdminKeys, initialAdminKeys...)
 34+	}
 35+
 36+	// Validate keys
 37+	pks := make([]string, 0)
 38 	for _, key := range cfg.InitialAdminKeys {
 39-		if _, _, err := backend.ParseAuthorizedKey(key); err != nil {
 40-			log.Error("invalid initial admin key", "err", err)
 41+		var pk string
 42+		if bts, err := os.ReadFile(key); err == nil {
 43+			// key is a file
 44+			pk = string(bts)
 45+		}
 46+		if _, _, err := backend.ParseAuthorizedKey(key); err == nil {
 47+			pk = key
 48+		}
 49+		pk = strings.TrimSpace(pk)
 50+		if pk != "" {
 51+			log.Debugf("found initial admin key: %q", key)
 52+			pks = append(pks, pk)
 53 		}
 54-		log.Debugf("found initial admin key: %q", key)
 55 	}
 56 
 57+	cfg.InitialAdminKeys = pks
 58+
 59 	// Reset datapath to config dir.
 60 	// This is necessary because the environment variable may be set to
 61 	// a different directory.
 62diff --git a/server/config/config_test.go b/server/config/config_test.go
 63index b3685209546af8797855750b6c23a415bd1a46d2..cd4a90198cc1f14ca1bdfaf88f242a5d26749226 100644
 64--- a/server/config/config_test.go
 65+++ b/server/config/config_test.go
 66@@ -2,18 +2,64 @@ package config
 67 
 68 import (
 69 	"os"
 70+	"path/filepath"
 71 	"testing"
 72 
 73 	"github.com/matryer/is"
 74+	"gopkg.in/yaml.v3"
 75 )
 76 
 77 func TestParseMultipleKeys(t *testing.T) {
 78 	is := is.New(t)
 79-	is.NoErr(os.Setenv("SOFT_SERVE_INITIAL_ADMIN_KEYS", "testdata/k1.pub\ntestdata/k2.pub"))
 80-	t.Cleanup(func() { is.NoErr(os.Unsetenv("SOFT_SERVE_INITIAL_ADMIN_KEYS")) })
 81+	td := t.TempDir()
 82+	is.NoErr(os.Setenv("SOFT_SERVE_INITIAL_ADMIN_KEYS", "testdata/k1.pub\nssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFxIobhwtfdwN7m1TFt9wx3PsfvcAkISGPxmbmbauST8 a@b"))
 83+	is.NoErr(os.Setenv("SOFT_SERVE_DATA_PATH", td))
 84+	t.Cleanup(func() {
 85+		is.NoErr(os.Unsetenv("SOFT_SERVE_INITIAL_ADMIN_KEYS"))
 86+		is.NoErr(os.Unsetenv("SOFT_SERVE_DATA_PATH"))
 87+	})
 88 	cfg := DefaultConfig()
 89 	is.Equal(cfg.InitialAdminKeys, []string{
 90-		"testdata/k1.pub",
 91-		"testdata/k2.pub",
 92+		"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINMwLvyV3ouVrTysUYGoJdl5Vgn5BACKov+n9PlzfPwH a@b",
 93+		"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFxIobhwtfdwN7m1TFt9wx3PsfvcAkISGPxmbmbauST8 a@b",
 94+	})
 95+}
 96+
 97+func TestMergeInitAdminKeys(t *testing.T) {
 98+	is := is.New(t)
 99+	is.NoErr(os.Setenv("SOFT_SERVE_INITIAL_ADMIN_KEYS", "testdata/k1.pub"))
100+	t.Cleanup(func() { is.NoErr(os.Unsetenv("SOFT_SERVE_INITIAL_ADMIN_KEYS")) })
101+	bts, err := yaml.Marshal(&Config{
102+		InitialAdminKeys: []string{"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFxIobhwtfdwN7m1TFt9wx3PsfvcAkISGPxmbmbauST8 a@b"},
103+	})
104+	is.NoErr(err)
105+	fp := filepath.Join(t.TempDir(), "config.yaml")
106+	err = os.WriteFile(fp, bts, 0644)
107+	is.NoErr(err)
108+	cfg, err := ParseConfig(fp)
109+	is.NoErr(err)
110+	is.Equal(cfg.InitialAdminKeys, []string{
111+		"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINMwLvyV3ouVrTysUYGoJdl5Vgn5BACKov+n9PlzfPwH a@b",
112+		"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFxIobhwtfdwN7m1TFt9wx3PsfvcAkISGPxmbmbauST8 a@b",
113+	})
114+}
115+
116+func TestValidateInitAdminKeys(t *testing.T) {
117+	is := is.New(t)
118+	bts, err := yaml.Marshal(&Config{
119+		InitialAdminKeys: []string{
120+			"testdata/k1.pub",
121+			"abc",
122+			"",
123+		},
124+	})
125+	is.NoErr(err)
126+	fp := filepath.Join(t.TempDir(), "config.yaml")
127+	err = os.WriteFile(fp, bts, 0644)
128+	is.NoErr(err)
129+	cfg, err := ParseConfig(fp)
130+	is.NoErr(err)
131+	is.Equal(cfg.InitialAdminKeys, []string{
132+		"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINMwLvyV3ouVrTysUYGoJdl5Vgn5BACKov+n9PlzfPwH a@b",
133 	})
134 }
135diff --git a/server/config/testdata/k1.pub b/server/config/testdata/k1.pub
136new file mode 100644
137index 0000000000000000000000000000000000000000..d82e29394d343e6e36bc1759b06689a399ea80a4
138--- /dev/null
139+++ b/server/config/testdata/k1.pub
140@@ -0,0 +1 @@
141+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINMwLvyV3ouVrTysUYGoJdl5Vgn5BACKov+n9PlzfPwH a@b