Files
narratio/internal/config/validate.go

115 lines
3.4 KiB
Go

package config
import (
"fmt"
"strings"
"gitea.maximumdirect.net/eric/narratio/internal/pathsafe"
)
// Validate checks resolved configuration for required fields and parseable durations.
func Validate(cfg *Config) error {
if cfg == nil {
return fmt.Errorf("config is nil")
}
if cfg.Pipeline == nil {
return fmt.Errorf("pipeline config is required")
}
if cfg.Campaign == nil {
return fmt.Errorf("campaign config is required")
}
if cfg.Session == nil {
return fmt.Errorf("session config is required")
}
if err := ValidatePipelineConfig(cfg.Pipeline); err != nil {
return fmt.Errorf("pipeline config %q invalid: %w", shortName(cfg.PipelinePath, "pipeline.yml"), err)
}
if err := ValidateCampaignConfig(cfg.Campaign); err != nil {
return fmt.Errorf("campaign config %q invalid: %w", shortName(cfg.CampaignPath, "campaign.yml"), err)
}
if err := validateSession(cfg.Session); err != nil {
return fmt.Errorf("session config %q invalid: %w", shortName(cfg.SessionPath, "session.yml"), err)
}
if err := validateResolvedPartyInputs(cfg); err != nil {
return fmt.Errorf("campaign/session config invalid: %w", err)
}
if err := validateCrossConfig(cfg.Pipeline, cfg.Session, cfg.StableInputs); err != nil {
return fmt.Errorf("pipeline/session config invalid: %w", err)
}
return nil
}
// ValidatePipelineConfig validates a loaded, defaulted pipeline without
// requiring session configuration. Callers that require party-driven artifact
// expansion must resolve a campaign first through LoadPipelineCampaign.
func ValidatePipelineConfig(cfg *PipelineConfig) error {
if cfg == nil {
return fmt.Errorf("pipeline config is required")
}
return validatePipeline(cfg)
}
// ValidateCampaignConfig validates a loaded campaign without requiring a
// session. Party parsing and canonical-party checks remain owned by
// LoadPipelineCampaign, which has the campaign source path available.
func ValidateCampaignConfig(cfg *CampaignConfig) error {
return validateCampaign(cfg)
}
func validatePipeline(cfg *PipelineConfig) error {
if strings.TrimSpace(cfg.Workspace.Root) == "" {
return fmt.Errorf("pipeline.workspace.root is required")
}
if campaignID := cfg.Campaigns.DefaultCampaignID; campaignID != "" {
if err := pathsafe.ValidateOpaqueSegment(campaignID); err != nil {
return fmt.Errorf("pipeline.campaigns.default_campaign_id: %w", err)
}
}
if err := validateSecrets(cfg.Secrets); err != nil {
return err
}
if err := validateStorage(cfg.Storage); err != nil {
return err
}
if err := validateSpool(cfg.Spool); err != nil {
return err
}
if err := validateCache(cfg.Cache); err != nil {
return err
}
if err := validateNotarius(cfg.Notarius, cfg.Scriptorium); err != nil {
return err
}
if err := validatePublish(cfg.Publish, cfg.Scriptorium, cfg.Notarius); err != nil {
return err
}
if err := validateWhisperX(cfg.WhisperX); err != nil {
return err
}
if err := validateSeriatim(cfg.Seriatim); err != nil {
return err
}
if err := validateAudita(cfg.Audita); err != nil {
return err
}
if err := validateNormalize(cfg.Normalize); err != nil {
return err
}
if err := validateTrim(cfg.Trim); err != nil {
return err
}
if err := validateRender(cfg.Render); err != nil {
return err
}
if err := validateScriptorium(cfg.Scriptorium, cfg.Notarius); err != nil {
return err
}
if err := validateNotification(cfg.Notification); err != nil {
return err
}
return nil
}