package config import ( "fmt" "io" "os" "gopkg.in/yaml.v3" ) // LoadPipeline loads pipeline configuration from a YAML file with strict field checking. func LoadPipeline(path string) (*PipelineConfig, error) { var cfg PipelineConfig if err := decodeStrictYAML(path, &cfg); err != nil { return nil, fmt.Errorf("load pipeline config: %w", err) } return &cfg, nil } // LoadSession loads session configuration from a YAML file with strict field checking. func LoadSession(path string) (*SessionConfig, error) { var cfg SessionConfig if err := decodeStrictYAML(path, &cfg); err != nil { return nil, fmt.Errorf("load session config: %w", err) } return &cfg, nil } // Load loads and resolves combined pipeline and session configuration. func Load(pipelinePath, sessionPath string) (*Config, error) { pipelineCfg, err := LoadPipeline(pipelinePath) if err != nil { return nil, err } sessionCfg, err := LoadSession(sessionPath) if err != nil { return nil, err } return &Config{ Pipeline: pipelineCfg, Session: sessionCfg, PipelinePath: pipelinePath, SessionPath: sessionPath, }, nil } func decodeStrictYAML(path string, out any) error { f, err := os.Open(path) if err != nil { return fmt.Errorf("open %q: %w", path, err) } defer f.Close() dec := yaml.NewDecoder(f) dec.KnownFields(true) if err := dec.Decode(out); err != nil { return fmt.Errorf("decode %q: %w", path, err) } var extra any if err := dec.Decode(&extra); err != nil && err != io.EOF { return fmt.Errorf("decode trailing content in %q: %w", path, err) } return nil }