756 lines
26 KiB
Go
756 lines
26 KiB
Go
package supervisor
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/example/remote-access-platform/agents/rap-node-agent/internal/client"
|
|
"github.com/example/remote-access-platform/agents/rap-node-agent/internal/webingress"
|
|
)
|
|
|
|
type Supervisor interface {
|
|
Apply(ctx context.Context, desired []client.DesiredWorkload) ([]client.WorkloadStatusRequest, error)
|
|
}
|
|
|
|
type StubSupervisor struct {
|
|
Version string
|
|
WebIngressRuntimeEnabled bool
|
|
WebIngressManager *webingress.Manager
|
|
RemoteWorkspaceRealAdapter RemoteWorkspaceRealAdapterConfig
|
|
}
|
|
|
|
type RemoteWorkspaceRealAdapterConfig struct {
|
|
EnabledRequested bool
|
|
Command string
|
|
ArgsJSON string
|
|
WorkDir string
|
|
}
|
|
|
|
func (s StubSupervisor) Apply(_ context.Context, desired []client.DesiredWorkload) ([]client.WorkloadStatusRequest, error) {
|
|
statuses := make([]client.WorkloadStatusRequest, 0, len(desired))
|
|
for _, workload := range desired {
|
|
statuses = append(statuses, s.applyOne(workload))
|
|
}
|
|
return statuses, nil
|
|
}
|
|
|
|
func (s StubSupervisor) applyOne(workload client.DesiredWorkload) client.WorkloadStatusRequest {
|
|
serviceType := strings.TrimSpace(workload.ServiceType)
|
|
desiredState := strings.TrimSpace(strings.ToLower(workload.DesiredState))
|
|
if desiredState == "" {
|
|
desiredState = "disabled"
|
|
}
|
|
runtimeMode := strings.TrimSpace(strings.ToLower(workload.RuntimeMode))
|
|
if runtimeMode == "" {
|
|
runtimeMode = "native"
|
|
}
|
|
version := strings.TrimSpace(workload.Version)
|
|
if version == "" {
|
|
version = s.Version
|
|
}
|
|
payload := map[string]any{
|
|
"schema_version": "rap.node_agent.workload_supervision.v1",
|
|
"supervisor": "node-agent-local",
|
|
"desired_state": desiredState,
|
|
"service_type": serviceType,
|
|
"runtime_mode": runtimeMode,
|
|
"observed_at": time.Now().UTC().Format(time.RFC3339Nano),
|
|
}
|
|
if desiredState != "enabled" {
|
|
payload["reason"] = "desired_state_not_enabled"
|
|
if (serviceType == "public-ingress" || serviceType == "admin-ingress") && s.WebIngressManager != nil {
|
|
payload["listener_status"] = s.WebIngressManager.Stop(context.Background())
|
|
}
|
|
return client.WorkloadStatusRequest{
|
|
ReportedState: "stopped",
|
|
RuntimeMode: runtimeMode,
|
|
Version: version,
|
|
StatusPayload: payload,
|
|
}
|
|
}
|
|
if serviceType == "core-mesh" || serviceType == "fabric-listener" {
|
|
payload["reason"] = "builtin_node_agent_service_ready"
|
|
payload["execution_mode"] = "builtin"
|
|
payload["traffic"] = serviceTrafficMode(serviceType)
|
|
return client.WorkloadStatusRequest{
|
|
ReportedState: "running",
|
|
RuntimeMode: runtimeMode,
|
|
Version: version,
|
|
StatusPayload: payload,
|
|
}
|
|
}
|
|
if serviceType == "public-ingress" || serviceType == "admin-ingress" {
|
|
contract := s.webIngressContract(serviceType, workload.Config)
|
|
for key, value := range contract {
|
|
payload[key] = value
|
|
}
|
|
if contract["contract_valid"] == true {
|
|
payload["reason"] = "web_ingress_contract_ready"
|
|
payload["execution_mode"] = "contract_probe"
|
|
payload["traffic"] = "https_edge_to_fabric_service_channel"
|
|
if contract["real_listener_requested"] == true && contract["real_listener_runtime_enabled"] != true {
|
|
payload["reason"] = "web_ingress_real_listener_gate_disabled"
|
|
payload["traffic"] = "blocked"
|
|
return client.WorkloadStatusRequest{
|
|
ReportedState: "degraded",
|
|
RuntimeMode: runtimeMode,
|
|
Version: version,
|
|
StatusPayload: payload,
|
|
}
|
|
}
|
|
if contract["real_listener_start_allowed"] == true && s.WebIngressManager != nil {
|
|
listenerStatus := s.WebIngressManager.Apply(context.Background(), webIngressListenerConfig(serviceType, workload.Config))
|
|
payload["listener_status"] = listenerStatus
|
|
payload["ports_opened_by_runtime"] = listenerStatus.Running
|
|
payload["ports_opened_by_stub"] = false
|
|
if !listenerStatus.HTTPSRunning {
|
|
payload["reason"] = "web_ingress_listener_partial"
|
|
payload["traffic"] = "blocked"
|
|
return client.WorkloadStatusRequest{
|
|
ReportedState: "degraded",
|
|
RuntimeMode: runtimeMode,
|
|
Version: version,
|
|
StatusPayload: payload,
|
|
}
|
|
}
|
|
}
|
|
return client.WorkloadStatusRequest{
|
|
ReportedState: "running",
|
|
RuntimeMode: runtimeMode,
|
|
Version: version,
|
|
StatusPayload: payload,
|
|
}
|
|
}
|
|
payload["reason"] = "web_ingress_contract_invalid"
|
|
payload["traffic"] = "blocked"
|
|
return client.WorkloadStatusRequest{
|
|
ReportedState: "degraded",
|
|
RuntimeMode: runtimeMode,
|
|
Version: version,
|
|
StatusPayload: payload,
|
|
}
|
|
}
|
|
if serviceType == "synthetic.echo" && runtimeMode == "native" {
|
|
payload["reason"] = "internal_synthetic_echo_ready"
|
|
payload["execution_mode"] = "builtin"
|
|
payload["traffic"] = "test_service_only"
|
|
return client.WorkloadStatusRequest{
|
|
ReportedState: "running",
|
|
RuntimeMode: runtimeMode,
|
|
Version: version,
|
|
StatusPayload: payload,
|
|
}
|
|
}
|
|
if (serviceType == "vpn-exit" || serviceType == "ipv4-egress" || serviceType == "vpn-client" || serviceType == "ipv4-ingress") && runtimeMode == "native" {
|
|
for key, value := range vpnFabricOnlyContract(serviceType, workload.Config) {
|
|
payload[key] = value
|
|
}
|
|
payload["execution_mode"] = "contract_probe"
|
|
payload["fabric_transport"] = "quic_only"
|
|
payload["fabric_service_channel_required"] = true
|
|
payload["backend_relay_fallback"] = false
|
|
payload["compat_protocol_compatibility"] = false
|
|
payload["traffic"] = "fabric_service_channel_only"
|
|
return client.WorkloadStatusRequest{
|
|
ReportedState: "running",
|
|
RuntimeMode: runtimeMode,
|
|
Version: version,
|
|
StatusPayload: payload,
|
|
}
|
|
}
|
|
if serviceType == "rdp-worker" && runtimeMode == "native" && boolConfig(workload.Config, "adapter_contract_probe") {
|
|
payload["reason"] = "remote_workspace_adapter_contract_probe_ready"
|
|
payload["execution_mode"] = "contract_probe"
|
|
payload["service_class"] = "remote_workspace"
|
|
payload["fabric_service_channel_required"] = true
|
|
payload["backend_relay_steady_state"] = false
|
|
payload["channels"] = remoteWorkspaceAdapterChannels()
|
|
payload["frame_batch_contract"] = remoteWorkspaceFrameBatchContract()
|
|
payload["real_adapter_supervision"] = remoteWorkspaceRealAdapterSupervisionContract(s.RemoteWorkspaceRealAdapter)
|
|
payload["traffic"] = "none"
|
|
return client.WorkloadStatusRequest{
|
|
ReportedState: "running",
|
|
RuntimeMode: runtimeMode,
|
|
Version: version,
|
|
StatusPayload: payload,
|
|
}
|
|
}
|
|
if serviceType == "rdp-worker" && runtimeMode == "native" && boolConfig(workload.Config, "real_adapter_supervision") {
|
|
payload["reason"] = "remote_workspace_real_adapter_supervision_disabled"
|
|
payload["execution_mode"] = "real_adapter_supervision_disabled"
|
|
payload["service_class"] = "remote_workspace"
|
|
payload["traffic"] = "blocked"
|
|
payload["payload_traffic"] = "none"
|
|
payload["real_adapter_supervision"] = remoteWorkspaceRealAdapterSupervisionContract(s.RemoteWorkspaceRealAdapter)
|
|
return client.WorkloadStatusRequest{
|
|
ReportedState: "degraded",
|
|
RuntimeMode: runtimeMode,
|
|
Version: version,
|
|
StatusPayload: payload,
|
|
}
|
|
}
|
|
payload["reason"] = "service_runtime_not_implemented"
|
|
payload["traffic"] = "blocked"
|
|
return client.WorkloadStatusRequest{
|
|
ReportedState: "degraded",
|
|
RuntimeMode: runtimeMode,
|
|
Version: version,
|
|
StatusPayload: payload,
|
|
}
|
|
}
|
|
|
|
func vpnFabricOnlyContract(serviceType string, config map[string]any) map[string]any {
|
|
role := "ipv4-ingress"
|
|
reason := "ipv4_ingress_node_contract_ready"
|
|
serviceClass := "vpn_packets"
|
|
internetEgress := false
|
|
if serviceType == "vpn-exit" || serviceType == "ipv4-egress" {
|
|
role = "ipv4-egress"
|
|
reason = "ipv4_egress_contract_ready"
|
|
internetEgress = true
|
|
}
|
|
contract := map[string]any{
|
|
"schema_version": "rap.vpn.fabric_node_contract.v1",
|
|
"reason": reason,
|
|
"role": role,
|
|
"service_class": serviceClass,
|
|
"internet_egress": internetEgress,
|
|
"exit_pool_id": stringConfig(config, "pool_id", ""),
|
|
"exit_region": stringConfig(config, "region", ""),
|
|
"allowed_cidrs": stringSliceConfig(config, "allowed_cidrs"),
|
|
"dns_servers": stringSliceConfig(config, "dns_servers"),
|
|
"client_policy_source": stringConfig(config, "client_policy_source", "fabric_access_policy"),
|
|
"legacy_role_alias": "vpn-client",
|
|
"node_core": "same_fabric_core_all_platforms",
|
|
"platform_adapter_scope": "local_packet_io_only",
|
|
"android_node_supported": serviceType == "vpn-client" || serviceType == "ipv4-ingress",
|
|
"linux_node_supported": serviceType == "vpn-client" || serviceType == "ipv4-ingress",
|
|
"windows_node_supported": serviceType == "vpn-client" || serviceType == "ipv4-ingress",
|
|
"ipv4_exit_supported": internetEgress,
|
|
"fabric_service_channel_required": true,
|
|
"packet_runtime_status": "fabric_channel_binding_pending_runtime",
|
|
"service_binding": vpnServiceBindingContract(serviceType, config),
|
|
}
|
|
return contract
|
|
}
|
|
|
|
func vpnServiceBindingContract(serviceType string, config map[string]any) map[string]any {
|
|
if serviceType == "vpn-exit" || serviceType == "ipv4-egress" {
|
|
return map[string]any{
|
|
"type": "ipv4_egress",
|
|
"accepts_service_class": "vpn_packets",
|
|
"accepts_from_fabric_only": true,
|
|
"compat_protocol_listener": false,
|
|
"exit_pool_id": stringConfig(config, "pool_id", ""),
|
|
"region": stringConfig(config, "region", ""),
|
|
"allowed_cidrs": stringSliceConfig(config, "allowed_cidrs"),
|
|
"dns_servers": stringSliceConfig(config, "dns_servers"),
|
|
"internet_egress": true,
|
|
"requires_host_packet_runtime": true,
|
|
}
|
|
}
|
|
return map[string]any{
|
|
"type": "local_ipv4_ingress",
|
|
"accepts_from": []string{"android_vpnservice_tun", "linux_tun", "windows_wintun", "host_service_port"},
|
|
"service_class": "vpn_packets",
|
|
"exit_selection": "pool",
|
|
"preferred_exit_pool_id": stringConfig(config, "exit_pool_id", ""),
|
|
"listen_tcp_ports": intSliceConfig(config, "listen_tcp_ports"),
|
|
"listen_udp_ports": intSliceConfig(config, "listen_udp_ports"),
|
|
"tun_required": true,
|
|
"route_authority": "fabric_farm",
|
|
"compat_protocol_listener": false,
|
|
"requires_fabric_node_runtime": true,
|
|
"traffic_visibility": "opaque_ipv4_packets",
|
|
"flow_distribution": "opaque_packet_hash_shards",
|
|
}
|
|
}
|
|
|
|
func webIngressListenerConfig(serviceType string, config map[string]any) webingress.ListenerConfig {
|
|
return webingress.ListenerConfig{
|
|
RuntimeConfig: webingress.RuntimeConfig{
|
|
ServiceType: serviceType,
|
|
Scope: stringConfig(config, "scope", ""),
|
|
ServiceClasses: webIngressServiceClasses(serviceType, config),
|
|
TLSMode: stringConfig(config, "tls_mode", "terminate"),
|
|
HTTPSPort: intConfig(config, "listen_https_port", 443),
|
|
},
|
|
HTTPSAddr: stringConfig(config, "listen_https_addr", ":443"),
|
|
TLSCertFile: stringConfig(config, "tls_cert_file", ""),
|
|
TLSKeyFile: stringConfig(config, "tls_key_file", ""),
|
|
}
|
|
}
|
|
|
|
func (s StubSupervisor) webIngressContract(serviceType string, config map[string]any) map[string]any {
|
|
httpsPort := intConfig(config, "listen_https_port", 443)
|
|
tlsMode := strings.TrimSpace(stringConfig(config, "tls_mode", "terminate"))
|
|
serviceClasses := webIngressServiceClasses(serviceType, config)
|
|
scope := strings.TrimSpace(stringConfig(config, "scope", ""))
|
|
realListenerRequested := boolConfig(config, "real_listener_enabled")
|
|
allowedClasses := webIngressAllowedServiceClasses(serviceType)
|
|
missing := []string{}
|
|
if httpsPort != 443 {
|
|
missing = append(missing, "listen_https_port_must_be_443")
|
|
}
|
|
if tlsMode != "terminate" && tlsMode != "passthrough-approved-terminator" {
|
|
missing = append(missing, "tls_mode_invalid")
|
|
}
|
|
if scope == "" {
|
|
missing = append(missing, "scope_required")
|
|
}
|
|
if len(serviceClasses) == 0 {
|
|
missing = append(missing, "service_classes_required")
|
|
}
|
|
for _, serviceClass := range serviceClasses {
|
|
if !containsString(allowedClasses, serviceClass) {
|
|
missing = append(missing, "service_class_not_allowed:"+serviceClass)
|
|
}
|
|
}
|
|
return map[string]any{
|
|
"schema_version": "rap.web_ingress.workload_contract.v1",
|
|
"contract_valid": len(missing) == 0,
|
|
"missing_checks": missing,
|
|
"service_edge_only": true,
|
|
"authority_service": false,
|
|
"fabric_transport": "quic_only",
|
|
"http_between_fabric_nodes": false,
|
|
"listen_https_port": httpsPort,
|
|
"tls_mode": tlsMode,
|
|
"scope": scope,
|
|
"service_classes": serviceClasses,
|
|
"allowed_service_classes": allowedClasses,
|
|
"fabric_service_channel_required": true,
|
|
"runtime_fabric_functions": webIngressFabricFunctions(serviceType, serviceClasses),
|
|
"payload_forwarding": "contract_only",
|
|
"real_listener_requested": realListenerRequested,
|
|
"real_listener_runtime_enabled": s.WebIngressRuntimeEnabled,
|
|
"real_listener_start_allowed": len(missing) == 0 && realListenerRequested && s.WebIngressRuntimeEnabled,
|
|
"runtime_handler_ready": len(missing) == 0,
|
|
"runtime_handler_contract": "rap.web_ingress.runtime_response.v1",
|
|
"runtime_handler_payload_status": "fabric_service_channel_binding_not_implemented",
|
|
"fabric_envelope_schema": webingress.FabricServiceChannelEnvelopeSchema,
|
|
"fabric_runtime_response_schema": "rap.web_ingress.fabric_runtime_response.v1",
|
|
"fabric_envelope_signer": "ed25519_available",
|
|
"fabric_envelope_sender": "mesh_request_response_runtime_adapter_available",
|
|
"fabric_quic_stream": "web_ingress_forward",
|
|
"fabric_quic_stream_id": 2,
|
|
"fabric_runtime_receiver": "signed_envelope_receiver_available",
|
|
"admin_runtime_dispatcher": "read_only_manifest_and_health_available",
|
|
"control_api_binding": "read_only_projection_skeleton_available",
|
|
"runtime_receiver_policy": "trusted_keys_and_service_class_allow_list",
|
|
"ports_opened_by_stub": false,
|
|
}
|
|
}
|
|
|
|
func webIngressAllowedServiceClasses(serviceType string) []string {
|
|
if serviceType == "admin-ingress" {
|
|
return []string{"admin-ingress"}
|
|
}
|
|
return []string{"public-ingress"}
|
|
}
|
|
|
|
func webIngressServiceClasses(serviceType string, config map[string]any) []string {
|
|
raw := stringSliceConfig(config, "service_classes")
|
|
if len(raw) == 0 {
|
|
return webIngressAllowedServiceClasses(serviceType)
|
|
}
|
|
out := []string{}
|
|
for _, serviceClass := range raw {
|
|
serviceClass = strings.TrimSpace(serviceClass)
|
|
switch serviceClass {
|
|
case "admin-ingress", "public-ingress":
|
|
out = append(out, serviceClass)
|
|
}
|
|
}
|
|
if len(out) == 0 {
|
|
return webIngressAllowedServiceClasses(serviceType)
|
|
}
|
|
return dedupeStrings(out)
|
|
}
|
|
|
|
func webIngressFabricFunctions(serviceType string, serviceClasses []string) []string {
|
|
functions := []string{serviceType}
|
|
for _, serviceClass := range serviceClasses {
|
|
switch serviceClass {
|
|
case "admin-ingress":
|
|
functions = append(functions, "admin-ingress")
|
|
case "public-ingress":
|
|
functions = append(functions, "public-ingress")
|
|
}
|
|
}
|
|
return dedupeStrings(functions)
|
|
}
|
|
|
|
func boolConfig(values map[string]any, key string) bool {
|
|
if values == nil {
|
|
return false
|
|
}
|
|
value, ok := values[key]
|
|
if !ok {
|
|
return false
|
|
}
|
|
switch typed := value.(type) {
|
|
case bool:
|
|
return typed
|
|
case string:
|
|
return strings.EqualFold(strings.TrimSpace(typed), "true")
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func intConfig(values map[string]any, key string, fallback int) int {
|
|
if values == nil {
|
|
return fallback
|
|
}
|
|
switch value := values[key].(type) {
|
|
case int:
|
|
return value
|
|
case int64:
|
|
return int(value)
|
|
case float64:
|
|
return int(value)
|
|
case string:
|
|
parsed, err := strconv.Atoi(strings.TrimSpace(value))
|
|
if err != nil {
|
|
return fallback
|
|
}
|
|
return parsed
|
|
default:
|
|
return fallback
|
|
}
|
|
}
|
|
|
|
func stringConfig(values map[string]any, key string, fallback string) string {
|
|
if values == nil {
|
|
return fallback
|
|
}
|
|
value, ok := values[key]
|
|
if !ok {
|
|
return fallback
|
|
}
|
|
if text, ok := value.(string); ok {
|
|
return text
|
|
}
|
|
return fallback
|
|
}
|
|
|
|
func stringSliceConfig(values map[string]any, key string) []string {
|
|
if values == nil {
|
|
return nil
|
|
}
|
|
value, ok := values[key]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
switch typed := value.(type) {
|
|
case []string:
|
|
return dedupeStrings(typed)
|
|
case []any:
|
|
out := []string{}
|
|
for _, item := range typed {
|
|
if text, ok := item.(string); ok {
|
|
out = append(out, strings.TrimSpace(text))
|
|
}
|
|
}
|
|
return dedupeStrings(out)
|
|
case string:
|
|
parts := strings.Split(typed, ",")
|
|
for index := range parts {
|
|
parts[index] = strings.TrimSpace(parts[index])
|
|
}
|
|
return dedupeStrings(parts)
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func intSliceConfig(values map[string]any, key string) []int {
|
|
if values == nil {
|
|
return nil
|
|
}
|
|
value, ok := values[key]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
add := func(out []int, item any) []int {
|
|
switch typed := item.(type) {
|
|
case int:
|
|
if typed > 0 {
|
|
out = append(out, typed)
|
|
}
|
|
case int64:
|
|
if typed > 0 {
|
|
out = append(out, int(typed))
|
|
}
|
|
case float64:
|
|
if typed > 0 {
|
|
out = append(out, int(typed))
|
|
}
|
|
case string:
|
|
if parsed := intConfig(map[string]any{"value": typed}, "value", 0); parsed > 0 {
|
|
out = append(out, parsed)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
out := []int{}
|
|
switch typed := value.(type) {
|
|
case []int:
|
|
out = append(out, typed...)
|
|
case []any:
|
|
for _, item := range typed {
|
|
out = add(out, item)
|
|
}
|
|
case string:
|
|
for _, part := range strings.Split(typed, ",") {
|
|
out = add(out, strings.TrimSpace(part))
|
|
}
|
|
default:
|
|
out = add(out, typed)
|
|
}
|
|
seen := map[int]struct{}{}
|
|
cleaned := make([]int, 0, len(out))
|
|
for _, port := range out {
|
|
if port <= 0 || port > 65535 {
|
|
continue
|
|
}
|
|
if _, ok := seen[port]; ok {
|
|
continue
|
|
}
|
|
seen[port] = struct{}{}
|
|
cleaned = append(cleaned, port)
|
|
}
|
|
return cleaned
|
|
}
|
|
|
|
func dedupeStrings(values []string) []string {
|
|
out := []string{}
|
|
seen := map[string]struct{}{}
|
|
for _, value := range values {
|
|
normalized := strings.TrimSpace(value)
|
|
if normalized == "" {
|
|
continue
|
|
}
|
|
if _, ok := seen[normalized]; ok {
|
|
continue
|
|
}
|
|
seen[normalized] = struct{}{}
|
|
out = append(out, normalized)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func containsString(values []string, needle string) bool {
|
|
for _, value := range values {
|
|
if value == needle {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func remoteWorkspaceAdapterChannels() []map[string]any {
|
|
return []map[string]any{
|
|
{"name": "input", "direction": "client_to_adapter", "reliability": "reliable_ordered", "priority": "critical", "droppable": true, "may_block_input": false},
|
|
{"name": "control", "direction": "bidirectional", "reliability": "reliable_ordered", "priority": "high", "droppable": false, "may_block_input": false},
|
|
{"name": "display", "direction": "adapter_to_client", "reliability": "droppable_latest", "priority": "high", "droppable": true, "may_block_input": false},
|
|
{"name": "cursor", "direction": "adapter_to_client", "reliability": "droppable_latest", "priority": "high", "droppable": true, "may_block_input": false},
|
|
{"name": "clipboard", "direction": "bidirectional", "reliability": "reliable_ordered", "priority": "medium", "droppable": false, "may_block_input": false},
|
|
{"name": "file_transfer", "direction": "bidirectional", "reliability": "reliable_chunked", "priority": "medium", "droppable": false, "may_block_input": false},
|
|
{"name": "audio", "direction": "adapter_to_client", "reliability": "adaptive_droppable", "priority": "medium", "droppable": true, "may_block_input": false},
|
|
{"name": "device", "direction": "bidirectional", "reliability": "reliable_ordered", "priority": "medium", "droppable": false, "may_block_input": false},
|
|
{"name": "telemetry", "direction": "adapter_to_client", "reliability": "sampled_droppable", "priority": "low", "droppable": true, "may_block_input": false},
|
|
}
|
|
}
|
|
|
|
func remoteWorkspaceFrameBatchContract() map[string]any {
|
|
return map[string]any{
|
|
"schema_version": "rap.remote_workspace_frame_batch.v1",
|
|
"adapter_contract_id": "rap.rdp_worker.remote_workspace_adapter_contract_probe.v1",
|
|
"probe_only": true,
|
|
"payload_forwarding": "not_implemented",
|
|
"service_class": "remote_workspace",
|
|
"allowed_flow_classes": []string{"control", "interactive", "reliable", "bulk", "droppable"},
|
|
"allowed_payload_encodings": []string{
|
|
"none",
|
|
"base64",
|
|
},
|
|
"max_probe_frames": 32,
|
|
"channels": remoteWorkspaceAdapterChannels(),
|
|
}
|
|
}
|
|
|
|
func remoteWorkspaceRealAdapterSupervisionContract(configs ...RemoteWorkspaceRealAdapterConfig) map[string]any {
|
|
var config RemoteWorkspaceRealAdapterConfig
|
|
if len(configs) > 0 {
|
|
config = configs[0]
|
|
}
|
|
return map[string]any{
|
|
"schema_version": "rap.remote_workspace_real_adapter_supervision.v1",
|
|
"enabled": false,
|
|
"activation_state": "disabled_until_real_runtime_stage",
|
|
"execution_mode": "real_adapter_supervision_disabled",
|
|
"payload_traffic": "none",
|
|
"process_model": "external_rdp_worker_process",
|
|
"config_projection": remoteWorkspaceRealAdapterConfigProjection(config),
|
|
"activation_decision": remoteWorkspaceRealAdapterActivationDecision(config),
|
|
"process_supervisor_preconditions": remoteWorkspaceRealAdapterProcessSupervisorPreconditions(config),
|
|
"process_health_probe": remoteWorkspaceRealAdapterProcessHealthProbe(),
|
|
"features": map[string]any{
|
|
"config_projection": true,
|
|
"activation_decision": true,
|
|
"missing_gates": true,
|
|
"process_health_probe": true,
|
|
"process_health_probe_disabled": true,
|
|
"process_supervisor_preconditions": true,
|
|
"process_supervisor_start_disabled": true,
|
|
"raw_values_redacted": true,
|
|
},
|
|
"config_env": []string{
|
|
"RAP_REMOTE_WORKSPACE_REAL_ADAPTER_ENABLED",
|
|
"RAP_REMOTE_WORKSPACE_REAL_ADAPTER_COMMAND",
|
|
"RAP_REMOTE_WORKSPACE_REAL_ADAPTER_ARGS_JSON",
|
|
"RAP_REMOTE_WORKSPACE_REAL_ADAPTER_WORKDIR",
|
|
},
|
|
"status_contract": []string{
|
|
"schema_version",
|
|
"enabled",
|
|
"activation_state",
|
|
"execution_mode",
|
|
"payload_traffic",
|
|
"process_model",
|
|
"config_projection",
|
|
"activation_decision",
|
|
"process_supervisor_preconditions",
|
|
"process_health_probe",
|
|
"features",
|
|
"config_env",
|
|
"status_contract",
|
|
},
|
|
"guardrails": []string{
|
|
"contract_probe_remains_default",
|
|
"no_payload_forwarding_until_real_runtime_stage",
|
|
"backend_relay_not_steady_state",
|
|
"fabric_service_channel_required",
|
|
},
|
|
}
|
|
}
|
|
|
|
func remoteWorkspaceRealAdapterProcessHealthProbe() map[string]any {
|
|
return map[string]any{
|
|
"schema_version": "rap.remote_workspace_real_adapter_process_health_probe.v1",
|
|
"health_probe_enabled": false,
|
|
"reason": "disabled_until_real_runtime_stage",
|
|
"payload_traffic": "none",
|
|
"probe_model": "external_process_health",
|
|
"required_signals": []string{
|
|
"process_started",
|
|
"process_exit_status",
|
|
"adapter_control_channel_ready",
|
|
"fabric_service_channel_bound",
|
|
"payload_forwarding_contract_ready",
|
|
},
|
|
"missing_signals": []string{
|
|
"process_started",
|
|
"process_exit_status",
|
|
"adapter_control_channel_ready",
|
|
"fabric_service_channel_bound",
|
|
"payload_forwarding_contract_ready",
|
|
},
|
|
}
|
|
}
|
|
|
|
func remoteWorkspaceRealAdapterProcessSupervisorPreconditions(config RemoteWorkspaceRealAdapterConfig) map[string]any {
|
|
return map[string]any{
|
|
"schema_version": "rap.remote_workspace_real_adapter_process_supervisor_preconditions.v1",
|
|
"process_start_allowed": false,
|
|
"reason": "disabled_until_real_runtime_stage",
|
|
"command_config_present": strings.TrimSpace(config.Command) != "",
|
|
"workdir_config_present": strings.TrimSpace(config.WorkDir) != "",
|
|
"args_config_present": strings.TrimSpace(config.ArgsJSON) != "",
|
|
"required_checks": []string{
|
|
"real_runtime_stage_enabled",
|
|
"command_config_validated",
|
|
"workdir_config_validated",
|
|
"process_identity_policy_bound",
|
|
"fabric_service_channel_runtime_ready",
|
|
"payload_forwarding_contract_enabled",
|
|
"health_probe_contract_enabled",
|
|
},
|
|
"missing_checks": []string{
|
|
"real_runtime_stage_enabled",
|
|
"command_config_validated",
|
|
"workdir_config_validated",
|
|
"process_identity_policy_bound",
|
|
"fabric_service_channel_runtime_ready",
|
|
"payload_forwarding_contract_enabled",
|
|
"health_probe_contract_enabled",
|
|
},
|
|
}
|
|
}
|
|
|
|
func remoteWorkspaceRealAdapterActivationDecision(config RemoteWorkspaceRealAdapterConfig) map[string]any {
|
|
return map[string]any{
|
|
"schema_version": "rap.remote_workspace_real_adapter_activation_decision.v1",
|
|
"decision": "blocked",
|
|
"reason": "real_runtime_stage_not_enabled",
|
|
"enabled_requested": config.EnabledRequested,
|
|
"activation_allowed": false,
|
|
"payload_traffic": "none",
|
|
"required_gates": []string{
|
|
"real_runtime_stage_enabled",
|
|
"fabric_service_channel_runtime_ready",
|
|
"adapter_process_supervisor_enabled",
|
|
"payload_forwarding_contract_enabled",
|
|
},
|
|
"missing_gates": []string{
|
|
"real_runtime_stage_enabled",
|
|
"fabric_service_channel_runtime_ready",
|
|
"adapter_process_supervisor_enabled",
|
|
"payload_forwarding_contract_enabled",
|
|
},
|
|
}
|
|
}
|
|
|
|
func remoteWorkspaceRealAdapterConfigProjection(config RemoteWorkspaceRealAdapterConfig) map[string]any {
|
|
return map[string]any{
|
|
"schema_version": "rap.remote_workspace_real_adapter_config_projection.v1",
|
|
"enabled_requested": config.EnabledRequested,
|
|
"activation_allowed": false,
|
|
"command_present": strings.TrimSpace(config.Command) != "",
|
|
"args_json_present": strings.TrimSpace(config.ArgsJSON) != "",
|
|
"args_json_shape": remoteWorkspaceArgsJSONShape(config.ArgsJSON),
|
|
"workdir_present": strings.TrimSpace(config.WorkDir) != "",
|
|
"raw_values_redacted": true,
|
|
}
|
|
}
|
|
|
|
func remoteWorkspaceArgsJSONShape(value string) string {
|
|
trimmed := strings.TrimSpace(value)
|
|
if trimmed == "" {
|
|
return "absent"
|
|
}
|
|
switch {
|
|
case strings.HasPrefix(trimmed, "["):
|
|
return "json_array"
|
|
case strings.HasPrefix(trimmed, "{"):
|
|
return "json_object"
|
|
default:
|
|
return "opaque"
|
|
}
|
|
}
|
|
|
|
func serviceTrafficMode(serviceType string) string {
|
|
switch serviceType {
|
|
case "core-mesh":
|
|
return "fabric_control"
|
|
case "fabric-listener":
|
|
return "entry_listener"
|
|
default:
|
|
return "unknown"
|
|
}
|
|
}
|