mirror of
https://github.com/mudler/LocalAI.git
synced 2026-06-20 22:59:09 -04:00
feat(modeladmin): reject alias configs with invalid targets on create/edit
Validate alias targets at create/swap entry points (ImportModelEndpoint, EditYAML, PatchConfig) so a dangling, chained, or disabled alias target is rejected at save time rather than surfacing as a runtime error. Assisted-by: Claude:opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
@@ -181,6 +181,12 @@ func ImportModelEndpoint(cl *config.ModelConfigLoader, appConfig *config.Applica
|
||||
return c.JSON(http.StatusBadRequest, ModelResponse{Success: false, Error: msg})
|
||||
}
|
||||
|
||||
// Reject aliases whose target is missing, chained, or disabled so a
|
||||
// dangling alias can't be persisted and surface as a runtime error later.
|
||||
if err := cl.ValidateAliasTarget(&modelConfig); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, ModelResponse{Success: false, Error: err.Error()})
|
||||
}
|
||||
|
||||
// Create the configuration file
|
||||
configPath := filepath.Join(appConfig.SystemState.Model.ModelsPath, modelConfig.Name+".yaml")
|
||||
if err := utils.VerifyPath(modelConfig.Name+".yaml", appConfig.SystemState.Model.ModelsPath); err != nil {
|
||||
|
||||
@@ -130,6 +130,9 @@ func (s *ConfigService) PatchConfig(_ context.Context, name string, patch map[st
|
||||
}
|
||||
return nil, ErrInvalidConfig
|
||||
}
|
||||
if err := s.Loader.ValidateAliasTarget(&updated); err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrInvalidConfig, err)
|
||||
}
|
||||
if err := writeFileAtomic(configPath, yamlData, 0644); err != nil {
|
||||
return nil, fmt.Errorf("write config file: %w", err)
|
||||
}
|
||||
@@ -215,6 +218,9 @@ func (s *ConfigService) EditYAML(_ context.Context, name string, body []byte, ml
|
||||
if valid, _ := req.Validate(); !valid {
|
||||
return nil, ErrInvalidConfig
|
||||
}
|
||||
if err := s.Loader.ValidateAliasTarget(&req); err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrInvalidConfig, err)
|
||||
}
|
||||
|
||||
configPath := existing.GetModelConfigFile()
|
||||
modelsPath := s.modelsPath()
|
||||
|
||||
@@ -211,5 +211,23 @@ var _ = Describe("ConfigService", func() {
|
||||
_, err := svc.EditYAML(ctx, "alpha", nil, nil)
|
||||
Expect(err).To(MatchError(ErrEmptyBody))
|
||||
})
|
||||
|
||||
It("rejects editing a config into an alias with a missing target", func() {
|
||||
writeModelYAML(svc, dir, "base", map[string]any{"backend": "llama-cpp"})
|
||||
|
||||
body := []byte("name: base\nalias: ghost\n")
|
||||
_, err := svc.EditYAML(ctx, "base", body, nil)
|
||||
Expect(err).To(MatchError(ErrInvalidConfig))
|
||||
Expect(err.Error()).To(ContainSubstring("ghost"))
|
||||
})
|
||||
|
||||
It("accepts editing a config into an alias with a real target", func() {
|
||||
writeModelYAML(svc, dir, "base", map[string]any{"backend": "llama-cpp"})
|
||||
writeModelYAML(svc, dir, "target", map[string]any{"backend": "llama-cpp"})
|
||||
|
||||
body := []byte("name: base\nalias: target\n")
|
||||
_, err := svc.EditYAML(ctx, "base", body, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user