Separate final configuration record validation

This commit is contained in:
2026-11-05 14:22:34 +00:00
parent 68668cee56
commit 2e2fba4993
2 changed files with 103 additions and 89 deletions

View File

@@ -419,101 +419,110 @@ func validateEffective(config *document, validation *configkit.Validation) {
}
for _, resources := range sets {
for index, backend := range resources.backends {
base := resources.bases.backends.Index(index)
validateBackendEndpoints(backend, base, validation)
if !domain.IsValidLocalResourceKey(backend.ID) {
validation.Error(base.Key("id"), "backend ID must be a nonblank local key without a slash")
}
if backend.Endpoint == nil || *backend.Endpoint == "" {
validation.Error(base.Key("endpoint"), "endpoint is required")
}
if backend.APIKeyEnv != nil && *backend.APIKeyEnv != "" && !envName.MatchString(*backend.APIKeyEnv) {
validation.Error(base.Key("api_key_env"), "environment variable name is invalid")
}
if backend.ConcurrencyLimit != nil && *backend.ConcurrencyLimit < 0 {
validation.Error(base.Key("concurrency_limit"), "concurrency limit must not be negative")
}
if backend.QueueCapacity != nil {
if *backend.QueueCapacity < 0 {
validation.Error(base.Key("queue_capacity"), "queue capacity must not be negative")
}
if backend.ConcurrencyLimit == nil || *backend.ConcurrencyLimit <= 0 {
validation.Error(base.Key("queue_capacity"), "queue capacity requires a positive concurrency limit")
} else if *backend.QueueCapacity > int(^uint(0)>>1)-*backend.ConcurrencyLimit {
validation.Error(base.Key("queue_capacity"), "total capacity overflows int")
}
}
validateExtraParams(backend.ExtraParams, base.Key("extra_params"), true, validation)
if smokeTests := backend.SmokeTests; smokeTests != nil {
smokePath := base.Key("smoke_tests")
if smokeTests.DefaultProfile != nil {
if strings.TrimSpace(*smokeTests.DefaultProfile) == "" {
validation.Error(smokePath.Key("default_profile"), "default profile must not be blank")
} else if !domain.IsValidResourceID(*smokeTests.DefaultProfile) {
validation.Error(smokePath.Key("default_profile"), "default profile reference is malformed")
}
}
if authentication := smokeTests.Authentication; authentication != nil {
kindPath := smokePath.Key("authentication").Key("kind")
if authentication.Kind == nil {
validation.Error(kindPath, "authentication kind is required")
} else if *authentication.Kind != "none" && *authentication.Kind != "openrouter_key" {
validation.Error(kindPath, "authentication kind must be none or openrouter_key")
}
}
}
validateBackendRecord(backend, resources.bases.backends.Index(index), validation)
}
for index, profile := range resources.profiles {
base := resources.bases.profiles.Index(index)
if profile.Endpoint != nil && *profile.Endpoint != "" {
if _, err := domain.NormalizeOpenAICompatibleBaseEndpoint(*profile.Endpoint); err != nil {
validation.Error(base.Key("endpoint"), err.Error())
}
}
if !domain.IsValidLocalResourceKey(profile.ID) {
validation.Error(base.Key("id"), "profile ID must be a nonblank local key without a slash")
}
if profile.Backend != nil && *profile.Backend != "" {
if !domain.IsValidResourceID(*profile.Backend) {
validation.Error(base.Key("backend"), "backend reference is malformed")
} else if _, exists := backendIDs[*profile.Backend]; !exists {
validation.Error(base.Key("backend"), "backend is not defined")
}
}
if profile.Model != nil && *profile.Model != "" && strings.TrimSpace(*profile.Model) == "" {
validation.Error(base.Key("model"), "model must not be blank")
}
if profile.Temperature != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{Temperature: *profile.Temperature}); err != nil {
validation.Error(base.Key("temperature"), err.Error())
}
}
if profile.TopP != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{TopP: *profile.TopP}); err != nil {
validation.Error(base.Key("top_p"), err.Error())
}
}
if profile.MaxTokens != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{MaxTokens: *profile.MaxTokens}); err != nil {
validation.Error(base.Key("max_tokens"), err.Error())
}
}
if profile.TimeoutSeconds != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{TimeoutSeconds: *profile.TimeoutSeconds}); err != nil {
validation.Error(base.Key("timeout_seconds"), err.Error())
}
}
validateExtraParams(profile.ExtraParams, base.Key("extra_params"), false, validation)
validateProfileRecord(profile, resources.bases.profiles.Index(index), backendIDs, validation)
}
for index, prompt := range resources.prompts {
base := resources.bases.prompts.Index(index)
if !domain.IsValidLocalResourceKey(prompt.ID) {
validation.Error(base.Key("id"), "prompt ID must be a nonblank local key without a slash")
}
if prompt.DefaultProfile != nil && *prompt.DefaultProfile != "" && !domain.IsValidResourceID(*prompt.DefaultProfile) {
validation.Error(base.Key("default_profile"), "default profile reference is malformed")
validatePromptRecord(prompt, resources.bases.prompts.Index(index), validation)
}
}
}
func validateBackendRecord(backend backendConfig, base configkit.Path, validation *configkit.Validation) {
validateBackendEndpoints(backend, base, validation)
if !domain.IsValidLocalResourceKey(backend.ID) {
validation.Error(base.Key("id"), "backend ID must be a nonblank local key without a slash")
}
if backend.Endpoint == nil || *backend.Endpoint == "" {
validation.Error(base.Key("endpoint"), "endpoint is required")
}
if backend.APIKeyEnv != nil && *backend.APIKeyEnv != "" && !envName.MatchString(*backend.APIKeyEnv) {
validation.Error(base.Key("api_key_env"), "environment variable name is invalid")
}
if backend.ConcurrencyLimit != nil && *backend.ConcurrencyLimit < 0 {
validation.Error(base.Key("concurrency_limit"), "concurrency limit must not be negative")
}
if backend.QueueCapacity != nil {
if *backend.QueueCapacity < 0 {
validation.Error(base.Key("queue_capacity"), "queue capacity must not be negative")
}
if backend.ConcurrencyLimit == nil || *backend.ConcurrencyLimit <= 0 {
validation.Error(base.Key("queue_capacity"), "queue capacity requires a positive concurrency limit")
} else if *backend.QueueCapacity > int(^uint(0)>>1)-*backend.ConcurrencyLimit {
validation.Error(base.Key("queue_capacity"), "total capacity overflows int")
}
}
validateExtraParams(backend.ExtraParams, base.Key("extra_params"), true, validation)
if smokeTests := backend.SmokeTests; smokeTests != nil {
smokePath := base.Key("smoke_tests")
if smokeTests.DefaultProfile != nil {
if strings.TrimSpace(*smokeTests.DefaultProfile) == "" {
validation.Error(smokePath.Key("default_profile"), "default profile must not be blank")
} else if !domain.IsValidResourceID(*smokeTests.DefaultProfile) {
validation.Error(smokePath.Key("default_profile"), "default profile reference is malformed")
}
}
if authentication := smokeTests.Authentication; authentication != nil {
kindPath := smokePath.Key("authentication").Key("kind")
if authentication.Kind == nil {
validation.Error(kindPath, "authentication kind is required")
} else if *authentication.Kind != "none" && *authentication.Kind != "openrouter_key" {
validation.Error(kindPath, "authentication kind must be none or openrouter_key")
}
}
}
}
func validateProfileRecord(profile profileConfig, base configkit.Path, backendIDs map[string]struct{}, validation *configkit.Validation) {
if profile.Endpoint != nil && *profile.Endpoint != "" {
if _, err := domain.NormalizeOpenAICompatibleBaseEndpoint(*profile.Endpoint); err != nil {
validation.Error(base.Key("endpoint"), err.Error())
}
}
if !domain.IsValidLocalResourceKey(profile.ID) {
validation.Error(base.Key("id"), "profile ID must be a nonblank local key without a slash")
}
if profile.Backend != nil && *profile.Backend != "" {
if !domain.IsValidResourceID(*profile.Backend) {
validation.Error(base.Key("backend"), "backend reference is malformed")
} else if _, exists := backendIDs[*profile.Backend]; !exists {
validation.Error(base.Key("backend"), "backend is not defined")
}
}
if profile.Model != nil && *profile.Model != "" && strings.TrimSpace(*profile.Model) == "" {
validation.Error(base.Key("model"), "model must not be blank")
}
if profile.Temperature != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{Temperature: *profile.Temperature}); err != nil {
validation.Error(base.Key("temperature"), err.Error())
}
}
if profile.TopP != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{TopP: *profile.TopP}); err != nil {
validation.Error(base.Key("top_p"), err.Error())
}
}
if profile.MaxTokens != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{MaxTokens: *profile.MaxTokens}); err != nil {
validation.Error(base.Key("max_tokens"), err.Error())
}
}
if profile.TimeoutSeconds != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{TimeoutSeconds: *profile.TimeoutSeconds}); err != nil {
validation.Error(base.Key("timeout_seconds"), err.Error())
}
}
validateExtraParams(profile.ExtraParams, base.Key("extra_params"), false, validation)
}
func validatePromptRecord(prompt promptConfig, base configkit.Path, validation *configkit.Validation) {
if !domain.IsValidLocalResourceKey(prompt.ID) {
validation.Error(base.Key("id"), "prompt ID must be a nonblank local key without a slash")
}
if prompt.DefaultProfile != nil && *prompt.DefaultProfile != "" && !domain.IsValidResourceID(*prompt.DefaultProfile) {
validation.Error(base.Key("default_profile"), "default profile reference is malformed")
}
}