package protocol import "strings" type RunAutonomousLifecyclePlan struct { SchemaVersion string `json:"schemaVersion"` ServerInstanceID string `json:"serverInstanceId"` PluginID string `json:"pluginId"` PluginVersion string `json:"pluginVersion"` RunEndpointID string `json:"runEndpointId"` ProfileKey string `json:"profileKey,omitempty"` TargetOS string `json:"targetOs"` TargetArch string `json:"targetArch"` TargetRelease string `json:"targetRelease"` DeploymentRevision int `json:"deploymentRevision,omitempty"` Bootstrap *RunAutonomousLifecycleAction `json:"bootstrap,omitempty"` Actions []RunAutonomousLifecycleAction `json:"actions,omitempty"` DependencyProbes []DependencyProbe `json:"dependencyProbes,omitempty"` InstallPlans []DependencyInstallPlan `json:"installPlans,omitempty"` LogSources []RuntimeLogSourcePlan `json:"logSources,omitempty"` DLLExtensions []RuntimeDLLExtensionPlan `json:"dllExtensions,omitempty"` DataTargets []RunAutonomousDataTarget `json:"dataTargets,omitempty"` RuntimeBindings map[string]string `json:"runtimeBindings,omitempty"` Deployment *RunAutonomousDeployment `json:"deployment,omitempty"` } type RunAutonomousLifecycleAction struct { Action string `json:"action"` Operation string `json:"operation"` Capability string `json:"capability"` TargetKey string `json:"targetKey"` } type RunAutonomousDeployment struct { SchemaVersion string `json:"schemaVersion"` Mode string `json:"mode"` ProfileKey string `json:"profileKey,omitempty"` RuntimeBindings map[string]string `json:"runtimeBindings,omitempty"` CreateInputs map[string]string `json:"createInputs,omitempty"` ServerRoot string `json:"serverRoot,omitempty"` WorkingDirectory string `json:"workingDirectory,omitempty"` InstallCommand string `json:"installCommand,omitempty"` StartCommand string `json:"startCommand,omitempty"` StopCommand string `json:"stopCommand,omitempty"` StatusCommand string `json:"statusCommand,omitempty"` Shell string `json:"shell,omitempty"` Revision int `json:"revision,omitempty"` } type RunAutonomousDataTarget struct { Key string `json:"key"` Kind string `json:"kind"` TransportKey string `json:"transportKey"` SourceRootKey string `json:"sourceRootKey"` SourcePath string `json:"sourcePath"` WorkspaceKey string `json:"workspaceKey"` RefreshPolicy string `json:"refreshPolicy"` MaxBytes int64 `json:"maxBytes,omitempty"` Platforms []string `json:"platforms,omitempty"` } const maxAutonomousDataTargetBytes = int64(1024 * 1024 * 1024) func ValidateRunAutonomousLifecyclePlan(plan RunAutonomousLifecyclePlan) error { if plan.SchemaVersion != "1" { return ValidationError("autonomous lifecycle plan schema is unsupported") } if !ValidLogicalFileKey(plan.ServerInstanceID) || !ValidLogicalFileKey(plan.RunEndpointID) || !validAutonomousPluginID(plan.PluginID) { return ValidationError("autonomous lifecycle plan identity is invalid") } if plan.ProfileKey != "" && !ValidLogicalFileKey(plan.ProfileKey) { return ValidationError("autonomous lifecycle profile key is invalid") } if !validAutonomousTarget(plan.TargetOS, plan.TargetArch) { return ValidationError("autonomous lifecycle target platform is invalid") } if plan.TargetRelease != "" && !validAutonomousToken(plan.TargetRelease, 240) { return ValidationError("autonomous lifecycle target release is invalid") } if plan.PluginVersion != "" && !validAutonomousToken(plan.PluginVersion, 120) { return ValidationError("autonomous lifecycle plugin version is invalid") } if plan.Bootstrap != nil { if err := validateAutonomousLifecycleAction(*plan.Bootstrap); err != nil { return err } if plan.Bootstrap.Capability != RunCapabilityProcessInstall && plan.Bootstrap.Capability != RunCapabilityProcessStart { return ValidationError("autonomous lifecycle bootstrap action is invalid") } } if len(plan.Actions) > 16 || len(plan.DependencyProbes) > 64 || len(plan.InstallPlans) > 64 || len(plan.LogSources) > 16 || len(plan.DLLExtensions) > 16 || len(plan.DataTargets) > 16 { return ValidationError("autonomous lifecycle plan is too large") } for _, action := range plan.Actions { if err := validateAutonomousLifecycleAction(action); err != nil { return err } } for _, probe := range plan.DependencyProbes { if !ValidLogicalFileKey(probe.Key) || !ValidLogicalFileKey(probe.TargetKey) || !validAutonomousToken(probe.Kind, 80) || probe.MinimumVersion != "" && !validAutonomousToken(probe.MinimumVersion, 80) { return ValidationError("autonomous dependency probe is invalid") } } for _, installPlan := range plan.InstallPlans { if !ValidLogicalFileKey(installPlan.Key) || len(installPlan.Steps) > 64 { return ValidationError("autonomous install plan is invalid") } for _, step := range installPlan.Steps { if !ValidLogicalFileKey(step.TargetKey) || !validAutonomousToken(step.Type, 80) || step.PackageManager != "" && !validAutonomousToken(step.PackageManager, 80) || step.PackageName != "" && !validAutonomousToken(step.PackageName, 160) || step.Version != "" && !validAutonomousToken(step.Version, 120) { return ValidationError("autonomous install step is invalid") } } } for _, source := range plan.LogSources { if err := validateRuntimeProcessLogSourcePlan(source); err != nil { return err } } seenDataTargets := map[string]struct{}{} seenWorkspaceTargets := map[string]struct{}{} for _, target := range plan.DataTargets { if err := validateAutonomousDataTarget(target); err != nil { return err } if _, exists := seenDataTargets[target.Key]; exists { return ValidationError("autonomous data target key is duplicated") } if _, exists := seenWorkspaceTargets[target.WorkspaceKey]; exists { return ValidationError("autonomous data target workspace is duplicated") } seenDataTargets[target.Key] = struct{}{} seenWorkspaceTargets[target.WorkspaceKey] = struct{}{} } if plan.Deployment != nil { if err := validateAutonomousDeployment(*plan.Deployment); err != nil { return err } } return nil } func validateAutonomousDataTarget(target RunAutonomousDataTarget) error { if !ValidLogicalFileKey(target.Key) || !ValidLogicalFileKey(target.TransportKey) || !ValidLogicalFileKey(target.SourceRootKey) || !ValidLogicalFileKey(target.SourcePath) || !ValidLogicalFileKey(target.WorkspaceKey) { return ValidationError("autonomous data target is invalid") } if target.Kind != "sqlite.snapshot" || target.RefreshPolicy != "on-demand-snapshot" || !strings.HasPrefix(target.WorkspaceKey, "databases/") { return ValidationError("autonomous data target is invalid") } if target.MaxBytes <= 0 || target.MaxBytes > maxAutonomousDataTargetBytes { return ValidationError("autonomous data target byte limit is invalid") } for _, platform := range target.Platforms { if platform != "windows" && platform != "linux" && platform != "darwin" { return ValidationError("autonomous data target platform is invalid") } } return nil } func validateAutonomousLifecycleAction(action RunAutonomousLifecycleAction) error { if !ValidLogicalFileKey(action.TargetKey) || !validAutonomousLifecycleCapability(action.Capability) || !validAutonomousLifecycleName(action.Action) || !validAutonomousLifecycleName(action.Operation) { return ValidationError("autonomous lifecycle action is invalid") } if expected := autonomousCapabilityForAction(action.Action); expected != "" && expected != action.Capability { return ValidationError("autonomous lifecycle action capability mismatch") } return nil } func autonomousCapabilityForAction(action string) string { switch action { case "create": return RunCapabilityProcessInstall case "start": return RunCapabilityProcessStart case "stop": return RunCapabilityProcessStop case "status": return RunCapabilityProcessStatus default: return "" } } func validAutonomousLifecycleCapability(capability string) bool { switch capability { case RunCapabilityProcessInstall, RunCapabilityProcessStart, RunCapabilityProcessStop, RunCapabilityProcessStatus: return true default: return false } } func validAutonomousLifecycleName(value string) bool { switch value { case "create", "install", "start", "stop", "status": return true default: return false } } func validateAutonomousDeployment(deployment RunAutonomousDeployment) error { if deployment.SchemaVersion != "1" || deployment.Mode == "" || deployment.Revision < 0 || deployment.ProfileKey != "" && !ValidLogicalFileKey(deployment.ProfileKey) { return ValidationError("autonomous deployment is invalid") } for key := range deployment.RuntimeBindings { if !ValidLogicalFileKey(key) { return ValidationError("autonomous deployment binding is invalid") } } for key := range deployment.CreateInputs { if !ValidLogicalFileKey(key) { return ValidationError("autonomous deployment input is invalid") } } return nil } func validAutonomousPluginID(value string) bool { return ValidLogicalFileKey(value) } func validAutonomousTarget(osName string, arch string) bool { switch osName { case "windows", "linux", "darwin": default: return false } switch arch { case "amd64", "arm64": return true default: return false } } func validAutonomousToken(value string, maxRunes int) bool { trimmed := strings.TrimSpace(value) if trimmed == "" || trimmed != value || len([]rune(value)) > maxRunes { return false } lower := strings.ToLower(value) if strings.Contains(value, "..") || strings.Contains(value, `\`) || strings.Contains(value, "://") || strings.Contains(lower, "/users/") || strings.Contains(lower, "password=") || strings.Contains(lower, "secret=") || strings.Contains(lower, "bearer ") || strings.Contains(lower, "sk-") { return false } for _, char := range value { if char >= 'a' && char <= 'z' || char >= 'A' && char <= 'Z' || char >= '0' && char <= '9' || char == '_' || char == '-' || char == '.' || char == '/' || char == ':' { continue } return false } return true }