[comp] Production Deploy#3463
Conversation
…) (#3462) adm-zip < 0.6.0 allows a crafted ZIP to trigger a 4GB memory allocation (DoS). This is reachable: apps/api/src/questionnaire/utils/content-extractor.ts runs `new AdmZip(fileBuffer)` on user-uploaded questionnaire files (xlsx/docx are ZIP containers). Bumps the direct dependency to ^0.6.0 (patched) and updates bun.lock. Our usage (new AdmZip, getEntry, getData, addFile, toBuffer) is unchanged in 0.6.0. Supersedes Dependabot PR #3451, which bumped package.json but left bun.lock out of sync. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
…rts (#3464) - engine.io: add bun override to ^6.6.7. The vulnerable 6.5.5 (Engine.IO polling connection-exhaustion DoS, <6.6.7) was pulled transitively via @trigger.dev/core -> socket.io@4.7.4. Override collapses it to 6.6.9 (the version top-level socket.io@4.8.3 already uses); bun.lock now has a single engine.io@6.6.9. Not a reachable DoS for us (we run no engine.io server; trigger.dev uses it client-side) but removes the alert. - body-parser: bump the transitive dep in apps/mcp-server (runtime, via express@5.2.1) 2.2.2 -> 2.3.0 (patched; DoS via invalid limit silently disabling size enforcement). Lockfile-only; express's ^2.2.1 range permits 2.3.0, so it stays transitive and survives SDK regeneration. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
#94-#104) (#3466) A batch of 11 node-tar advisories (Critical->Moderate: decompression DoS, path traversal, symlink/hardlink escape, PAX parsing differentials) flagged every tar copy below 7.5.19. bun.lock had tar@6.2.1 (x5, via build tooling: node-gyp, cacache, @electron/rebuild, app-builder-lib, giget), tar@7.5.11 (fleetctl), and tar@7.5.20 (already patched). node-tar backported no fixes to the 6.x line, so the only remediation is tar >= 7.5.19. Added a bun override "tar": "^7.5.19" — bun.lock now resolves a single tar@7.5.20 for all consumers. tar@7 is a dual CJS/ESM package with a stable extract/create API, so the CJS build tools keep working via require(). Reachability was low pre-fix (all vulnerable copies were build-time tooling or trusted-source CLI extraction, none extract attacker-controlled archives in the runtime API), but the override removes the vulnerable versions entirely. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…S-724) (#3468) * feat(isms): internal audit programme, plan and report — clause 9.2 (CS-724) Adds the ninth ISMS document type: Compliance > ISMS > Internal Audit. - Programme paragraph (editable, seeded with a default) rendered verbatim into the generated document - Audit instances with server-generated IA-YYYY-NN references, templated scope/criteria, auditor pulled from ISMS > Roles > Internal Auditor, planned dates, status, and a conclusion verdict + narrative - Controls Tested table seeded with the default 15-row sample set (management-system clauses + high-impact Annex A controls); result + notes recorded per row - Findings with server-generated F-NN references, type/owner/due date/status/closure evidence, optional link back to a control row - Three sign-off slots per audit, frozen into the published version snapshot and rendered as the document's sign-off table - Submit gate: at least one audit, and a conclusion verdict on every completed audit (enforced server-side, mirrored in the client) * fix(isms): align internal-audit components with design-system prop types The Vercel next build enforces the design-system unions that the local tsc pass missed: Stack gap has no '5', TableCell omits className, and Select.onValueChange passes string | null. * fix(isms): address internal-audit review findings - scope audit/control/finding lookups to the internal-audit document type - seed the programme paragraph only when the draft narrative is empty, so a concurrent setup call can never overwrite an edit - trim required text fields (scope, criteria, control reference) so whitespace-only values are rejected - marking a control row non-conformity/observation now opens the findings form pre-filled with the linked row (per the ticket flow), and the edit form pre-fills clause text like the add form - preserve unsaved sign-off input across sibling register refreshes - gate the control-row Save button on validity - document the audit register fields in the OpenAPI body schema - cover the internal-audit derivation path in generate.spec * fix(isms): make the programme seed atomic and re-key the finding prompt - seed the programme via a conditional update that matches only a NULL draft narrative, removing the read-then-write race entirely (and with it the duplicated empty-narrative predicate) - key the prefilled linked-finding form by row and type, so re-marking the same control with a different result re-initializes the form * fix(isms): treat an empty-object narrative as seedable, matching generate The programme seed's conditional update now matches NULL or {} — the same empty definition generateNarrative uses — so the two seed paths can never drift while still never overwriting a populated draft. * feat(isms): render closure evidence in the exported findings table Closed corrective actions now show how they were evidenced in the generated document — appended to the description cell, keeping the reference document's seven-column findings table. --------- Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
There was a problem hiding this comment.
8 issues found across 60 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]/documents/isms/components/AuditControlsTable.tsx">
<violation number="1" location="apps/app/src/app/(app)/[orgId]/documents/isms/components/AuditControlsTable.tsx:44">
P3: New control rows always save with blank notes because this form has no Notes field, despite the table exposing that column. Add the optional notes input so auditors can record it when creating the row rather than requiring a second edit.</violation>
</file>
<file name="apps/api/src/isms/isms.service.ts">
<violation number="1" location="apps/api/src/isms/isms.service.ts:575">
P3: ISMS service now exceeds the repository's 300-line file limit by more than 2x, making the lifecycle and validation responsibilities harder to maintain. Move Internal Audit validation/provisioning behavior into a focused helper/service module and retain a small delegation here.</violation>
</file>
<file name="apps/app/src/app/(app)/[orgId]/documents/isms/components/audit-schema.ts">
<violation number="1" location="apps/app/src/app/(app)/[orgId]/documents/isms/components/audit-schema.ts:20">
P2: An audit can be saved with a planned end date before its planned start date, producing an invalid audit schedule. Add a cross-field date-order validation here and enforce the same invariant in the API for non-UI callers.</violation>
</file>
<file name="apps/api/src/isms/isms-audit-finding.service.ts">
<violation number="1" location="apps/api/src/isms/isms-audit-finding.service.ts:150">
P2: Deleting the highest-numbered finding lets its reference be reissued on the next create, breaking the immutable audit trail promised for `F-NN`. Persist a per-audit monotonically increasing sequence (or retain deleted reference history) rather than deriving it from live rows.</violation>
</file>
<file name="apps/app/src/app/(app)/[orgId]/documents/isms/components/AuditControlRow.tsx">
<violation number="1" location="apps/app/src/app/(app)/[orgId]/documents/isms/components/AuditControlRow.tsx:143">
P3: Clearing the required control reference leaves Save disabled without any validation feedback, so users cannot tell what needs fixing. Render the `controlRef` field error (and ideally invalid state) in this edit row, matching the create form.</violation>
</file>
<file name="apps/app/src/app/(app)/[orgId]/documents/isms/components/ProgrammeCard.tsx">
<violation number="1" location="apps/app/src/app/(app)/[orgId]/documents/isms/components/ProgrammeCard.tsx:132">
P3: Multi-line programme edits lose paragraph/line-break formatting in the read view because normal text rendering collapses newlines. Preserve whitespace when displaying the saved textarea value so it matches the entered/generated document content.</violation>
</file>
<file name="apps/app/src/app/(app)/[orgId]/documents/isms/components/AuditSignoffCard.tsx">
<violation number="1" location="apps/app/src/app/(app)/[orgId]/documents/isms/components/AuditSignoffCard.tsx:142">
P3: The signed badge can report a completed slot for a whitespace-only signatory name, although the API normalizes that name to `null`. Trim the name for this completeness check so badge and generated sign-off state agree.</violation>
</file>
<file name="apps/api/src/isms/isms-audit-control.service.ts">
<violation number="1" location="apps/api/src/isms/isms-audit-control.service.ts:103">
P2: Deleting a control can leave a linked finding with no control reference when its API request omitted optional `clauseOrControl`; the FK clears `controlId` and no frozen label is populated. Preserve `control.controlRef` for linked findings with a null label before deleting, or require/derive that label when creating linked findings.</violation>
</file>
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
| criteria: z.string().trim().min(1, 'Criteria is required'), | ||
| auditorName: z.string(), | ||
| plannedStartDate: z.string(), | ||
| plannedEndDate: z.string(), |
There was a problem hiding this comment.
P2: An audit can be saved with a planned end date before its planned start date, producing an invalid audit schedule. Add a cross-field date-order validation here and enforce the same invariant in the API for non-UI callers.
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]/documents/isms/components/audit-schema.ts, line 20:
<comment>An audit can be saved with a planned end date before its planned start date, producing an invalid audit schedule. Add a cross-field date-order validation here and enforce the same invariant in the API for non-UI callers.</comment>
<file context>
@@ -0,0 +1,105 @@
+ criteria: z.string().trim().min(1, 'Criteria is required'),
+ auditorName: z.string(),
+ plannedStartDate: z.string(),
+ plannedEndDate: z.string(),
+ status: z.enum(AUDIT_STATUSES),
+ conclusionVerdict: z.union([z.enum(CONCLUSION_VERDICTS), z.literal('')]),
</file context>
| const match = /^F-(\d+)$/.exec(finding.reference); | ||
| return match ? Math.max(max, Number.parseInt(match[1], 10)) : max; | ||
| }, 0); | ||
| return `F-${String(maxSequence + 1).padStart(2, '0')}`; |
There was a problem hiding this comment.
P2: Deleting the highest-numbered finding lets its reference be reissued on the next create, breaking the immutable audit trail promised for F-NN. Persist a per-audit monotonically increasing sequence (or retain deleted reference history) rather than deriving it from live rows.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/isms/isms-audit-finding.service.ts, line 150:
<comment>Deleting the highest-numbered finding lets its reference be reissued on the next create, breaking the immutable audit trail promised for `F-NN`. Persist a per-audit monotonically increasing sequence (or retain deleted reference history) rather than deriving it from live rows.</comment>
<file context>
@@ -0,0 +1,248 @@
+ const match = /^F-(\d+)$/.exec(finding.reference);
+ return match ? Math.max(max, Number.parseInt(match[1], 10)) : max;
+ }, 0);
+ return `F-${String(maxSequence + 1).padStart(2, '0')}`;
+ }
+
</file context>
| await invalidateApprovalIfNeeded({ tx, documentId: control.documentId }); | ||
| // Findings linked to this row survive: the FK is SET NULL and each | ||
| // finding keeps its own clauseOrControl text as the frozen label. | ||
| await tx.ismsAuditControl.delete({ where: { id: controlId } }); |
There was a problem hiding this comment.
P2: Deleting a control can leave a linked finding with no control reference when its API request omitted optional clauseOrControl; the FK clears controlId and no frozen label is populated. Preserve control.controlRef for linked findings with a null label before deleting, or require/derive that label when creating linked findings.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/isms/isms-audit-control.service.ts, line 103:
<comment>Deleting a control can leave a linked finding with no control reference when its API request omitted optional `clauseOrControl`; the FK clears `controlId` and no frozen label is populated. Preserve `control.controlRef` for linked findings with a null label before deleting, or require/derive that label when creating linked findings.</comment>
<file context>
@@ -0,0 +1,165 @@
+ await invalidateApprovalIfNeeded({ tx, documentId: control.documentId });
+ // Findings linked to this row survive: the FK is SET NULL and each
+ // finding keeps its own clauseOrControl text as the frozen label.
+ await tx.ismsAuditControl.delete({ where: { id: controlId } });
+ });
+ return { success: true };
</file context>
| controlRef: '', | ||
| whatWasTested: '', | ||
| whereToFind: '', | ||
| notes: '', |
There was a problem hiding this comment.
P3: New control rows always save with blank notes because this form has no Notes field, despite the table exposing that column. Add the optional notes input so auditors can record it when creating the row rather than requiring a second edit.
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]/documents/isms/components/AuditControlsTable.tsx, line 44:
<comment>New control rows always save with blank notes because this form has no Notes field, despite the table exposing that column. Add the optional notes input so auditors can record it when creating the row rather than requiring a second edit.</comment>
<file context>
@@ -0,0 +1,202 @@
+ controlRef: '',
+ whatWasTested: '',
+ whereToFind: '',
+ notes: '',
+};
+
</file context>
| } | ||
| } | ||
|
|
||
| private async assertInternalAuditComplete({ |
There was a problem hiding this comment.
P3: ISMS service now exceeds the repository's 300-line file limit by more than 2x, making the lifecycle and validation responsibilities harder to maintain. Move Internal Audit validation/provisioning behavior into a focused helper/service module and retain a small delegation here.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/isms/isms.service.ts, line 575:
<comment>ISMS service now exceeds the repository's 300-line file limit by more than 2x, making the lifecycle and validation responsibilities harder to maintain. Move Internal Audit validation/provisioning behavior into a focused helper/service module and retain a small delegation here.</comment>
<file context>
@@ -525,6 +572,25 @@ export class IsmsService {
}
}
+ private async assertInternalAuditComplete({
+ tx,
+ documentId,
</file context>
| control={control} | ||
| name="controlRef" | ||
| render={({ field: { ref: _ref, ...field } }) => ( | ||
| <Input {...field} aria-label="Control reference" /> |
There was a problem hiding this comment.
P3: Clearing the required control reference leaves Save disabled without any validation feedback, so users cannot tell what needs fixing. Render the controlRef field error (and ideally invalid state) in this edit row, matching the create form.
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]/documents/isms/components/AuditControlRow.tsx, line 143:
<comment>Clearing the required control reference leaves Save disabled without any validation feedback, so users cannot tell what needs fixing. Render the `controlRef` field error (and ideally invalid state) in this edit row, matching the create form.</comment>
<file context>
@@ -0,0 +1,282 @@
+ control={control}
+ name="controlRef"
+ render={({ field: { ref: _ref, ...field } }) => (
+ <Input {...field} aria-label="Control reference" />
+ )}
+ />
</file context>
| /> | ||
| </Field> | ||
| ) : ( | ||
| <Text size="sm">{programme || 'No programme recorded yet.'}</Text> |
There was a problem hiding this comment.
P3: Multi-line programme edits lose paragraph/line-break formatting in the read view because normal text rendering collapses newlines. Preserve whitespace when displaying the saved textarea value so it matches the entered/generated document content.
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]/documents/isms/components/ProgrammeCard.tsx, line 132:
<comment>Multi-line programme edits lose paragraph/line-break formatting in the read view because normal text rendering collapses newlines. Preserve whitespace when displaying the saved textarea value so it matches the entered/generated document content.</comment>
<file context>
@@ -0,0 +1,136 @@
+ />
+ </Field>
+ ) : (
+ <Text size="sm">{programme || 'No programme recorded yet.'}</Text>
+ )}
+ </IsmsRegisterCard>
</file context>
|
|
||
| const values = toFormValues(audit); | ||
| const signedCount = SLOTS.filter( | ||
| (slot) => values[slot.nameField] && values[slot.dateField], |
There was a problem hiding this comment.
P3: The signed badge can report a completed slot for a whitespace-only signatory name, although the API normalizes that name to null. Trim the name for this completeness check so badge and generated sign-off state agree.
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]/documents/isms/components/AuditSignoffCard.tsx, line 142:
<comment>The signed badge can report a completed slot for a whitespace-only signatory name, although the API normalizes that name to `null`. Trim the name for this completeness check so badge and generated sign-off state agree.</comment>
<file context>
@@ -0,0 +1,183 @@
+
+ const values = toFormValues(audit);
+ const signedCount = SLOTS.filter(
+ (slot) => values[slot.nameField] && values[slot.dateField],
+ ).length;
+
</file context>
…verwriting published (#3471) * fix(policies): create draft version on policy regenerate instead of overwriting published ## Problem When regenerating a policy, the published version's content is overwritten immediately. This bypasses the approval workflow that should gate any content changes. Regenerating a published policy currently mutates its live content, signedBy metadata, and currentVersionId directly without creating a draft for review. ## Root cause updatePolicyInDatabase in update-policy-helpers.ts rewrites policy.content, currentVersionId, and signedBy on the live published policy record without changing status or requiring approval. Every other content-change path (createVersion, submitForApproval, acceptChanges) creates a draft version first and only publishes on explicit approval; regenerate was the sole exception. ## Fix For published or needs_review policies, regenerate now creates a new draft version (incrementing the version number) with the regenerated content, leaving the published version's content, currentVersionId, signedBy, and status unchanged. This mirrors the existing approval workflow: draft versions are created, then approved, then published with the signing flow triggered for all employees. ## Explicitly NOT touched - Policies not yet published (status: draft) - The signing flow (runs only on explicit publish, unchanged) - Approval/rejection workflows - Version history or deletion logic ## Verification Added regression test asserting that regenerating a published policy creates a new draft version without modifying the published content or status. Existing policy regenerate and versioning unit tests pass locally ✅ * fix(bug-todo): address cubic review Address review findings. * fix(bug-todo): address cubic review Address review findings.
There was a problem hiding this comment.
1 issue found across 3 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/api/src/trigger/policies/update-policy-helpers.ts">
<violation number="1" location="apps/api/src/trigger/policies/update-policy-helpers.ts:113">
P2: Regenerating an uploaded draft now detaches its PDF without deleting the S3 object, leaving an orphaned document on every regeneration. Delete the old policy/current-version keys after the database update commits (deduplicating keys and retaining failures for cleanup).</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
| data: { | ||
| content: versionContent, | ||
| changelog: 'Regenerated policy content', | ||
| pdfUrl: null, |
There was a problem hiding this comment.
P2: Regenerating an uploaded draft now detaches its PDF without deleting the S3 object, leaving an orphaned document on every regeneration. Delete the old policy/current-version keys after the database update commits (deduplicating keys and retaining failures for cleanup).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/trigger/policies/update-policy-helpers.ts, line 113:
<comment>Regenerating an uploaded draft now detaches its PDF without deleting the S3 object, leaving an orphaned document on every regeneration. Delete the old policy/current-version keys after the database update commits (deduplicating keys and retaining failures for cleanup).</comment>
<file context>
@@ -75,79 +79,99 @@ export async function updatePolicyInDatabase(
+ data: {
+ content: versionContent,
+ changelog: 'Regenerated policy content',
+ pdfUrl: null,
+ },
});
</file context>
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
Ship Internal Audit (ISO 27001 clause 9.2, CS-724) for ISMS: adds a new document with an editable programme, audits register (IA-YYYY-NN), Controls Tested, findings, sign-off, export, and submit gates; includes a DB migration and UI/API changes. Also deploy security fixes: upgrade
adm-zipto ^0.6.0, pinengine.ioto ^6.6.7, bumpbody-parserto 2.3.0, and overridetarto ^7.5.19; and change policy regenerate to create a new draft version instead of overwriting the published policy.Written for commit ff31dbd. Summary will update on new commits.