Skip to content

feat(isms): internal audit programme, plan and report — clause 9.2 (CS-724) - #3468

Merged
tofikwest merged 6 commits into
mainfrom
tofik/cs-724-feature-area-internal-audit
Jul 21, 2026
Merged

tofikwest merged 6 commits into
mainfrom
tofik/cs-724-feature-area-internal-audit

Conversation

@github-actions

@github-actions github-actions Bot commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

This is an automated pull request to merge tofik/cs-724-feature-area-internal-audit into dev.
It was created by the [Auto Pull Request] action.


Summary by cubic

Adds the Internal Audit (ISO 27001 9.2) as a new ISMS document with programme, audits, controls, findings, sign‑off, and export (now including owner names and closure evidence), plus safety and UX fixes aligning with @trycompai/design-system; delivers CS-724.

  • New Features

    • New internal_audit document at Compliance > ISMS > Internal Audit; programme paragraph seeded atomically only when empty and editable.
    • Audits with IA-YYYY-NN refs, templated scope/criteria, auditor from Roles, planned dates, status, and conclusion verdict + notes.
    • Controls Tested table auto-seeded with 15 rows; result and notes per row; rows fully editable; non‑conformity/observation prompts a prefilled finding.
    • Findings with F-NN refs, type/owner/due/status/closure evidence, optional link to a control; three sign‑off slots captured and frozen in versions.
    • Export resolves finding owner names and appends closure evidence for closed findings to the description cell; document marked non‑drift; submit gate requires at least one audit and a conclusion verdict for completed audits.
    • Added DB enums/tables for audits, controls, and findings; template seeded.
  • Bug Fixes

    • Scoped audit/control/finding lookups to internal_audit; atomic programme seed via conditional update matching NULL or {} to avoid race and align with generate; trimmed required text fields.
    • Re-keyed linked‑finding prompt by control row + result so re‑marking a control re‑initializes correctly.
    • Prefilled clause text on finding edit; preserved unsaved sign‑off across refresh; gated control-row Save on validity; documented register bodies in OpenAPI; covered derivation path in tests.

Written for commit 36c2473. Summary will update on new commits.

Review in cubic

…S-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)
@linear

linear Bot commented Jul 21, 2026

Copy link
Copy Markdown

CS-724

@vercel

vercel Bot commented Jul 21, 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 Ready Ready Preview, Comment Jul 21, 2026 8:04pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
app Skipped Skipped Jul 21, 2026 8:04pm
portal Skipped Skipped Jul 21, 2026 8:04pm

Request Review

@tofikwest tofikwest changed the title [dev] [tofikwest] tofik/cs-724-feature-area-internal-audit feat(isms): internal audit programme, plan and report — clause 9.2 (CS-724) Jul 21, 2026
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.

@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.

cubic analysis

8 issues found and verified against the latest diff

Confidence score: 2/5

  • apps/api/src/isms/isms-registers.controller.ts remaps audit/finding mutations to evidence:update, which can grant evidence editors unintended write access and prevents proper custom-role scoping for audit/finding resources. This is the riskiest regression because it affects authorization boundaries — restore dedicated RBAC resources for audit/finding actions before merging.
  • apps/api/src/isms/registers/register-registry.ts accepts arbitrary auditor text, and apps/app/src/app/(app)/[orgId]/documents/isms/[type]/page.tsx deduplicates same-name auditors while storing only names, so records can be assigned to the wrong or non-holder person. That creates concrete data integrity and traceability issues in audit ownership — enforce Internal Auditor holder validation and persist/select by member ID before merging.
  • apps/api/src/isms/isms-audit.service.ts derives IA-YYYY-NN from remaining rows, so deleting the latest/only audit can cause reference reuse and duplicate-looking identifiers. Merging as-is risks confusing audit history and downstream references — persist a monotonic per-year sequence (or equivalent) before merge.
  • apps/api/src/isms/documents/generate.ts introduces a new regeneration/approval dispatch path without runDerivation coverage, and related wording logic is split across API/UI (apps/api/src/isms/documents/internal-audit-defaults.ts), increasing the chance of silent generation or narrative drift regressions. Add focused derivation tests and consolidate/shared verdict text mapping to de-risk release.
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/isms/isms-audit.service.ts">

<violation number="1" location="apps/api/src/isms/isms-audit.service.ts:162">
P2: Deleting the only or highest audit for a year causes the next audit to reuse its `IA-YYYY-NN` reference because the sequence is derived solely from remaining rows. Persist the per-document/year sequence (or otherwise retain consumed references) if references must remain non-reusable as this service documents.</violation>
</file>

<file name="apps/app/src/app/(app)/[orgId]/documents/isms/components/AuditFindingFields.tsx">

<violation number="1" location="apps/app/src/app/(app)/[orgId]/documents/isms/components/AuditFindingFields.tsx:76">
P3: According to linked Linear issue CS-724, each finding type's plain-English explanation is specified as a tooltip; rendering it permanently below the selector changes the requested interaction and adds repeated vertical content to every finding form. Exposing this description through the design-system tooltip on the type control would match the requirement.</violation>

<violation number="2" location="apps/app/src/app/(app)/[orgId]/documents/isms/components/AuditFindingFields.tsx:91">
P2: According to linked Linear issue CS-724, the Clause or control field should pre-fill from the linked Controls Tested row; in edit mode, `AuditFindingRow` does not provide `onRelatedControlPicked`, so selecting a related control leaves this field unchanged. Passing the same prefill callback from the edit form (or moving the synchronization into this shared component) would keep linked findings consistent.</violation>
</file>

<file name="apps/api/src/isms/documents/generate.ts">

<violation number="1" location="apps/api/src/isms/documents/generate.ts:265">
P3: Internal Audit regeneration/approval now depends on this new dispatch path, but it has no `runDerivation` coverage. A later dispatch or narrative-preservation regression could make Clause 9.2 generation fail without a focused test detecting it; a small seed-and-preserve test would make this behavior explicit.</violation>
</file>

<file name="apps/app/src/app/(app)/[orgId]/documents/isms/[type]/page.tsx">

<violation number="1" location="apps/app/src/app/(app)/[orgId]/documents/isms/[type]/page.tsx:194">
P3: Audits cannot distinguish two Internal Auditor holders who share the same display name because this deduplication removes one option and the form stores only the name string. Preserving a member ID in the option/value (or disambiguating labels with a stable secondary identifier) would keep the dropdown selection unambiguous.</violation>
</file>

<file name="apps/api/src/isms/documents/internal-audit-defaults.ts">

<violation number="1" location="apps/api/src/isms/documents/internal-audit-defaults.ts:27">
P3: The API adds a second conclusion-verdict map and sentence builder while the same mapping/output already exists in the app, so UI and exported-document wording can drift when a verdict or copy changes. A shared typed constant/helper would keep both surfaces consistent.</violation>
</file>

<file name="apps/api/src/isms/registers/register-registry.ts">

<violation number="1" location="apps/api/src/isms/registers/register-registry.ts:201">
P2: According to linked Linear issue CS-724, Auditor must be pulled from the ISMS Roles > Internal Auditor assigned holder. This API accepts arbitrary auditor text, so a direct caller can save an auditor who is not the configured holder and the generated Clause 9.2 document will report the wrong person; resolving the current role assignment (or validating a submitted member/reference against it) would keep the audit tied to Roles.</violation>
</file>

<file name="apps/api/src/isms/isms-registers.controller.ts">

<violation number="1" location="apps/api/src/isms/isms-registers.controller.ts:202">
P1: Audit and finding mutations now inherit `evidence:update` rather than their dedicated RBAC resources, so custom roles cannot be scoped correctly and evidence editors may gain unintended audit/finding write access. Resolving permissions per register and operation (for example `audit:update` for audit rows and `finding:create|update|delete` for findings) would preserve the repository's resource-level RBAC model.</violation>
</file>

Linked issue analysis

Linked issue: CS-724: [Feature] Area- Internal Audit

Status Acceptance criteria Notes
✅ Programme paragraph seeded with auditor-defensible default, editable, and rendered verbatim into the generated document Default programme text function, derivation and seeding on document create, narrative schema, client ProgrammeCard and export mapping are present and tested.
✅ Audits register with server-generated IA-YYYY-NN reference and fields (scope, criteria defaults, auditor, planned dates, status, conclusion template) DB migration, Prisma model, service for audits, client audit form fields and default-scope/criteria constants are implemented and covered by tests.
✅ Controls Tested table seeded with the 15 default rows (idempotent by controlKey); editable rows and result dropdown exist Seed definitions and seed-if-missing function exist, CRUD service for audit controls added, UI components for the controls table/rows and constants for result enums included.
✅ Result dropdown saves and Notes editable; rows can be added/edited/deleted (seeded rows deletable) Control service implements create/update/delete, client components support inline editing and immediate saves; tests and register wiring present.
✅ Findings inline below Controls Tested with server-generated F-NN, types, optional related-control link, owner/due/status/closure fields DB model and migration for findings, finding service CRUD, client finding forms/UI, export mapping and tests are present.
✅ Sign-off: three slots (Auditor / SPO / Top Management) stored on audit and frozen into the version snapshot for export Sign-off fields added to DB model, client sign-off card exists, export code includes audits and sign-off in exported rows, and version/export wiring includes internal audit extras.
✅ Submit gate: at least one audit required and completed audits must have a conclusion verdict (server and client validation) Client validation messages mirror server rules; server lifecycle test blocks submission for no audits; document-level assertion and validation functions are implemented.
✅ Generated document export mirrors reference DOCX (Programme · Audit plan · Controls Tested · Findings · Conclusion · Sign-off) Export builders, mapping of controls/findings/sign-off, tests for export data and PDF/DOCX rendering verification are included.

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread apps/api/src/isms/isms-audit.service.ts Outdated
Comment thread apps/api/src/isms/isms-registers.controller.ts
Comment thread apps/api/src/isms/isms-audit.service.ts
Comment thread apps/api/src/isms/documents/generate.ts
Comment thread apps/app/src/app/(app)/[orgId]/documents/isms/[type]/page.tsx
Comment thread apps/api/src/isms/documents/internal-audit-defaults.ts
Comment thread apps/api/src/isms/registers/register-registry.ts
Comment thread apps/api/src/isms/registers/register-registry.ts Outdated
- 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

@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.

All reported issues were addressed across 15 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread apps/app/src/app/(app)/[orgId]/documents/isms/components/AuditFindingsSection.tsx Outdated
Comment thread apps/api/src/isms/isms.service.ts Outdated
Comment thread apps/api/src/isms/isms.service.ts Outdated
- 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

@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.

All reported issues were addressed across 3 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread apps/api/src/isms/isms.service.ts Outdated
…rate

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.
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.
@vercel
vercel Bot temporarily deployed to Preview – portal July 21, 2026 20:03 Inactive
@vercel
vercel Bot temporarily deployed to Preview – app July 21, 2026 20:03 Inactive
@tofikwest
tofikwest merged commit 42e5ebd into main Jul 21, 2026
9 checks passed
@tofikwest
tofikwest deleted the tofik/cs-724-feature-area-internal-audit branch July 21, 2026 20:14
claudfuen pushed a commit that referenced this pull request Jul 22, 2026
# [3.106.0](v3.105.0...v3.106.0) (2026-07-22)

### Bug Fixes

* **auth:** attribute API-key mutations to the key's creator, not the org owner ([#3472](#3472)) ([206ed96](206ed96)), closes [hi#risk](https://github.com/hi/issues/risk)
* **deps:** bump adm-zip 0.5.18 -> 0.6.0 in apps/api (Dependabot [#88](https://github.com/trycompai/comp/issues/88)/[#89](https://github.com/trycompai/comp/issues/89)) ([#3462](#3462)) ([300f2a1](300f2a1)), closes [#3451](#3451)
* **deps:** override tar to ^7.5.19 to clear node-tar Dependabot alerts ([#94](https://github.com/trycompai/comp/issues/94)-[#104](https://github.com/trycompai/comp/issues/104)) ([#3466](#3466)) ([8ab5709](8ab5709))
* **deps:** patch engine.io ([#93](#93)) and body-parser ([#92](#92)) Dependabot alerts ([#3464](#3464)) ([94c33b1](94c33b1))
* **isms:** harden internal-audit validation and edge cases from deploy review ([#3473](#3473)) ([c6c7379](c6c7379))
* **policies:** create draft version on policy regenerate instead of overwriting published ([#3471](#3471)) ([ff31dbd](ff31dbd))
* **policies:** delete detached PDF objects when regenerating a draft ([#3474](#3474)) ([ecd1bd0](ecd1bd0))
* **policies:** rename CreateVersionDto to avoid swagger collision with automations ([#3469](#3469)) ([2d5290a](2d5290a))

### Features

* **isms:** internal audit programme, plan and report — clause 9.2 (CS-724) ([#3468](#3468)) ([42e5ebd](42e5ebd)), closes [hi#impact](https://github.com/hi/issues/impact)
@claudfuen

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.106.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

This branch was successfully deployed

1 active and 2 inactive deployments
Preview – comp-framework-editor — 36c24737 Deployed Jul 21, 2026 by vercel[bot]
Preview – app — 36c24737 Deployed Jul 21, 2026 by vercel[bot]
Preview – portal — 36c24737 Deployed Jul 21, 2026 by vercel[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