Skip to content

Conversation

@SachaProbo
Copy link
Contributor

@SachaProbo SachaProbo commented Jan 5, 2026

Test-35.pdf

Summary by cubic

Introduces States of Applicability (SoA) to manage control states (implemented, not implemented, excluded) per framework. SoA can be snapshotted.

  • New Features

    • Console: new “States of Applicability” section with list and detail (overview + controls) pages.
    • Dialogs to link and edit controls with state and exclusion justification; framework-based control selection.
    • GraphQL: SoA types, connections, queries (list/node/forEdit), mutations (create/update/delete), totals, ordering and filtering; availableControls and link/unlink control mutations.
    • Backend: DB tables and enum for SoA and its controls; coredata models; services to list/count controls by SoA; entity registry; resolvers.
    • Controls: expose framework info for controls; queries support framework-based selection.
    • Snapshots: added STATES_OF_APPLICABILITY type and UI/helper updates to create and view SoA snapshots.
    • Export: generate and download SoA as PDF.
  • Migration

    • Run migrations 20260102T134633Z.sql and 20260108T123353Z.sql.
    • Grant new permissions: listStateOfApplicabilities and createStateOfApplicability.
    • No backfill required; SoAs are created going forward.

Written for commit 0b4aea9. Summary will update on new commits.

@SachaProbo SachaProbo force-pushed the add-soa-2 branch 9 times, most recently from 1c68fb0 to 975dcde Compare January 9, 2026 09:31
@SachaProbo SachaProbo marked this pull request as ready for review January 9, 2026 09:36
Copy link

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

11 issues found across 65 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="pkg/authz/permissions.go">

<violation number="1" location="pkg/authz/permissions.go:320">
P2: Permission inconsistency: `ActionListStateOfApplicabilities` uses `CoreRoles` at the Organization level, but entity-level read permissions use `NonEmployeeRoles`. This means Auditors can access individual SoA records but cannot list them. Consider using `NonEmployeeRoles` for consistency with entity-level permissions, similar to how Snapshots handle this.</violation>
</file>

<file name="apps/console/src/pages/organizations/state-of-applicabilities/StateOfApplicabilitiesPage.tsx">

<violation number="1" location="apps/console/src/pages/organizations/state-of-applicabilities/StateOfApplicabilitiesPage.tsx:66">
P2: `hasAnyAction` checks for `updateStateOfApplicability` permission, but the ActionDropdown only contains a delete action. If a user has update permission but not delete permission, they will see an Actions column with an empty dropdown. Either add an edit action to the dropdown, or remove the update permission check from `hasAnyAction`.</violation>
</file>

<file name="apps/console/src/routes/stateOfApplicabilityRoutes.ts">

<violation number="1" location="apps/console/src/routes/stateOfApplicabilityRoutes.ts:29">
P2: Inconsistent route path naming: `state-of-applicabilities` vs `states-of-applicability`. The snapshot routes use a different naming convention than the non-snapshot routes. Consider using consistent naming across all routes (e.g., all use `state-of-applicabilities`).</violation>
</file>

<file name="pkg/probo/state_of_applicability_service.go">

<violation number="1" location="pkg/probo/state_of_applicability_service.go:494">
P1: PDF generation is performed inside a database transaction, keeping the connection open during slow I/O. Move PDF generation outside the transaction by first fetching all required data, then closing the transaction, and finally generating the PDF.

(Based on your team's feedback about splitting data fetching and PDF generation.) [FEEDBACK_USED]</violation>
</file>

<file name="apps/console/src/components/form/StateOfApplicabilityControlsField.tsx">

<violation number="1" location="apps/console/src/components/form/StateOfApplicabilityControlsField.tsx:281">
P1: `useMemo` should not be used for side effects. This hook is meant for memoizing computed values, not triggering state updates. The `setFrameworkDataMap` call here may not execute reliably in React's StrictMode or with concurrent features. Use `useEffect` instead.</violation>
</file>

<file name="pkg/coredata/state_of_applicability_control_state.go">

<violation number="1" location="pkg/coredata/state_of_applicability_control_state.go:49">
P2: The `Scan` method does not validate the input against valid enum values. Unlike `MeasureState` which validates via `UnmarshalText`, this implementation silently accepts any string from the database. Consider adding validation to return an error for invalid values.</violation>
</file>

<file name="pkg/coredata/state_of_applicability_control.go">

<violation number="1" location="pkg/coredata/state_of_applicability_control.go:85">
P1: Query selects `tenant_id` but `StateOfApplicabilityControl` struct has no `TenantID` field. This will cause a runtime error with `pgx.RowToAddrOfStructByName`.</violation>

<violation number="2" location="pkg/coredata/state_of_applicability_control.go:136">
P0: Table name typo: `state_of_applicabilities_controls` should be `states_of_applicability_controls`. This will cause runtime errors as the table doesn't exist.</violation>
</file>

<file name="apps/console/src/pages/organizations/state-of-applicabilities/StateOfApplicabilityDetailPage.tsx">

<violation number="1" location="apps/console/src/pages/organizations/state-of-applicabilities/StateOfApplicabilityDetailPage.tsx:87">
P1: Navigation is called immediately after `deleteStateOfApplicability()`, but the delete shows a confirmation dialog and performs the mutation asynchronously. The user will be navigated away before they can even interact with the confirmation dialog. The navigation should only happen after successful deletion, not immediately when `onDelete` is triggered. Consider modifying `useDeleteStateOfApplicability` to accept an `onSuccess` callback, or handle navigation within the hook itself.</violation>
</file>

<file name="apps/console/src/pages/organizations/state-of-applicabilities/dialogs/EditControlDialog.tsx">

<violation number="1" location="apps/console/src/pages/organizations/state-of-applicabilities/dialogs/EditControlDialog.tsx:159">
P1: Cancel button inside form will trigger form submission. Add `type="button"` to prevent the default submit behavior.</violation>
</file>

<file name="pkg/coredata/migrations/20260102T134633Z.sql">

<violation number="1" location="pkg/coredata/migrations/20260102T134633Z.sql:33">
P2: Unique constraint on `(name, snapshot_id)` won't prevent duplicate names when `snapshot_id` is NULL because PostgreSQL treats NULL values as distinct. Consider using a partial unique index or `NULLS NOT DISTINCT` (PostgreSQL 15+):

```sql
CREATE UNIQUE INDEX states_of_applicability_name_tenant_uniq 
  ON states_of_applicability (name, tenant_id) 
  WHERE snapshot_id IS NULL;

Also consider including tenant_id in uniqueness constraints for proper multi-tenant isolation.


</details>

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

@SachaProbo SachaProbo force-pushed the add-soa-2 branch 6 times, most recently from 1417c4f to fc18a7a Compare January 9, 2026 09:58
Signed-off-by: Sacha Al Himdani <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants