db525127
feat: add middleware package with YAML config loading
a73x 2026-03-31 05:46
diff --git a/middleware/middleware.go b/middleware/middleware.go new file mode 100644 index 0000000..8be111e --- /dev/null +++ b/middleware/middleware.go @@ -0,0 +1,59 @@ package middleware import ( "fmt" "os" "gopkg.in/yaml.v3" ) type Rule struct { Match string Action string Dest string } type Middleware struct { rules []Rule } type yamlRule struct { Match string `yaml:"match"` Action string `yaml:"action"` Dest string `yaml:"dest"` } type yamlConfig struct { Middleware []yamlRule `yaml:"middleware"` } // New loads middleware config from a YAML file. // Returns an empty Middleware if the file does not exist. func New(path string) (*Middleware, error) { data, err := os.ReadFile(path) if err != nil { if os.IsNotExist(err) { return &Middleware{}, nil } return nil, fmt.Errorf("reading middleware config: %w", err) } var cfg yamlConfig if err := yaml.Unmarshal(data, &cfg); err != nil { return nil, fmt.Errorf("parsing middleware YAML: %w", err) } rules := make([]Rule, 0, len(cfg.Middleware)) for _, yr := range cfg.Middleware { if yr.Action != "save_response" { return nil, fmt.Errorf("unknown middleware action %q for match %q", yr.Action, yr.Match) } rules = append(rules, Rule{Match: yr.Match, Action: yr.Action, Dest: yr.Dest}) } return &Middleware{rules: rules}, nil } func (m *Middleware) RuleCount() int { return len(m.rules) } diff --git a/middleware/middleware_test.go b/middleware/middleware_test.go new file mode 100644 index 0000000..367a6b8 --- /dev/null +++ b/middleware/middleware_test.go @@ -0,0 +1,52 @@ package middleware_test import ( "os" "path/filepath" "testing" "github.com/xanderle/nono/middleware" ) func TestNewLoadsConfig(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "middleware.yaml") os.WriteFile(path, []byte(`middleware: - match: "api.anthropic.com/api/oauth/usage" action: save_response dest: "/tmp/usage.json" `), 0644) mw, err := middleware.New(path) if err != nil { t.Fatalf("unexpected error: %v", err) } if mw.RuleCount() != 1 { t.Errorf("expected 1 rule, got %d", mw.RuleCount()) } } func TestNewReturnsEmptyForMissingFile(t *testing.T) { mw, err := middleware.New("/nonexistent/middleware.yaml") if err != nil { t.Fatalf("unexpected error: %v", err) } if mw.RuleCount() != 0 { t.Errorf("expected 0 rules, got %d", mw.RuleCount()) } } func TestNewRejectsUnknownAction(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "middleware.yaml") os.WriteFile(path, []byte(`middleware: - match: "example.com/foo" action: delete_everything dest: "/tmp/out" `), 0644) _, err := middleware.New(path) if err == nil { t.Fatal("expected error for unknown action") } }