Skip to content

Commit e96e850

Browse files
tofikwestclaude
andcommitted
fix: address PR review feedback
- Change body logging from log to debug level (avoid leaking IAM data in prod) - Roll back optimistic state on API failure in project picker - Rename orgId → gcpOrgId to avoid shadowing app org ID - Add defensive validation for servicesByProject JSON shape - Add .catch() to prevent unhandled promise rejections in ServiceCard Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 0a7993b commit e96e850

5 files changed

Lines changed: 16 additions & 9 deletions

File tree

apps/api/src/cloud-security/gcp-command-executor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ async function executeOnce(
217217
logger.log(`${step.method} ${url}${step.purpose}`);
218218
if (effectiveBody && (step.method === 'POST' || step.method === 'PUT' || step.method === 'PATCH')) {
219219
const bodyStr = JSON.stringify(effectiveBody);
220-
logger.log(` Body (${bodyStr.length} chars): ${bodyStr.substring(0, 2000)}${bodyStr.length > 2000 ? '...' : ''}`);
220+
logger.debug(` Body (${bodyStr.length} chars): ${bodyStr.substring(0, 2000)}${bodyStr.length > 2000 ? '...' : ''}`);
221221
}
222222

223223
const response = await fetch(url, {

apps/api/src/integration-platform/controllers/services.controller.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,15 @@ export class ServicesController {
9797

9898
// Per-project service mapping (GCP only)
9999
const servicesByProject =
100-
(variables.servicesByProject as Record<string, string[]>) ?? {};
100+
variables.servicesByProject &&
101+
typeof variables.servicesByProject === 'object' &&
102+
!Array.isArray(variables.servicesByProject)
103+
? (variables.servicesByProject as Record<string, string[]>)
104+
: {};
101105
// Invert: service → project IDs
102106
const projectsByService: Record<string, string[]> = {};
103107
for (const [projectId, serviceIds] of Object.entries(servicesByProject)) {
108+
if (!Array.isArray(serviceIds)) continue;
104109
for (const svcId of serviceIds) {
105110
(projectsByService[svcId] ??= []).push(projectId);
106111
}

apps/app/src/app/(app)/[orgId]/cloud-tests/components/ServiceCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ export function ServiceCard({
163163
role="switch"
164164
aria-checked={isEnabled}
165165
disabled={toggling}
166-
onClick={() => void Promise.resolve(onToggle?.(service.id, !isEnabled))}
166+
onClick={() => void Promise.resolve(onToggle?.(service.id, !isEnabled)).catch(() => {})}
167167
className={`relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full transition-colors disabled:opacity-50 ${
168168
isEnabled ? 'bg-primary' : 'bg-muted-foreground/30'
169169
}`}

apps/app/src/app/(app)/[orgId]/integrations/[slug]/components/ProviderDetailView.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -308,10 +308,11 @@ export function ProviderDetailView({
308308
<GcpProjectPicker
309309
organizations={gcpOrgs}
310310
selectedProjectIds={gcpSelectedProjectIds}
311-
onToggleProject={(orgId, projectId) => {
312-
const next = gcpSelectedProjectIds.includes(projectId)
313-
? gcpSelectedProjectIds.filter((id) => id !== projectId)
314-
: [...gcpSelectedProjectIds, projectId];
311+
onToggleProject={(gcpOrgId, projectId) => {
312+
const prev = gcpSelectedProjectIds;
313+
const next = prev.includes(projectId)
314+
? prev.filter((id) => id !== projectId)
315+
: [...prev, projectId];
315316
setGcpSelectedProjectIds(next);
316317
// Build name map keyed by both project ID and project number
317318
const allProjects = gcpOrgs.flatMap((o) => o.projects);
@@ -328,10 +329,11 @@ export function ProviderDetailView({
328329
void api
329330
.post(
330331
`/v1/cloud-security/select-gcp-projects/${selectedConnection.id}`,
331-
{ projectIds: next, projectNames, gcpOrganizationId: orgId },
332+
{ projectIds: next, projectNames, gcpOrganizationId: gcpOrgId },
332333
)
333334
.then(async (res) => {
334335
if (res.error) {
336+
setGcpSelectedProjectIds(prev);
335337
toast.error('Failed to update projects');
336338
return;
337339
}

apps/app/src/app/(app)/[orgId]/integrations/[slug]/components/ServiceCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ export function ServiceCard({
148148
role="switch"
149149
aria-checked={isEnabled}
150150
disabled={toggling}
151-
onClick={() => void Promise.resolve(onToggle?.(service.id, !isEnabled))}
151+
onClick={() => void Promise.resolve(onToggle?.(service.id, !isEnabled)).catch(() => {})}
152152
className={`relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full transition-colors disabled:opacity-50 ${
153153
isEnabled ? 'bg-primary' : 'bg-muted-foreground/30'
154154
}`}

0 commit comments

Comments
 (0)