Files
browser/run/protocol/job_validation.go
T
2026-07-11 14:56:10 +08:00

59 lines
2.1 KiB
Go

package protocol
import "strings"
const maxRunLogicalFileKeyLength = 160
func ValidateRunJobAssignment(assignment RunJobAssignment) error {
if assignment.JobID == "" || assignment.RunEndpointID == "" || assignment.Capability == "" {
return ValidationError("jobId, runEndpointId, and capability are required")
}
switch assignment.Capability {
case RunCapabilityConfigWrite, RunCapabilityFilesRead, RunCapabilityFilesWrite:
if assignment.ServerInstanceID == "" {
return ValidationError("serverInstanceId is required for scoped file jobs")
}
if !ValidLogicalFileKey(assignment.TargetKey) {
return ValidationError("targetKey is not allowed")
}
}
switch assignment.Capability {
case RunCapabilityConfigWrite, RunCapabilityFilesWrite:
if !ValidScopedInputRef(assignment.InputRef) {
return ValidationError("inputRef is not allowed")
}
}
return nil
}
type ValidationError string
func (err ValidationError) Error() string { return string(err) }
func ValidLogicalFileKey(key string) bool {
trimmed := strings.TrimSpace(key)
if trimmed == "" || trimmed != key || len([]rune(key)) > maxRunLogicalFileKeyLength {
return false
}
lower := strings.ToLower(key)
if strings.HasPrefix(key, "/") || strings.Contains(key, "..") || strings.Contains(key, `\`) || strings.Contains(key, "://") || strings.Contains(lower, "/users/") || strings.Contains(lower, "password=") || strings.Contains(lower, "secret=") || strings.Contains(lower, "sk-") || strings.Contains(lower, "bearer ") {
return false
}
for _, char := range key {
if (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9') || char == '_' || char == '-' || char == '.' || char == '/' {
continue
}
return false
}
return true
}
func ValidScopedInputRef(ref string) bool {
trimmed := strings.TrimSpace(ref)
lower := strings.ToLower(ref)
if trimmed == "" || trimmed != ref || strings.Contains(lower, "/users/") || strings.Contains(lower, "password=") || strings.Contains(lower, "secret=") || strings.Contains(lower, "sk-") || strings.Contains(lower, "bearer ") {
return false
}
return strings.HasPrefix(ref, "input://") || strings.HasPrefix(ref, "artifact://")
}