feat(scum): add file config workbench
This commit is contained in:
@@ -146,6 +146,7 @@ func ValidateGamePlugin(plugin domain.GamePlugin) error {
|
||||
violations = append(violations, validateDeclaredPluginPermissions(plugin.DeclaredPermissions)...)
|
||||
violations = append(violations, validateBridgeActions("bridgeActions", plugin.BridgeActions)...)
|
||||
violations = append(violations, validatePluginPages(plugin.Pages)...)
|
||||
violations = append(violations, validatePluginFileWorkspace("fileWorkspace", plugin.FileWorkspace)...)
|
||||
violations = append(violations, duplicateViolations("tags", plugin.Tags)...)
|
||||
violations = append(violations, validateAIPurposes(plugin.AIPurposes)...)
|
||||
violations = append(violations, validateProductionLifecycle("productionLifecycle", plugin.ProductionLifecycle, true)...)
|
||||
@@ -207,6 +208,7 @@ func ValidateGamePluginManifestRegistration(registration domain.GamePluginManife
|
||||
violations = append(violations, validateBridgeActions("manifest.bridge.actions", manifest.Bridge.Actions)...)
|
||||
violations = append(violations, validateLifecycleActions(manifest.Actions)...)
|
||||
violations = append(violations, validatePluginPages(manifest.Pages)...)
|
||||
violations = append(violations, validatePluginFileWorkspace("manifest.fileWorkspace", manifest.FileWorkspace)...)
|
||||
violations = append(violations, duplicateViolations("manifest.tags", manifest.Tags)...)
|
||||
violations = append(violations, validateAIPurposes(manifest.AI.Purposes)...)
|
||||
violations = append(violations, validateProductionLifecycle("manifest.productionLifecycle", manifest.ProductionLifecycle, true)...)
|
||||
@@ -1400,6 +1402,46 @@ func validatePluginPages(pages []domain.GamePluginPage) []string {
|
||||
return violations
|
||||
}
|
||||
|
||||
func validatePluginFileWorkspace(prefix string, workspace domain.PluginFileWorkspace) []string {
|
||||
if workspace.DefaultDirectoryKey == "" && len(workspace.Directories) == 0 && len(workspace.Files) == 0 && len(workspace.ConfigFields) == 0 {
|
||||
return nil
|
||||
}
|
||||
var violations []string
|
||||
directories := map[string]bool{}
|
||||
files := map[string]domain.PluginLogicalFile{}
|
||||
for i, item := range workspace.Directories {
|
||||
field := fmt.Sprintf("%s.directories[%d]", prefix, i)
|
||||
if !validDistributionLogicalKey(item.Key) || item.Label == "" || !oneOf(item.Scope, "config", "logs") {
|
||||
violations = append(violations, field+" is invalid")
|
||||
}
|
||||
if directories[item.Key] {
|
||||
violations = append(violations, field+".key duplicates another directory")
|
||||
}
|
||||
directories[item.Key] = true
|
||||
}
|
||||
if !directories[workspace.DefaultDirectoryKey] {
|
||||
violations = append(violations, prefix+".defaultDirectoryKey must reference a declared directory")
|
||||
}
|
||||
for i, item := range workspace.Files {
|
||||
field := fmt.Sprintf("%s.files[%d]", prefix, i)
|
||||
if !validDistributionLogicalKey(item.Key) || !directories[item.DirectoryKey] || item.Label == "" || !oneOf(item.Kind, "config", "log") || (item.Kind == "log" && item.StreamKey == "") {
|
||||
violations = append(violations, field+" is invalid")
|
||||
}
|
||||
if _, exists := files[item.Key]; exists {
|
||||
violations = append(violations, field+".key duplicates another file")
|
||||
}
|
||||
files[item.Key] = item
|
||||
}
|
||||
for i, item := range workspace.ConfigFields {
|
||||
field := fmt.Sprintf("%s.configFields[%d]", prefix, i)
|
||||
file, exists := files[item.FileKey]
|
||||
if !validDistributionLogicalKey(item.Key) || !exists || file.Kind != "config" || !file.Editable || item.ConfigKey == "" || item.Label == "" || item.Description == "" || !oneOf(item.Control, "text", "number", "boolean", "port") || !oneOf(item.RestartImpact, "none", "restart-required") || (item.Minimum > 0 && item.Maximum > 0 && item.Minimum > item.Maximum) {
|
||||
violations = append(violations, field+" is invalid")
|
||||
}
|
||||
}
|
||||
return violations
|
||||
}
|
||||
|
||||
func validateBridgeActions(field string, actions []string) []string {
|
||||
var violations []string
|
||||
for i, action := range actions {
|
||||
|
||||
@@ -35,6 +35,28 @@ func TestValidateGamePluginManifestRegistration(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateGamePluginManifestRegistrationValidatesLogicalFileWorkspace(t *testing.T) {
|
||||
registration := validGamePluginManifestRegistration()
|
||||
registration.Manifest.FileWorkspace = domain.PluginFileWorkspace{
|
||||
DefaultDirectoryKey: "config",
|
||||
Directories: []domain.PluginLogicalDirectory{{Key: "config", Label: "配置", Scope: "config"}},
|
||||
Files: []domain.PluginLogicalFile{{Key: "settings", DirectoryKey: "config", Label: "Settings.ini", Kind: "config", Editable: true}},
|
||||
ConfigFields: []domain.PluginConfigField{{Key: "max-players", FileKey: "settings", ConfigKey: "MaxPlayers", Label: "最大玩家数", Description: "玩家上限", Control: "number", Minimum: 1, Maximum: 128, RestartImpact: "restart-required"}},
|
||||
}
|
||||
if err := ValidateGamePluginManifestRegistration(registration); err != nil {
|
||||
t.Fatalf("expected safe logical file workspace: %v", err)
|
||||
}
|
||||
registration.Manifest.FileWorkspace.Files[0].DirectoryKey = "../host"
|
||||
if err := ValidateGamePluginManifestRegistration(registration); err == nil {
|
||||
t.Fatal("expected unsafe logical directory reference to fail")
|
||||
}
|
||||
registration.Manifest.FileWorkspace.Files[0].DirectoryKey = "config"
|
||||
registration.Manifest.FileWorkspace.Files[0].Editable = false
|
||||
if err := ValidateGamePluginManifestRegistration(registration); err == nil {
|
||||
t.Fatal("expected a configuration field without an editable owning file to fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateGamePluginManifestRegistrationRejectsUnsafeRequests(t *testing.T) {
|
||||
registration := validGamePluginManifestRegistration()
|
||||
registration.Manifest.Description = "requires direct run socket and raw AI key material"
|
||||
|
||||
Reference in New Issue
Block a user