diff --git a/pkg/workloads/statuses/file_status.go b/pkg/workloads/statuses/file_status.go index 38aabd0d4..442521a56 100644 --- a/pkg/workloads/statuses/file_status.go +++ b/pkg/workloads/statuses/file_status.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "io" "os" "path/filepath" "strings" @@ -94,14 +93,17 @@ func (f *fileStatusManager) isRemoteWorkload(ctx context.Context, workloadName s } defer reader.Close() - // Read the configuration data - data, err := io.ReadAll(reader) - if err != nil { + // Parse the JSON to check for remote_url field + var config struct { + RemoteURL string `json:"remote_url"` + } + decoder := json.NewDecoder(reader) + if err := decoder.Decode(&config); err != nil { return false, err } - // Check if the JSON contains "remote_url" field - return strings.Contains(string(data), `"remote_url"`), nil + // Check if the remote_url field is set + return strings.TrimSpace(config.RemoteURL) != "", nil } // remoteWorkloadConfig is a minimal struct to parse only the fields we need from RunConfig diff --git a/pkg/workloads/statuses/file_status_test.go b/pkg/workloads/statuses/file_status_test.go index 628897f84..1c247545e 100644 --- a/pkg/workloads/statuses/file_status_test.go +++ b/pkg/workloads/statuses/file_status_test.go @@ -1867,3 +1867,62 @@ func TestFileStatusManager_ListWorkloads_PIDMigration(t *testing.T) { require.NoError(t, err) assert.Equal(t, existingPID, statusFile2.ProcessID, "PID should remain unchanged for second workload") } + +func TestFileStatusManager_IsRemoteWorkload_EdgeCases(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + configJSON string + expected bool + }{ + { + name: "remote workload with URL", + configJSON: `{"remote_url": "https://example.com"}`, + expected: true, + }, + { + name: "local workload without remote_url field", + configJSON: `{"name": "test-workload"}`, + expected: false, + }, + { + name: "edge case - remote_url in string value (false positive with old implementation)", + configJSON: `{"description": "Set \"remote_url\" in config to enable remote mode"}`, + expected: false, + }, + { + name: "remote_url field is empty string", + configJSON: `{"remote_url": ""}`, + expected: false, + }, + { + name: "remote_url field with whitespace only", + configJSON: `{"remote_url": " "}`, + expected: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + // Test the JSON parsing logic directly + var config struct { + RemoteURL string `json:"remote_url"` + } + + err := json.Unmarshal([]byte(tt.configJSON), &config) + if err != nil { + t.Fatalf("failed to parse JSON: %v", err) + } + + result := strings.TrimSpace(config.RemoteURL) != "" + + if result != tt.expected { + t.Errorf("expected %v, got %v for JSON: %s", tt.expected, result, tt.configJSON) + } + }) + } +}