功能修改

This commit is contained in:
npc0-hue
2026-07-20 16:42:33 +08:00
parent 48b8ad8d6c
commit a0e69417db
224 changed files with 22015 additions and 884 deletions
+99
View File
@@ -11,6 +11,11 @@ import (
"browser.local/platform/domain"
)
var (
runtimeLogEventSchemaRefPattern = regexp.MustCompile(`^[A-Za-z0-9_./-]+\.json$`)
runtimeLogEventTypePattern = regexp.MustCompile(`^[a-z0-9][a-z0-9._-]{0,119}$`)
)
func ValidateGamePluginRuntimeProfiles(profiles domain.GamePluginRuntimeProfiles) error {
profiles = domain.CopyGamePluginRuntimeProfiles(profiles)
var violations []string
@@ -21,6 +26,9 @@ func ValidateGamePluginRuntimeProfiles(profiles domain.GamePluginRuntimeProfiles
dependencyKeys := map[string]struct{}{}
installPlanKeys := map[string]struct{}{}
logSourceKeys := map[string]struct{}{}
logSourceRetentions := map[string]int{}
logEventKeys := map[string]struct{}{}
logEventTypes := map[string]struct{}{}
for i, probe := range profiles.Discovery {
prefix := fmt.Sprintf("runtimeProfiles.discovery[%d]", i)
@@ -138,6 +146,9 @@ func ValidateGamePluginRuntimeProfiles(profiles domain.GamePluginRuntimeProfiles
prefix := fmt.Sprintf("runtimeProfiles.logSources[%d]", i)
violations = append(violations, validateProfileKey(prefix+".key", source.Key)...)
violations = append(violations, recordRuntimeProfileKey(logSourceKeys, prefix+".key", source.Key)...)
if source.Key != "" {
logSourceRetentions[source.Key] = source.RetentionDays
}
if !oneOf(source.Kind, "process.stdout", "process.stderr", "file.tail", "ftp.poll", "sql.query", "client-manager") {
violations = append(violations, prefix+".kind is invalid")
}
@@ -152,6 +163,44 @@ func ValidateGamePluginRuntimeProfiles(profiles domain.GamePluginRuntimeProfiles
violations = append(violations, prefix+".retentionDays is invalid")
}
}
if len(profiles.LogEvents) > 128 {
violations = append(violations, "runtimeProfiles.logEvents must not exceed 128")
}
for i, event := range profiles.LogEvents {
prefix := fmt.Sprintf("runtimeProfiles.logEvents[%d]", i)
violations = append(violations, validateProfileKey(prefix+".key", event.Key)...)
violations = append(violations, recordRuntimeProfileKey(logEventKeys, prefix+".key", event.Key)...)
if strings.TrimSpace(event.Title) == "" || len([]rune(event.Title)) > 80 {
violations = append(violations, prefix+".title is invalid")
}
violations = append(violations, validateSafeRuntimeValue(prefix+".title", event.Title)...)
violations = append(violations, validateProfileKey(prefix+".sourceKey", event.SourceKey)...)
if _, exists := logSourceKeys[event.SourceKey]; !exists {
violations = append(violations, prefix+".sourceKey must reference a declared runtime log source")
}
if !runtimeLogEventTypePattern.MatchString(event.EventType) {
violations = append(violations, prefix+".eventType is invalid")
}
violations = append(violations, recordRuntimeProfileKey(logEventTypes, prefix+".eventType", event.EventType)...)
if hasUnsafeRuntimeLogEventSemantics(event.EventType) {
violations = append(violations, prefix+".eventType contains unsafe operation semantics")
}
if !validPluginPermission(event.Permission) {
violations = append(violations, prefix+".permission is not allowed")
}
if len(event.SchemaRef) > 240 || !runtimeLogEventSchemaRefPattern.MatchString(event.SchemaRef) || !safeRelativeJSONRef(event.SchemaRef) {
violations = append(violations, prefix+".schemaRef must be a bounded safe relative JSON reference")
}
if event.RetentionDays < 1 || event.RetentionDays > 365 {
violations = append(violations, prefix+".retentionDays is invalid")
}
if sourceRetention, exists := logSourceRetentions[event.SourceKey]; exists && sourceRetention > 0 && event.RetentionDays > sourceRetention {
violations = append(violations, prefix+".retentionDays must not exceed the source retention")
}
if !oneOf(string(event.Severity), string(domain.RuntimeLogEventSeverityInfo), string(domain.RuntimeLogEventSeverityNotice), string(domain.RuntimeLogEventSeverityWarning), string(domain.RuntimeLogEventSeverityCritical)) {
violations = append(violations, prefix+".severity is invalid")
}
}
for i, transport := range profiles.TransportProfiles {
prefix := fmt.Sprintf("runtimeProfiles.transportProfiles[%d]", i)
violations = append(violations, validateProfileKey(prefix+".key", transport.Key)...)
@@ -346,6 +395,42 @@ func validateSafeRuntimeValue(field, value string) []string {
return nil
}
func hasUnsafeRuntimeLogEventSemantics(eventType string) bool {
lowered := strings.ToLower(strings.TrimSpace(eventType))
tokens := strings.FieldsFunc(lowered, func(char rune) bool {
return char == '.' || char == '_' || char == '-' || char == '/'
})
unsafeTokens := map[string]struct{}{
"apikey": {}, "credential": {}, "credentials": {}, "eval": {}, "exec": {},
"execute": {}, "password": {}, "powershell": {}, "script": {}, "secret": {},
"shell": {}, "socket": {}, "terminal": {}, "token": {},
}
for _, token := range tokens {
if _, unsafe := unsafeTokens[token]; unsafe {
return true
}
}
for index := 0; index+1 < len(tokens); index++ {
pair := tokens[index] + "." + tokens[index+1]
switch pair {
case "absolute.path", "access.key", "api.key", "component.key", "database.query", "direct.socket", "file.path", "host.path", "private.key", "raw.path", "run.direct", "run.socket", "unix.socket":
return true
}
}
tokenSet := make(map[string]struct{}, len(tokens))
for _, token := range tokens {
tokenSet[token] = struct{}{}
}
if _, hasSQL := tokenSet["sql"]; hasSQL {
for _, token := range []string{"query", "statement", "raw"} {
if _, unsafe := tokenSet[token]; unsafe {
return true
}
}
}
return false
}
func recordRuntimeProfileKey(seen map[string]struct{}, field, key string) []string {
if key == "" {
return nil
@@ -382,6 +467,20 @@ func validateRuntimeProfileCapabilityDeclarations(profiles domain.GamePluginRunt
return violations
}
func validateRuntimeLogEventPermissionDeclarations(field string, profiles domain.GamePluginRuntimeProfiles, declared []string) []string {
declaredSet := make(map[string]struct{}, len(declared))
for _, permission := range declared {
declaredSet[permission] = struct{}{}
}
var violations []string
for i, event := range profiles.LogEvents {
if _, exists := declaredSet[event.Permission]; !exists {
violations = append(violations, fmt.Sprintf("%s[%d].permission must be declared by the plugin", field, i))
}
}
return violations
}
func validateLifecycleActionsOptional(actions domain.PluginLifecycleActions) []string {
var violations []string
for field, value := range map[string]string{"install": actions.Install, "start": actions.Start, "stop": actions.Stop, "restart": actions.Restart, "status": actions.Status} {