Skip to content

Commit 321edfe

Browse files
authored
adds --config flag with config file load and parsing (#46)
* adds `--config` flag with config file load and parsing Signed-off-by: ChrisJBurns <[email protected]> * lint Signed-off-by: ChrisJBurns <[email protected]> * adds docs Signed-off-by: ChrisJBurns <[email protected]> --------- Signed-off-by: ChrisJBurns <[email protected]>
1 parent 77690d7 commit 321edfe

File tree

6 files changed

+351
-1
lines changed

6 files changed

+351
-1
lines changed

cmd/thv-registry-api/app/serve.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717
"k8s.io/client-go/rest"
1818
"k8s.io/client-go/tools/clientcmd"
1919

20+
"github.com/stacklok/toolhive-registry-server/pkg/config"
21+
2022
v1 "github.com/stacklok/toolhive-registry-server/cmd/thv-registry-api/api/v1"
2123
"github.com/stacklok/toolhive-registry-server/cmd/thv-registry-api/internal/service"
2224
thvk8scli "github.com/stacklok/toolhive/pkg/container/kubernetes"
@@ -46,6 +48,7 @@ const (
4648

4749
func init() {
4850
serveCmd.Flags().String("address", ":8080", "Address to listen on")
51+
serveCmd.Flags().String("config", "", "Path to configuration file (YAML format)")
4952
serveCmd.Flags().String("from-configmap", "", "ConfigMap name containing registry data (mutually exclusive with --from-file)")
5053
serveCmd.Flags().String("from-file", "", "File path to registry.json (mutually exclusive with --from-configmap)")
5154
serveCmd.Flags().String("registry-name", "", "Registry name identifier (required)")
@@ -54,6 +57,10 @@ func init() {
5457
if err != nil {
5558
logger.Fatalf("Failed to bind address flag: %v", err)
5659
}
60+
err = viper.BindPFlag("config", serveCmd.Flags().Lookup("config"))
61+
if err != nil {
62+
logger.Fatalf("Failed to bind config flag: %v", err)
63+
}
5764
err = viper.BindPFlag("from-configmap", serveCmd.Flags().Lookup("from-configmap"))
5865
if err != nil {
5966
logger.Fatalf("Failed to bind from-configmap flag: %v", err)
@@ -141,6 +148,17 @@ func runServe(_ *cobra.Command, _ []string) error {
141148

142149
logger.Infof("Starting registry API server on %s", address)
143150

151+
configPath := viper.GetString("config")
152+
if configPath != "" {
153+
// TODO: Use the configuration
154+
// TODO: Validate the path to avoid path traversal issues
155+
_, err := config.NewConfigLoader().LoadConfig(configPath)
156+
if err != nil {
157+
return fmt.Errorf("failed to load configuration: %w", err)
158+
}
159+
logger.Infof("Loaded configuration from %s", configPath)
160+
}
161+
144162
providerConfig, err := buildProviderConfig()
145163
if err != nil {
146164
return fmt.Errorf("failed to build provider configuration: %w", err)

docs/cli/thv-registry-api_serve.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ thv-registry-api serve [flags]
3131

3232
```
3333
--address string Address to listen on (default ":8080")
34+
--config string Path to configuration file (YAML format)
3435
--from-configmap string ConfigMap name containing registry data (mutually exclusive with --from-file)
3536
--from-file string File path to registry.json (mutually exclusive with --from-configmap)
3637
-h, --help help for serve

go.mod

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.24.6
44

55
require (
66
github.com/go-chi/chi/v5 v5.2.3
7+
github.com/go-git/go-git/v5 v5.16.3
78
github.com/spf13/viper v1.21.0
89
github.com/stacklok/toolhive v0.4.0
910
github.com/stretchr/testify v1.11.1
@@ -20,13 +21,16 @@ require (
2021
github.com/KyleBanks/depth v1.2.1 // indirect
2122
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
2223
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
24+
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
2325
github.com/danieljoos/wincred v1.2.2 // indirect
2426
github.com/dylibso/observe-sdk/go v0.0.0-20240819160327-2d926c5d788a // indirect
2527
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
2628
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
2729
github.com/extism/go-sdk v1.7.0 // indirect
2830
github.com/fsnotify/fsnotify v1.9.0 // indirect
2931
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
32+
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
33+
github.com/go-git/go-billy/v5 v5.6.2 // indirect
3034
github.com/go-logr/zapr v1.3.0 // indirect
3135
github.com/go-openapi/jsonpointer v0.21.1 // indirect
3236
github.com/go-openapi/jsonreference v0.21.0 // indirect
@@ -62,7 +66,7 @@ require (
6266
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
6367
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
6468
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
65-
github.com/rogpeppe/go-internal v1.14.1 // indirect
69+
github.com/pjbgf/sha1cd v0.3.2 // indirect
6670
github.com/russross/blackfriday/v2 v2.1.0 // indirect
6771
github.com/sagikazarmark/locafero v0.11.0 // indirect
6872
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
@@ -95,6 +99,7 @@ require (
9599
google.golang.org/protobuf v1.36.9 // indirect
96100
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
97101
gopkg.in/inf.v0 v0.9.1 // indirect
102+
gopkg.in/warnings.v0 v0.1.2 // indirect
98103
gopkg.in/yaml.v2 v2.4.0 // indirect
99104
k8s.io/api v0.34.1 // indirect
100105
k8s.io/klog/v2 v2.130.1 // indirect

go.sum

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
1919
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
2020
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
2121
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
22+
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
23+
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
2224
github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0=
2325
github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8=
2426
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -43,6 +45,12 @@ github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sa
4345
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
4446
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
4547
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
48+
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
49+
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
50+
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
51+
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
52+
github.com/go-git/go-git/v5 v5.16.3 h1:Z8BtvxZ09bYm/yYNgPKCzgWtaRqDTgIKRgIRHBfU6Z8=
53+
github.com/go-git/go-git/v5 v5.16.3/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
4654
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
4755
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
4856
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
@@ -140,6 +148,8 @@ github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
140148
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
141149
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
142150
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
151+
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
152+
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
143153
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
144154
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
145155
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -278,6 +288,8 @@ gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSP
278288
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
279289
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
280290
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
291+
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
292+
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
281293
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
282294
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
283295
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

pkg/config/config.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package config
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"gopkg.in/yaml.v3"
8+
)
9+
10+
// ConfigLoader defines the interface for loading configuration
11+
type ConfigLoader interface {
12+
LoadConfig(path string) (*Config, error)
13+
}
14+
15+
// Config represents the root configuration structure
16+
type Config struct {
17+
Source SourceConfig `yaml:"source"`
18+
SyncPolicy SyncPolicyConfig `yaml:"syncPolicy"`
19+
Filter FilterConfig `yaml:"filter"`
20+
}
21+
22+
// SourceConfig defines the data source configuration
23+
type SourceConfig struct {
24+
Type string `yaml:"type"`
25+
ConfigMap *ConfigMapConfig `yaml:"configmap,omitempty"`
26+
}
27+
28+
// ConfigMapConfig defines Kubernetes ConfigMap source settings
29+
type ConfigMapConfig struct {
30+
Name string `yaml:"name"`
31+
}
32+
33+
// SyncPolicyConfig defines synchronization settings
34+
type SyncPolicyConfig struct {
35+
Interval string `yaml:"interval"`
36+
}
37+
38+
// FilterConfig defines filtering rules for registry entries
39+
type FilterConfig struct {
40+
Tags TagFilterConfig `yaml:"tags"`
41+
}
42+
43+
// TagFilterConfig defines tag-based filtering
44+
type TagFilterConfig struct {
45+
Include []string `yaml:"include,omitempty"`
46+
Exclude []string `yaml:"exclude,omitempty"`
47+
}
48+
49+
// configLoader implements the ConfigLoader interface
50+
type configLoader struct{}
51+
52+
// NewConfigLoader creates a new ConfigLoader instance
53+
func NewConfigLoader() ConfigLoader {
54+
return &configLoader{}
55+
}
56+
57+
// LoadConfig loads and parses configuration from a YAML file
58+
func (c *configLoader) LoadConfig(path string) (*Config, error) {
59+
// Read the entire file into memory
60+
data, err := os.ReadFile(path)
61+
if err != nil {
62+
return nil, fmt.Errorf("failed to read config file: %w", err)
63+
}
64+
65+
// Parse YAML content
66+
var config Config
67+
if err := yaml.Unmarshal(data, &config); err != nil {
68+
return nil, fmt.Errorf("failed to parse YAML config: %w", err)
69+
}
70+
71+
return &config, nil
72+
}

0 commit comments

Comments
 (0)