diff --git a/apps/api/src/cloud-security/cloud-security.service.ts b/apps/api/src/cloud-security/cloud-security.service.ts index af8cba373..f249e0c57 100644 --- a/apps/api/src/cloud-security/cloud-security.service.ts +++ b/apps/api/src/cloud-security/cloud-security.service.ts @@ -387,6 +387,7 @@ export class CloudSecurityService { ...variables, detectedServices: [...existingDetected], disabledServices: [...updatedDisabled], + serviceDetectionCompletedAt: new Date().toISOString(), }, }, }); diff --git a/apps/api/src/integration-platform/controllers/services.controller.ts b/apps/api/src/integration-platform/controllers/services.controller.ts index 427aba61b..5ed883bea 100644 --- a/apps/api/src/integration-platform/controllers/services.controller.ts +++ b/apps/api/src/integration-platform/controllers/services.controller.ts @@ -63,6 +63,19 @@ export class ServicesController { ? (variables.enabledServices as string[]) : null; + const source = legacyEnabledServices + ? 'legacy-enabled' + : detectedServices + ? 'detected' + : 'manifest-default'; + const detectionCompletedAt = + typeof variables.serviceDetectionCompletedAt === 'string' + ? variables.serviceDetectionCompletedAt + : null; + const detectionReady = providerSlug === 'gcp' + ? source !== 'manifest-default' || Boolean(detectionCompletedAt) + : true; + // AWS security baseline: always scanned, hidden from Services tab const BASELINE_SERVICES = providerSlug === 'aws' ? new Set(['cloudtrail', 'config', 'guardduty', 'iam', 'cloudwatch', 'kms']) @@ -89,15 +102,8 @@ export class ServicesController { } else if (detectedServices) { enabled = detectedServices.includes(s.id) && !disabledServices.has(s.id); } else { - // No detection data yet: - // - GCP should default to enabled (scan already runs across SCC categories by default), - // so UI doesn't misleadingly show everything as OFF immediately after OAuth connect. - // - Others keep manifest defaults. - if (providerSlug === 'gcp') { - enabled = !disabledServices.has(s.id); - } else { - enabled = (s.enabledByDefault ?? true) && !disabledServices.has(s.id); - } + // Default: use enabledByDefault from manifest, otherwise enabled + enabled = (s.enabledByDefault ?? true) && !disabledServices.has(s.id); } return { @@ -108,6 +114,12 @@ export class ServicesController { enabled, }; }), + meta: { + providerSlug, + source, + detectionReady, + detectionCompletedAt, + }, }; } } diff --git a/apps/app/src/app/(app)/[orgId]/cloud-tests/components/CloudTestsSection.tsx b/apps/app/src/app/(app)/[orgId]/cloud-tests/components/CloudTestsSection.tsx index baead1038..518b97c64 100644 --- a/apps/app/src/app/(app)/[orgId]/cloud-tests/components/CloudTestsSection.tsx +++ b/apps/app/src/app/(app)/[orgId]/cloud-tests/components/CloudTestsSection.tsx @@ -199,6 +199,7 @@ export function CloudTestsSection({ description?: string; } | null>(null); const [showSetupDialog, setShowSetupDialog] = useState(false); + const [showGcpSetupStatus, setShowGcpSetupStatus] = useState(false); const findingsResponse = api.useSWR<{ data: Finding[]; count: number }>( '/v1/cloud-security/findings', @@ -464,6 +465,15 @@ export function CloudTestsSection({
Detecting active GCP services...
++ We'll show real service toggles as soon as detection completes. +
+Daily scan
-Every day at 5:00 AM UTC
++ {waitingForDetection + ? 'Detecting active GCP services...' + : 'Every day at 5:00 AM UTC'} +
- {enabledCount} of {implementedServices.length} services + {waitingForDetection + ? 'Waiting for detection' + : `${enabledCount} of ${implementedServices.length} services`}
+ Service toggles will appear once detection completes. +
+ ) : ( + filteredServices.map((service) => ( {service.name} - ))} - {filteredServices.length === 0 && search && ( + )) + )} + {!waitingForDetection && filteredServices.length === 0 && search && (No services match "{search}"
diff --git a/apps/app/src/app/(app)/[orgId]/integrations/[slug]/components/ProviderDetailView.tsx b/apps/app/src/app/(app)/[orgId]/integrations/[slug]/components/ProviderDetailView.tsx index d8a56b6c3..45d852390 100644 --- a/apps/app/src/app/(app)/[orgId]/integrations/[slug]/components/ProviderDetailView.tsx +++ b/apps/app/src/app/(app)/[orgId]/integrations/[slug]/components/ProviderDetailView.tsx @@ -84,6 +84,7 @@ export function ProviderDetailView({ provider, initialConnections }: ProviderDet // Services hook for the selected connection const { services: connectionServices, + meta: servicesMeta, refresh: refreshServices, updateServices, } = useConnectionServices(selectedConnection?.id ?? null); @@ -251,13 +252,22 @@ export function ProviderDetailView({ provider, initialConnections }: ProviderDet {services.length > 0 && (Detecting active GCP services...
++ We'll show real service toggles as soon as detection completes. +
+