package runtime import ( "context" "errors" "fmt" "net/url" "strings" "sync" "time" "browser.local/run/protocol" ) type RemoteAdapterRequest struct { JobID string ServerInstanceID string AdapterKey string AdapterKind string TargetKey string Capability string InputRef string } type RemoteAdapterOutcome struct { Message string ResultRef string Retryable bool } type RemoteAdapter interface { Execute(context.Context, RemoteAdapterRequest) (RemoteAdapterOutcome, error) } type RemoteAdapterFunc func(context.Context, RemoteAdapterRequest) (RemoteAdapterOutcome, error) func (fn RemoteAdapterFunc) Execute(ctx context.Context, request RemoteAdapterRequest) (RemoteAdapterOutcome, error) { return fn(ctx, request) } type RemoteAdapterRegistry struct { mu sync.RWMutex adapters map[string]RemoteAdapter } func NewRemoteAdapterRegistry() *RemoteAdapterRegistry { registry := &RemoteAdapterRegistry{adapters: map[string]RemoteAdapter{}} for _, kind := range []string{"ftp", "rsync", "run-file", "run-process", "database", "log-transfer"} { registry.adapters[kind] = declaredRemoteAdapter{kind: kind} } return registry } func (registry *RemoteAdapterRegistry) Register(kind string, adapter RemoteAdapter) error { kind = strings.TrimSpace(kind) if kind == "" || adapter == nil { return fmt.Errorf("remote adapter kind and implementation are required") } registry.mu.Lock() defer registry.mu.Unlock() registry.adapters[kind] = adapter return nil } func (registry *RemoteAdapterRegistry) adapter(kind string) (RemoteAdapter, bool) { registry.mu.RLock() defer registry.mu.RUnlock() adapter, exists := registry.adapters[kind] return adapter, exists } func ExecuteRemoteAccessJob(ctx context.Context, assignment protocol.RunJobAssignment) LifecycleExecutionResult { return ExecuteRemoteAccessJobWithRegistry(ctx, assignment, NewRemoteAdapterRegistry()) } func ExecuteRemoteAccessJobWithRegistry(ctx context.Context, assignment protocol.RunJobAssignment, registry *RemoteAdapterRegistry) LifecycleExecutionResult { if assignment.ExecutionInput.SourceRCON != nil { return lifecycleFailure("source_rcon_requires_worker_transport", "Source RCON commands require the one-time worker transport") } if err := protocol.ValidateRunJobAssignment(assignment); err != nil { if strings.Contains(err.Error(), "remoteAdapterKey") { return lifecycleFailure("unsafe_remote_adapter_target", "remote adapter key must be an approved logical key") } return lifecycleFailure("unsafe_remote_access_job", err.Error()) } if !isSupportedRemoteCapability(assignment.Capability) { return lifecycleFailure("unsupported_remote_access_capability", "unsupported remote access capability") } if registry == nil { return lifecycleFailure("remote_adapter_unavailable", "remote adapter registry is unavailable") } adapterKind := strings.TrimSpace(assignment.ExecutionInput.RemoteAdapterKind) if adapterKind == "" { adapterKind = adapterKindForCapability(assignment.Capability) } adapterKey := strings.TrimSpace(assignment.ExecutionInput.RemoteAdapterKey) if adapterKey == "" { adapterKey = assignment.TargetKey } if !protocol.ValidLogicalFileKey(adapterKey) || !protocol.ValidLogicalFileKey(assignment.TargetKey) { return lifecycleFailure("unsafe_remote_adapter_target", "remote adapter and target must use approved logical keys") } if !adapterKindAllowsCapability(adapterKind, assignment.Capability) { return lifecycleFailure("remote_adapter_capability_mismatch", "remote adapter kind does not allow requested capability") } adapter, exists := registry.adapter(adapterKind) if !exists { return lifecycleFailure("remote_adapter_unavailable", "declared remote adapter is unavailable") } executionCtx := ctx cancel := func() {} if timeout := assignment.ExecutionInput.TimeoutSeconds; timeout > 0 { if timeout > 300 { return lifecycleFailure("unsafe_remote_adapter_timeout", "remote adapter timeout exceeds bound") } executionCtx, cancel = context.WithTimeout(ctx, time.Duration(timeout)*time.Second) } defer cancel() request := RemoteAdapterRequest{JobID: assignment.JobID, ServerInstanceID: assignment.ServerInstanceID, AdapterKey: adapterKey, AdapterKind: adapterKind, TargetKey: assignment.TargetKey, Capability: assignment.Capability, InputRef: assignment.InputRef} outcome, err := adapter.Execute(executionCtx, request) if err != nil { if errors.Is(err, context.DeadlineExceeded) || errors.Is(executionCtx.Err(), context.DeadlineExceeded) { return LifecycleExecutionResult{State: lifecycleResultStateFailed, Progress: protocol.RunJobProgressReport{Percent: 100, Message: "remote adapter timed out"}, Message: "remote adapter timed out", ErrorCode: "remote_adapter_timeout", Retryable: true} } if errors.Is(err, context.Canceled) || errors.Is(executionCtx.Err(), context.Canceled) { return LifecycleExecutionResult{State: lifecycleResultStateCancelled, Progress: protocol.RunJobProgressReport{Percent: 100, Message: "remote adapter cancelled"}, Message: "remote adapter cancelled", ErrorCode: "remote_adapter_cancelled"} } return LifecycleExecutionResult{State: lifecycleResultStateFailed, Progress: protocol.RunJobProgressReport{Percent: 100, Message: "remote adapter failed"}, Message: "remote adapter failed", ErrorCode: "remote_adapter_failed", Retryable: outcome.Retryable} } if err := executionCtx.Err(); err != nil { if errors.Is(err, context.DeadlineExceeded) { return LifecycleExecutionResult{State: lifecycleResultStateFailed, Progress: protocol.RunJobProgressReport{Percent: 100, Message: "remote adapter timed out"}, Message: "remote adapter timed out", ErrorCode: "remote_adapter_timeout", Retryable: true} } return LifecycleExecutionResult{State: lifecycleResultStateCancelled, Progress: protocol.RunJobProgressReport{Percent: 100, Message: "remote adapter cancelled"}, Message: "remote adapter cancelled", ErrorCode: "remote_adapter_cancelled"} } resultRef := outcome.ResultRef if resultRef == "" { resultRef = fmt.Sprintf("artifact://jobs/%s/remote-access-result", url.PathEscape(assignment.JobID)) } message := strings.TrimSpace(outcome.Message) if message == "" { message = fmt.Sprintf("%s completed through declared %s adapter", assignment.Capability, adapterKind) } return LifecycleExecutionResult{State: lifecycleResultStateSucceeded, Progress: protocol.RunJobProgressReport{Percent: 100, Message: "remote adapter completed"}, ResultRef: resultRef, Message: message} } type declaredRemoteAdapter struct { kind string } func (adapter declaredRemoteAdapter) Execute(ctx context.Context, request RemoteAdapterRequest) (RemoteAdapterOutcome, error) { select { case <-ctx.Done(): return RemoteAdapterOutcome{}, ctx.Err() default: } if request.AdapterKind != adapter.kind || request.ServerInstanceID == "" || request.JobID == "" { return RemoteAdapterOutcome{}, fmt.Errorf("remote adapter request identity mismatch") } return RemoteAdapterOutcome{Message: fmt.Sprintf("%s completed through bounded remote access envelope", request.Capability), ResultRef: fmt.Sprintf("artifact://jobs/%s/remote-access-result", url.PathEscape(request.JobID))}, nil } func adapterKindForCapability(capability string) string { switch capability { case protocol.RunCapabilityRemoteFTPRead, protocol.RunCapabilityRemoteFTPWrite: return "ftp" case protocol.RunCapabilityRemoteRsyncRead, protocol.RunCapabilityRemoteRsyncWrite: return "rsync" case protocol.RunCapabilityRemoteRunFilesRead, protocol.RunCapabilityRemoteRunFilesWrite: return "run-file" case protocol.RunCapabilityRemoteRunProcessStart, protocol.RunCapabilityRemoteRunProcessStop: return "run-process" case protocol.RunCapabilityRemoteRunDBMySQLQuery, protocol.RunCapabilityRemoteRunDBSQLiteQuery: return "database" case protocol.RunCapabilityRemoteRunRCONCommand: return "rcon" case protocol.RunCapabilityRemoteRunLogsTransfer: return "log-transfer" default: return "" } } func adapterKindAllowsCapability(kind string, capability string) bool { return kind != "" && kind == adapterKindForCapability(capability) }