Skip to content

[comp] Production Deploy#2694

Merged
tofikwest merged 26 commits intoreleasefrom
main
Apr 29, 2026
Merged

[comp] Production Deploy#2694
tofikwest merged 26 commits intoreleasefrom
main

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot commented Apr 29, 2026

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

Rebuilt penetration tests with a split-view UI, @maced/api-client backend (signed webhooks, issues/events), and a credit wallet with admin grants and audit logs. Also added SOC 3 to the Trust Portal, fixed progress counts, enabled Markdown/CSV evidence uploads, and removed legacy Stripe billing and GitHub OAuth forwarding.

  • New Features

    • Split-view pentest UI with live findings and agent activity; inline create at /security/penetration-tests/new with a generic target URL placeholder.
    • Backend swap to @maced/api-client; added GET /v1/security-penetration-tests/:id/issues and .../:id/events; HMAC webhooks with raw-body capture on webhook routes; server-side filtering of vendor-internal events.
    • Pentest credits wallet (debit on create, refund on failure/cancel, audited); balance shown in UI; admin grant via POST /v1/admin/organizations/:orgId/pentest-credits.
    • Trust Portal: added SOC 3 (switches, statuses, labels, files).
    • Evidence uploads now accept Markdown and CSV.
    • Security nav gated by permissions only (feature flag removed).
    • Integrations catalog refreshed to 559 integrations (includes new entries and a slug rename to better-stack).
    • Fixed framework/requirement/control progress tracking.
  • Migration

    • Run DB migrations: drop organization_billing and pentest_subscriptions; add pentest_credits, credit_refunded_at, completed_audit_at, and a non-negative balance check.
    • Remove env vars: STRIPE_PENTEST_SUBSCRIPTION_PRICE_ID, STRIPE_PENTEST_OVERAGE_PRICE_ID, STRIPE_PENTEST_WEBHOOK_SECRET. Keep MACED_API_KEY.
    • Jest config updated to load @maced/api-client; no other app config changes required.

Written for commit 2670b15. Summary will update on new commits. Review in cubic

tofikwest and others added 12 commits April 27, 2026 10:39
…ooks

Frontend
- Split-view shell at /security/penetration-tests with run list + detail pane
- New /penetration-tests/new route with inline create form (replaces modal)
- 8 detail variants: empty, overview, running, completed, clean, failed, finding, create
- Live findings table + agent activity log (polling-based)
- Severity tokens (oklch) scoped to .pt-tokens, light/dark mode aware

Backend
- Swapped homegrown MacedClient → @maced/api-client v0.9.1
- New endpoints: GET /:id/issues, GET /:id/events
- Webhook signature verification via SDK's MacedClient.webhooks.constructEvent
- Raw-body preservation in main.ts for HMAC verification
- Attribution metadata (compOrganizationId/compEnvironment/compApiVersion)
  sent on every create — disaster-recovery + audit parity
- Removed silent GitHub OAuth token forwarding to Maced (privacy)

Removed
- pentest-billing.{controller,service}.ts + Stripe webhook route (deferred to v2)
- Homegrown maced-client.ts + Zod schemas (replaced by SDK types)
- Phantom webhook handshake (Maced uses HMAC, not per-run tokens)
- listGithubRepos endpoint + getGithubTokenForOrg + CredentialVaultService
  dep — no more silent OAuth-token forwarding to vendor

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Backbone:
- pentest_credits wallet table (balance + lifetime totals + last_grant_source),
  backfill of 1 trial credit per existing org, drop empty pentest_subscriptions
  / organization_billing legacy tables
- credit_refunded_at column on security_penetration_test_runs for webhook
  refund idempotency
- 'pentest' added to AuditLogEntityType enum

Service:
- PentestCreditsService with idempotent grantInitialTrial, grant, atomic
  debitOrThrow, refund (no-op on missing wallet row), audit-log entries on
  grant/refund attributed to org owner
- createReport: debit-first ordering blocks concurrent fast-clicks before
  hitting Maced; refund-on-Maced-failure; refund-on-ownership-persist-failure;
  402 attempts also written to audit log
- handleWebhook: refund on pentest.failed / pentest.cancelled with claim-
  before-refund pattern (updateMany WHERE creditRefundedAt IS NULL); audit
  entry on pentest.completed with finding count, duration, agent count
- persistRunOwnership upsert hardened to never overwrite organizationId on
  conflict (defensive — Maced generates unique IDs in practice)
- @maced/api-client@0.9.1 retry wrapper disabled (maxAttempts: 1) to
  avoid the "Cannot construct a Request..." cryptic error on retriable 5xx;
  jest transformIgnorePatterns added so specs can load the ESM SDK

Admin panel:
- New "Pentest credits" tab on org detail page
- POST /v1/admin/organizations/:orgId/pentest-credits/grant (PlatformAdminGuard,
  source=manual, capped at 1000/grant, audited via AdminAuditLogInterceptor +
  per-org audit log entry)

Frontend UX:
- Quota footer in scan sidebar (X scans remaining / trial used messaging)
- "+ New scan" disabled at zero balance with explicit tooltip + create-form
  banner; no extra clutter in the header
- Overview pane: onboarding state for 0 scans; posture stats (completed,
  coverage, avg duration, cadence), Latest Assessment card with download +
  view-detail, Recent Scans, Stale Coverage. Real data only — no fabricated
  severity rollup or trend charts.
- Clean-state detail pane redesigned: neutral hero, no decorative checks,
  symmetric Markdown/PDF buttons, framework-agnostic CTA copy, suppressed
  misleading "<1m" duration when Maced doesn't bump updatedAt, suppressed
  "Last update" when equal to "Started", removed redundant right-column
- Findings detail: severity left-bar accent on neutral card (no full-card
  tint that overwhelmed at any severity)
- Sidebar: filter button + agent count removed (misleading at low data
  volumes); status pill stays "Completed" everywhere (clean variant dropped
  to keep sidebar/detail badges consistent)
- Execution trace opens by default; events containing "maced" filtered
  out (white-label cleanup) plus TodoWrite noise
- Tamed running pulse animation; elapsed time computed client-side from
  createdAt instead of trusting Maced progress.elapsedMs
- Softer medium severity tokens; full-bleed split-view (negative margins
  around app-shell padding)
- is-security-enabled feature flag check removed (RBAC pentest:read alone
  gates access; flag was breaking dev after PostHog/session restarts)

Tenant isolation:
- All per-run endpoints flow through assertRunOwnership returning 404 (not
  403) so org B cannot enumerate org A's run ids
- listReports filters via listOwnedRunIds before mapping
- Audit log entries scoped to organizationId of the affected org

Tests:
- 17 unit tests for PentestCreditsService covering status, grant, debit
  (including concurrent-debit race), refund, audit-log writes, no-owner
  edge case, audit failure tolerance

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves modify/delete conflict on packages/db/prisma/schema/organization-billing.prisma
by keeping the delete from this branch — the legacy `OrganizationBilling`
model was empty in production and its only code consumer
(apps/app/src/app/api/webhooks/stripe-pentest/route.ts) was already removed
in db0e7e7. Schema state remains consistent: no orphan relations from
Organization or elsewhere.

All other overlapping files auto-merged cleanly:
- apps/api/package.json (jest transformIgnorePatterns + main's new deps)
- apps/api/src/admin-organizations/admin-organizations.module.ts
  (AdminPentestCreditsController + main's PurgeOrganization* services)
- apps/app/src/app/(app)/[orgId]/admin/organizations/[adminOrgId]/components/AdminOrgTabs.tsx
  (Pentest credits tab + main's "Delete Permanently" action)
- bun.lock
- packages/db/prisma/schema/organization.prisma
- packages/db/prisma/schema/security-penetration-test-run.prisma

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
API:
- refundOnTerminalFailure now wraps claim+refund in a single Prisma
  transaction; if the wallet write fails, the creditRefundedAt claim
  rolls back so a redelivered webhook can retry. Previously a transient
  failure would permanently suppress retries and leave the customer
  unrefunded.
- pentest-credits.refund() accepts an optional tx client so the webhook
  path can run it transactionally.
- pentest.completed audit dedup via new completed_audit_at column on
  security_penetration_test_runs (atomic claim before write — webhook
  redelivery can no longer create duplicate audit log rows).
- debitOrThrow's post-debit getStatus now uses the optional tx client
  rather than always going through the bare `db` connection (would
  return stale balance when called inside a transaction).
- Restrict raw-body preservation in main.ts to webhook routes only;
  attaching `rawBody` to every JSON request was duplicating up to 150MB
  of payload memory per request.
- Restructure admin grant route POST `/:orgId/pentest-credits/grant`
  → POST `/:orgId/pentest-credits` so AdminAuditLogInterceptor's URL
  parser doesn't treat "grant" as the entityId. Added `pentest-credits`
  to SEGMENT_TO_RESOURCE so the audit row gets entityType=pentest.

Database:
- New migration 20260429120000_pentest_credits_balance_check:
  - CHECK constraint enforcing balance >= 0 (defense-in-depth on the
    atomic decrement we already do)
  - Drop the redundant @@index on organization_id (already covered by
    @unique's btree)
  - Add completed_audit_at column for the audit dedup above

Frontend:
- SplitView: keep `balance` undefined while credits are loading; the
  previous `?? 0` collapsed loading into "out of credits" and disabled
  the +New button before we knew the user's real balance.
- SplitView download: derive Accept header from the filename's
  extension; previously markdown downloads requested application/pdf
  because the check was "filename ? pdf : markdown" but both formats
  pass a filename.
- FindingDetail PoC: use truthiness so empty strings render the
  fallback message instead of a blank block.
- PentestCreditsTab grant validation: Number() + isInteger() rather
  than parseInt(), which silently truncated "1.5" → 1 and accepted
  "1e3" as 1000.
- useNewFindingHighlights now keys on runId — switching scans no longer
  flashes existing findings as newly arrived.
- usePenetrationTestIssues: trigger one final mutate() when status
  transitions out of in-progress, so the last batch Maced writes
  during completion is fetched.
- FindingsTable rows: role=button, tabIndex, onKeyDown(Enter/Space) so
  keyboard users can open findings.
- relativeTime: "just now" only for < 1 minute (was <= 1, treating a
  full minute as "just now").
- Pulse animation respects prefers-reduced-motion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
These two specs were broken on `main` since the earlier SDK swap and
GitHub-OAuth removal:

- lib.test.ts referenced fields (userId, organizationId, sandboxId,
  workflowId, sessionId) that no longer exist on PentestRun
- penetration-tests-page-client.test.tsx referenced useGithubRepos hook
  that was removed when we dropped GitHub OAuth token forwarding

They've been throwing typecheck errors for weeks while providing zero
real coverage. Deleting rather than rewriting — the few utility
functions in lib.ts (statusLabel, isReportInProgress, etc.) can get a
fresh small spec if needed in a follow-up; the page-client tests would
need a full rewrite against the new SplitView architecture which is a
separate effort.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… files

- getReportEvents() now filters Maced-internal events at the API
  layer instead of trusting the frontend filter alone. The previous
  client-only filter left supplier names visible in DevTools / curl /
  any non-browser consumer of /v1/...:id/events. This is defense in
  depth against cubic's P1 — same predicate as the frontend's
  isCustomerVisible, but enforced server-side so the policy is in one
  place and bypass-proof.

- pentest-credits.prisma: added a doc-comment on `balance` referencing
  the CHECK constraint migration (Prisma's schema DSL doesn't support
  CHECK constraints natively, so the invariant lives in
  20260429120000_pentest_credits_balance_check). The earlier cubic
  flag predates that migration; this comment ensures future readers
  see both the code-side and DB-side enforcement.

- Deleted apps/api/src/security-penetration-tests/README.md — module
  README that grew stale (referenced an older endpoint set / env
  vars) and no longer matched the implementation. The endpoint list
  is the source of truth in the controller; OpenAPI docs are the
  external contract.

- Deleted tasks/todo.md — local planning doc that ended up tracked.
  It described an earlier proposed flow (check-then-create) that we
  superseded with the credit-atomic debit-first ordering in
  createReport. Cubic correctly flagged the doc's pseudocode as
  non-atomic; deleting the doc is the right answer rather than
  rewriting it to match shipped behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
API:
- refundOnTerminalFailure no longer swallows errors. Failures now
  propagate through handleWebhook → 5xx response → Maced redelivery →
  rolled-back creditRefundedAt allows retry. Previously a transient
  refund-tx blip would silently drop the customer's refund forever.
- Removed dead grantInitialTrial method. Trial credits are granted
  via Prisma nested-create on Organization in the org-create server
  actions, atomic with org insert. The unused service method just
  invited future divergence; existing orgs were backfilled by the
  20260427000000_pentest_credits migration. Added a comment in
  pentest-credits.service explaining where the trial actually fires.
- Service spec updated (-1 dead test for the deleted method, total 19).

Frontend:
- AgentActivityLog: track open state in React so user collapse isn't
  fought by the next parent re-render. Was rendering as
  `<details open={defaultOpen}>` which forced the panel re-open every
  SWR poll.
- OverviewPane: coverage and stale-target stats now derive from
  `completed` runs only, not the full runs list. A target with only
  failed scans is no longer counted as "covered" or "fresh."
- AgentProgressGrid: clamp `done` to grid size so an out-of-sync
  Maced progress payload (`done > total`) doesn't render extra cells
  past the configured columns.
- usePenetrationTestEvents: added the same final-revalidation pattern
  as usePenetrationTestIssues so the last events written during the
  completion phase aren't missed when polling stops.
- StatusPill: unknown status values now render as "Unknown" instead
  of falling back to "Provisioning" (which would mislead users into
  thinking the run was still starting up).
- RunningDetail useNewFindingHighlights: removed the timeout-cleanup
  that was canceling pending highlight removals when issues changed
  in <2s (during a 3s SWR poll, very common). Each batch now
  schedules its own fire-and-forget removal so they can't step on
  each other.
- RunList: removed unused `overviewActive` prop (declared but never
  consumed) and stopped passing it from SplitView.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
16 added, 31 updated, 2 removed. Total: 554 integrations across 9 categories.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Build was failing because the new PurgeOrganizationSnapshotService
(added on main while this branch was open) queried db.organizationBilling
and db.pentestSubscription, both of which we dropped in migration
20260427000000_pentest_credits. The git auto-merge couldn't catch this
— it's a logical conflict, not a textual one.

Replace the queries with null literals. The snapshot's `stripe.customerId`
and `stripe.subscriptionId` shape is preserved so downstream consumers
(purge orchestrator, restore tooling) keep working; the legacy tables
had no production data anyway, and v2 billing will add new fields here
when it lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
feat(pentest): credits wallet, admin grants, audit logging, UX polish
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 29, 2026

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

Project Deployment Actions Updated (UTC)
app (staging) Ready Ready Preview, Comment Apr 29, 2026 4:36pm
comp-framework-editor (staging) Ready Ready Preview, Comment Apr 29, 2026 4:36pm
portal (staging) Ready Ready Preview, Comment Apr 29, 2026 4:36pm

Request Review

Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

8 issues found across 72 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/app/src/app/(app)/[orgId]/security/penetration-tests/_components/FindingDetail.tsx">

<violation number="1" location="apps/app/src/app/(app)/[orgId]/security/penetration-tests/_components/FindingDetail.tsx:239">
P2: `extractValidationSteps` is hardcoded to `[]`, so validation steps can never render and the non-empty branch is dead code.</violation>
</file>

<file name="apps/app/src/app/(app)/[orgId]/security/penetration-tests/_components/SplitView.tsx">

<violation number="1" location="apps/app/src/app/(app)/[orgId]/security/penetration-tests/_components/SplitView.tsx:77">
P2: The empty-state condition does not account for list fetch errors, so API failures are shown as an empty scans state.</violation>

<violation number="2" location="apps/app/src/app/(app)/[orgId]/security/penetration-tests/_components/SplitView.tsx:154">
P2: `aria-hidden` is applied to a container with focusable descendants; in create mode the run list can still be keyboard-focused despite being hidden from assistive tech.</violation>
</file>

<file name="apps/app/src/app/(app)/[orgId]/security/penetration-tests/_components/OverviewPane.tsx">

<violation number="1" location="apps/app/src/app/(app)/[orgId]/security/penetration-tests/_components/OverviewPane.tsx:140">
P2: Recent scan activity is filtered to completed runs only, so failed/cancelled recent scans are hidden from the "Recent scans" section.</violation>
</file>

<file name="apps/app/src/app/(app)/[orgId]/security/penetration-tests/_components/RunningDetail.tsx">

<violation number="1" location="apps/app/src/app/(app)/[orgId]/security/penetration-tests/_components/RunningDetail.tsx:139">
P2: The new-finding highlight baseline is initialized before issues finish loading, so the first fetched findings for a run can all be incorrectly marked as newly arrived.</violation>
</file>

<file name="apps/api/src/security-penetration-tests/security-penetration-tests.service.spec.ts">

<violation number="1" location="apps/api/src/security-penetration-tests/security-penetration-tests.service.spec.ts:612">
P1: Do not leave webhook HMAC validation and constructor-time API-key behavior untested; this removes coverage for a security-critical flow.</violation>
</file>

<file name="apps/api/src/security-penetration-tests/security-penetration-tests.service.ts">

<violation number="1" location="apps/api/src/security-penetration-tests/security-penetration-tests.service.ts:178">
P2: Do not include raw transport exception messages in the HTTP response body; this can leak internal infrastructure details.</violation>

<violation number="2" location="apps/api/src/security-penetration-tests/security-penetration-tests.service.ts:544">
P2: `completedAuditAt` is set before the audit entry is durably written, so transient audit-write failures can permanently suppress completion auditing.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

'Maced API key not configured on server',
);
});
// TODO(phase-5): webhook tests removed — handleWebhook now verifies HMAC
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.

P1: Do not leave webhook HMAC validation and constructor-time API-key behavior untested; this removes coverage for a security-critical flow.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/security-penetration-tests/security-penetration-tests.service.spec.ts, line 612:

<comment>Do not leave webhook HMAC validation and constructor-time API-key behavior untested; this removes coverage for a security-critical flow.</comment>

<file context>
@@ -585,201 +609,11 @@ describe('SecurityPenetrationTestsService', () => {
-      'Maced API key not configured on server',
-    );
-  });
+  // TODO(phase-5): webhook tests removed — handleWebhook now verifies HMAC
+  // via @maced/api-client verifyMacedWebhook. Rewrite: valid signature → ok,
+  // invalid/missing signature → ForbiddenException, unknown run → warn+ok.
</file context>

// Validation-steps field isn't part of PentestIssue type (yet); parse if it
// shows up on future payloads. For now returns empty.
function extractValidationSteps(_issue: PentestIssue): string[] {
return [];
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.

P2: extractValidationSteps is hardcoded to [], so validation steps can never render and the non-empty branch is dead code.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/app/(app)/[orgId]/security/penetration-tests/_components/FindingDetail.tsx, line 239:

<comment>`extractValidationSteps` is hardcoded to `[]`, so validation steps can never render and the non-empty branch is dead code.</comment>

<file context>
@@ -0,0 +1,240 @@
+// Validation-steps field isn't part of PentestIssue type (yet); parse if it
+// shows up on future payloads. For now returns empty.
+function extractValidationSteps(_issue: PentestIssue): string[] {
+  return [];
+}
</file context>


const showEmptyState =
!listLoading &&
reports.length === 0 &&
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.

P2: The empty-state condition does not account for list fetch errors, so API failures are shown as an empty scans state.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/app/(app)/[orgId]/security/penetration-tests/_components/SplitView.tsx, line 77:

<comment>The empty-state condition does not account for list fetch errors, so API failures are shown as an empty scans state.</comment>

<file context>
@@ -0,0 +1,255 @@
+
+  const showEmptyState =
+    !listLoading &&
+    reports.length === 0 &&
+    selectedRunId === null &&
+    mode !== 'create';
</file context>

return (
<div className="pt-tokens flex h-[calc(100vh-4rem)] min-h-0 -m-4 md:-m-6">
<div
aria-hidden={isCreateMode}
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.

P2: aria-hidden is applied to a container with focusable descendants; in create mode the run list can still be keyboard-focused despite being hidden from assistive tech.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/app/(app)/[orgId]/security/penetration-tests/_components/SplitView.tsx, line 154:

<comment>`aria-hidden` is applied to a container with focusable descendants; in create mode the run list can still be keyboard-focused despite being hidden from assistive tech.</comment>

<file context>
@@ -0,0 +1,255 @@
+  return (
+    <div className="pt-tokens flex h-[calc(100vh-4rem)] min-h-0 -m-4 md:-m-6">
+      <div
+        aria-hidden={isCreateMode}
+        className={isCreateMode ? 'pointer-events-none opacity-45' : ''}
+      >
</file context>
Suggested change
aria-hidden={isCreateMode}
inert={isCreateMode}

const lastScan = mostRecent(completed);
const avgDuration = avgDurationMs(completed);
const scansLast30d = countWithin(completed, 30 * 24 * 60 * 60 * 1000);
const recentScans = sortByUpdatedDesc(completed).slice(0, 6);
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.

P2: Recent scan activity is filtered to completed runs only, so failed/cancelled recent scans are hidden from the "Recent scans" section.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/app/(app)/[orgId]/security/penetration-tests/_components/OverviewPane.tsx, line 140:

<comment>Recent scan activity is filtered to completed runs only, so failed/cancelled recent scans are hidden from the "Recent scans" section.</comment>

<file context>
@@ -0,0 +1,259 @@
+  const lastScan = mostRecent(completed);
+  const avgDuration = avgDurationMs(completed);
+  const scansLast30d = countWithin(completed, 30 * 24 * 60 * 60 * 1000);
+  const recentScans = sortByUpdatedDesc(completed).slice(0, 6);
+  const staleTargets = computeStaleTargets(completed, targets);
+
</file context>

// On run change: prime `seenRef` with the issues already present so
// they don't all flash as newly-arrived. Bypass the next "newly
// landed" pass entirely for this run change.
if (lastRunIdRef.current !== runId) {
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.

P2: The new-finding highlight baseline is initialized before issues finish loading, so the first fetched findings for a run can all be incorrectly marked as newly arrived.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/app/(app)/[orgId]/security/penetration-tests/_components/RunningDetail.tsx, line 139:

<comment>The new-finding highlight baseline is initialized before issues finish loading, so the first fetched findings for a run can all be incorrectly marked as newly arrived.</comment>

<file context>
@@ -0,0 +1,177 @@
+  // On run change: prime `seenRef` with the issues already present so
+  // they don't all flash as newly-arrived. Bypass the next "newly
+  // landed" pass entirely for this run change.
+  if (lastRunIdRef.current !== runId) {
+    seenRef.current = new Set(issues.map((i) => i.id));
+    lastRunIdRef.current = runId;
</file context>

providerRunId: data.pentestId,
completedAuditAt: null,
},
data: { completedAuditAt: new Date() },
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.

P2: completedAuditAt is set before the audit entry is durably written, so transient audit-write failures can permanently suppress completion auditing.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/security-penetration-tests/security-penetration-tests.service.ts, line 544:

<comment>`completedAuditAt` is set before the audit entry is durably written, so transient audit-write failures can permanently suppress completion auditing.</comment>

<file context>
@@ -314,149 +427,224 @@ export class SecurityPenetrationTestsService {
+        providerRunId: data.pentestId,
+        completedAuditAt: null,
+      },
+      data: { completedAuditAt: new Date() },
+    });
+    if (claimed.count === 0) {
</file context>

);
throw new HttpException(
{
error: `Provider call failed (${context}): ${errMessage}`,
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.

P2: Do not include raw transport exception messages in the HTTP response body; this can leak internal infrastructure details.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/security-penetration-tests/security-penetration-tests.service.ts, line 178:

<comment>Do not include raw transport exception messages in the HTTP response body; this can leak internal infrastructure details.</comment>

<file context>
@@ -81,22 +107,81 @@ interface WebhookRequestMetadata {
+      );
+      throw new HttpException(
+        {
+          error: `Provider call failed (${context}): ${errMessage}`,
+          source: 'transport',
+        },
</file context>
Suggested change
error: `Provider call failed (${context}): ${errMessage}`,
error: `Provider call failed (${context})`,

chore(integrations-catalog): refresh 2026-04-29
tofikwest and others added 3 commits April 29, 2026 11:48
Drop the "22 specialist agents" wording and call out that repo attach is
public-only, matching the language in CreateRunPanel.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Avoid implementation-specific language in user-facing copy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
[dev] [Marfuen] mariano/cs-316-bug-progress-tracking-issues-and-missing-documents-link-in
…2684)

Co-authored-by: chasprowebdev <chasgarciaprowebdev@gmail.com>
Co-authored-by: chasprowebdev <70908289+chasprowebdev@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

1 issue found across 16 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/app/src/app/(app)/[orgId]/frameworks/[frameworkInstanceId]/requirements/[requirementKey]/components/table/RequirementControlsTable.tsx">

<violation number="1" location="apps/app/src/app/(app)/[orgId]/frameworks/[frameworkInstanceId]/requirements/[requirementKey]/components/table/RequirementControlsTable.tsx:163">
P2: Avoid recomputing `getRequirementArtifactCounts` inside each table row; it repeatedly scans tasks and sorts evidence submissions per row.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

// Use the shared aggregator so per-control counts (especially
// documents) honour the same 6-month freshness rule as
// getControlStatus / getControlProgressPercent below.
const counts = getRequirementArtifactCounts(
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.

P2: Avoid recomputing getRequirementArtifactCounts inside each table row; it repeatedly scans tasks and sorts evidence submissions per row.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/app/(app)/[orgId]/frameworks/[frameworkInstanceId]/requirements/[requirementKey]/components/table/RequirementControlsTable.tsx, line 163:

<comment>Avoid recomputing `getRequirementArtifactCounts` inside each table row; it repeatedly scans tasks and sorts evidence submissions per row.</comment>

<file context>
@@ -104,42 +118,69 @@ export function RequirementControlsTable({
+              // Use the shared aggregator so per-control counts (especially
+              // documents) honour the same 6-month freshness rule as
+              // getControlStatus / getControlProgressPercent below.
+              const counts = getRequirementArtifactCounts(
+                [control],
+                tasks,
</file context>

tofikwest and others added 2 commits April 29, 2026 12:24
Replace the staging-specific hostname with a generic "your.staging.app"
so the placeholder doesn't imply a Comp AI internal target.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chore(pentest): genericize target URL placeholder
tofikwest and others added 3 commits April 29, 2026 12:30
5 new integrations + slug rename. Total: 559.

Added: better-stack, heap, looker, power-bi, tableau, uptime-robot
Renamed: betterstack -> better-stack

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chore(integrations-catalog): refresh 2026-04-29 round 2
@tofikwest tofikwest merged commit 7a2df16 into release Apr 29, 2026
9 of 12 checks passed
@claudfuen
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.36.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