Conversation
…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
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 []; |
There was a problem hiding this comment.
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 && |
There was a problem hiding this comment.
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} |
There was a problem hiding this comment.
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>
| 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); |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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() }, |
There was a problem hiding this comment.
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}`, |
There was a problem hiding this comment.
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>
| error: `Provider call failed (${context}): ${errMessage}`, | |
| error: `Provider call failed (${context})`, |
chore(integrations-catalog): refresh 2026-04-29
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>
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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>
chore(pentest): tighten empty-state copy
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
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
|
🎉 This PR is included in version 3.36.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
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-clientbackend (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
/security/penetration-tests/newwith a generic target URL placeholder.@maced/api-client; addedGET /v1/security-penetration-tests/:id/issuesand.../:id/events; HMAC webhooks with raw-body capture on webhook routes; server-side filtering of vendor-internal events.POST /v1/admin/organizations/:orgId/pentest-credits.better-stack).Migration
organization_billingandpentest_subscriptions; addpentest_credits,credit_refunded_at,completed_audit_at, and a non-negative balance check.STRIPE_PENTEST_SUBSCRIPTION_PRICE_ID,STRIPE_PENTEST_OVERAGE_PRICE_ID,STRIPE_PENTEST_WEBHOOK_SECRET. KeepMACED_API_KEY.@maced/api-client; no other app config changes required.Written for commit 2670b15. Summary will update on new commits. Review in cubic