Skip to content

[comp] Production Deploy#3265

Merged
tofikwest merged 17 commits into
releasefrom
main
Jun 23, 2026
Merged

[comp] Production Deploy#3265
tofikwest merged 17 commits into
releasefrom
main

Conversation

@github-actions

@github-actions github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

This is an automated pull request to release the candidate branch into production, which will trigger a deployment.
It was created by the [Production PR] action.


Summary by cubic

Make GCP scans reliable by always running direct API checks and adding SCC findings when available. Also fix Microsoft Entra sign-in, speed up individual policy regeneration with deterministic templates, and prevent bulk policy PDF downloads from failing on malformed imports.

  • New Features

    • Run direct checks and SCC in parallel; combine into one list.
    • Tag runs with source: gcp_scc (SCC contributed) or gcp_direct (direct only).
    • Remediation handles direct-check findings the same as SCC.
  • Bug Fixes

    • Gracefully degrade SCC errors (Legacy disabled, not activated, missing org viewer, transient) to direct-only; preserve the prior run if all direct checks error.
    • Honor per-service disable toggles for direct checks; if all covered services are disabled, run none.
    • Microsoft Entra sign-in no longer fails when the email claim is missing; derive from preferred_username or upn.
    • Individual policy regeneration uses a deterministic template processor (fills placeholders and framework conditionals) and only refines cue lines when present; runs in seconds.
    • Bulk policy PDF render tolerates non-array policy content (e.g., Drata imports) so "download all" no longer fails on a single malformed policy.

Written for commit a54483a. Summary will update on new commits.

Review in cubic

tofikwest and others added 10 commits June 23, 2026 13:48
…y regen

## Problem
After bulk policy regeneration, subsequent individual policy regenerations produce generic output instead of specific content. Individual regen also takes 5+ minutes to complete, making it impractical for users.

## Root cause
Individual policy regen in `apps/api/src/trigger/policies/update-policy-helpers.ts` uses a slow AI-based full-document rewrite path (gpt-4-mini, 5 retries, 600s timeout) that ignores company/industry context. Bulk regen already migrated to a deterministic template-fill engine that preserves authored templates and fills placeholders like {{COMPANY}} and {{INDUSTRY}}. Individual regen was never updated to use the same path, so it falls back to generic LLM generation.

## Fix
Swap individual regen to use the existing deterministic template processor from bulk regen (processTemplate + refineCueLines). This path fills context-aware placeholders, respects the authored template structure, and runs in seconds instead of minutes.

Changes are isolated to `apps/api/src/trigger/policies/`. The deterministic processor is already shipping and proven in bulk workflows.

## Explicitly NOT touched
- Bulk regen behavior (already correct)
- LLM retry logic in other contexts
- API surface or database schema
- Any other policy workflows

## Verification
✅ Individual regen produces specific output with correct company/industry fills
✅ Regen completes in <30 seconds (was 5+ minutes)
✅ Output matches bulk regen output format
✅ Backward compatible with existing bulk behavior
## Problem

Customers encounter "error downloading policy pack" during Drata migration when the policy-pack download endpoint tries to render multiple policies at once. Single policy downloads work fine.

## Root cause

The bulk download flow (download-all-policies) uses Promise.all to render all policies in parallel via preparePolicy. When a policy's content.content is not an array (malformed or unexpected shape), convertToInternalFormat in policy-pdf-renderer.service throws without guards. This rejects the entire Promise.all and fails the whole pack download. Single policy renders don't hit this path so they're unaffected.

The uploaded-PDF fetch has defensive try/catch (1532-1547) and merge fallback (1587-1684) but the content-render path (1550 renderPoliciesPdfBuffer inside Promise.all 1559) has no per-policy error handling.

## Fix

Wrap each policy's prepare and render in try/catch at the promise level so a single bad policy is skipped with a placeholder, not the entire bundle. Add Array.isArray checks in policy-pdf-renderer.service:678-685 before calling convertToInternalFormat to bail early on unexpected shapes. Working orgs with proper array content are unaffected; failing policies now get a safe fallback instead of crashing the whole download.

## Explicitly NOT touched

Not changing trigger/policies regeneration tasks (covered by #3249). Not altering uploaded-PDF fetch path which already has guards. Not touching any §4 never-touch areas.

## Verification

✅ Bulk policy pack download completes even if one policy has malformed content.content
✅ Single policy renders still work
✅ Organizations with valid array content see no change in output
✅ Failed policies appear with placeholder in bundle instead of failing entire download
…laim

Microsoft Entra ID frequently omits the `email` claim for work/school
accounts (it is only emitted when the mailbox `mail` attribute is set or
`email` is configured as an optional claim). better-auth's built-in
Microsoft provider derives the user's email solely from that claim, so
affected users failed sign-in with `error=email_not_found` and were
redirected to the API's Swagger page instead of the app.

Add a `mapProfileToUser` fallback that resolves the email from
`preferred_username`, then `upn`, when the `email` claim is absent —
mirroring better-auth's own microsoftEntraId generic-oauth helper.
Accounts that already return an `email` claim are unaffected (the
resolver returns that claim unchanged). The resolver also guards against
non-string claims so a malformed token cannot crash sign-in.

Adds unit tests for the resolver.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DsGo9DPoaKf7npxMhY2tkz
… when unavailable

The GCP Cloud Tests "Scan" button ran ONLY Security Command Center for GCP.
After Google retired the free "Legacy" SCC tier, every SCC query for orgs
without SCC Standard/Premium fails, and the all-scopes-failed guard turned that
into a hard abort: the scan saved nothing and the dashboard froze on the last
run, so customers could never re-scan to reflect their fixes.

Now GCP scans run our direct-API manifest checks (storage / IAM / firewall /
Cloud SQL / …) as the always-on baseline AND query SCC in parallel, combining
both into one finding list. Our checks read the GCP APIs directly with the OAuth
token, so they always work; SCC is a best-effort supplement that adds its
findings when available and is silently skipped (direct-only) when it errors
(Legacy disabled / not activated / permission / transient). No source split in
the UI — one combined list grouped by service.

Guards:
- The only hard failure is when our OWN checks can't run at all (e.g. a dead
  token): scanGcpDirectChecks throws so the prior good run is preserved instead
  of being overwritten with nothing (keeps PR #3108's protection).
- Runs are tagged scanMode gcp_scc (SCC contributed) / gcp_direct (direct only)
  so reconciliation never cross-diffs an SCC-bearing run (findings carry
  findingKeys) against a direct-only run (no findingKeys), which would mark every
  prior finding falsely "resolved".

Scope is the GCP branch of cloud-security scan() only. Evidence-task automation,
the check engine (runAllChecks/checks/manifest), and the AWS/Azure scan paths
are untouched.

Tests: new gcp-scan-fallback.spec.ts + cloud-security.service.scan-gcp.spec.ts
(20 cases); full cloud-security suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015b1aNsKBRSNPFB6dL6mxqi
…checks

Cubic review (P2): the combined GCP scan filtered SCC findings by the user's
per-service toggle but ran ALL direct-API manifest checks unfiltered, so a
service the user explicitly disabled could still produce findings.

Gate the direct checks by `disabledServices` (the explicit opt-out) via a
check-id → serviceId map: a check whose service is disabled is skipped; a check
with no mapping always runs (a missing mapping must never silently hide
findings). Deliberately NOT gated by the full `enabledServices` set — that also
requires a service to have been auto-detected, but the direct checks are the
always-on baseline (the manual Scan button skips detection), so gating on
detection could hide real findings for a service the user never disabled. When
every covered service is disabled, return [] (intentional empty, not the
all-errored failure the guardrail throws on).

+2 regression tests (disabled service's check dropped; all-disabled → no run).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015b1aNsKBRSNPFB6dL6mxqi
…ndings

Broaden the GCP remediation prompt to treat SCC findings and Comp AI's
direct-API check findings identically. When a finding has no SCC
category/resourceName (our direct checks), derive the fix from the
title/description/remediation/resourceId/evidence and map it to the equivalent
SCC-category fix rules (e.g. "Bucket publicly accessible" == PUBLIC_BUCKET_ACL).

The remediation already runs claude-opus-4-8 (strongest model), so no model
change. Prompt-only: execution (gcp-command-executor), safety rules, and the
manual-steps fallback are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015b1aNsKBRSNPFB6dL6mxqi
…-fallback

fix(cloud-security): combine GCP direct-API checks with SCC, skip SCC when unavailable
@vercel

vercel Bot commented Jun 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
comp-framework-editor (staging) Ready Ready Preview, Comment Jun 23, 2026 11:07pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
app (staging) Skipped Skipped Jun 23, 2026 11:07pm
portal (staging) Skipped Skipped Jun 23, 2026 11:07pm

Request Review

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 5 files

Confidence score: 3/5

  • In apps/api/src/cloud-security/cloud-security.service.ts, scanGcpDirectChecks may return a successful empty result that reconciliation can misread as “fully scanned,” which risks incorrectly resolving real findings and hiding unresolved security exposure—guard against empty scans (treat as incomplete/failed) and require non-empty scannedServices before allowing resolution paths.

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread apps/api/src/cloud-security/cloud-security.service.ts
@vercel vercel Bot temporarily deployed to staging – portal June 23, 2026 23:01 Inactive
@vercel vercel Bot temporarily deployed to staging – app June 23, 2026 23:01 Inactive
…y-pack-during

fix(drata): handle non-array policy content in bulk pdf render
@vercel vercel Bot temporarily deployed to staging – portal June 23, 2026 23:04 Inactive
@vercel vercel Bot temporarily deployed to staging – app June 23, 2026 23:04 Inactive
@tofikwest tofikwest merged commit e51f429 into release Jun 23, 2026
12 checks passed
@claudfuen

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.91.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants