Skip to content

Add risk assessment system#1171

Open
SachaProbo wants to merge 1 commit into
mainfrom
SachaProbo/risk-assessment
Open

Add risk assessment system#1171
SachaProbo wants to merge 1 commit into
mainfrom
SachaProbo/risk-assessment

Conversation

@SachaProbo
Copy link
Copy Markdown
Contributor

@SachaProbo SachaProbo commented May 11, 2026

Introduce a hierarchical risk assessment model with six entity types:

  • Risk Assessment: top-level container scoped to an organization
  • Risk Assessment Scope: sub-container for scoping threat modeling exercises within an assessment
  • Risk Assessment Node: DFD elements typed as ENTITY, BOUNDARY, ASSET, or DATA within a scope
  • Risk Assessment Process: directed data flows between two nodes
  • Risk Assessment Threat: descriptive threats attached to a process with a free-text category (e.g. Confidentiality, Integrity)
  • Risk Scenario: thin join linking a threat to a risk from the register, carrying only a name and description

Risk scoring (likelihood, impact, treatment) remains on the existing Risk entity. Threats are purely descriptive. Risk Scenarios connect the threat model to the risk register without duplicating scores.

Backend: migration with PG enum for node types, coredata structs, service layer with full CRUD and validation, GraphQL schema with 18 mutations and paginated connections, authorization actions and policies, and base_resolvers.go Node dispatch for all entity types.

Frontend: Risk Assessments list page with create dialog, detail page showing scopes as cards with nodes/processes/threats tables, inline create/edit/delete actions on all entities, and a Scenarios tab on the Risk detail page linking threats to risks. Existing RiskGraph.ts hook file removed in favor of colocated queries in page files.

E2E tests cover CRUD for all entity types, RBAC, and tenant isolation.

Deferred to follow-up PRs:

  • N8N/CLI/MCP
  • Front end graph

Summary by cubic

Introduces a complete risk assessment system with assessments, scopes, nodes, processes, threats, and scenarios, plus console UI and GraphQL API. Risk scoring stays on Risk; scenarios link threats to risks without duplicating scores.

  • New Features

    • Data model: Risk Assessment, Scope, Node (ENTITY/BOUNDARY/ASSET/DATA), Process, Threat, and Risk Scenario linking threats to risks.
    • Backend/API: pkg/coredata models and queries; pkg/riskmanagement service with validation and full CRUD; RBAC actions for all entities; GraphQL adds Organization riskAssessments and Risk scenarios connections, types, and 18 mutations; Node dispatch covers all new types; server wires the service (pkg/probod, pkg/server, GraphQL handler).
    • Console: Permission-gated sidebar and riskAssessmentRoutes; list/detail pages with inline create/edit/delete for scopes/nodes/processes/threats; Scenarios tab on Risk detail with create/delete; risks list/detail refactored with colocated queries/mutations; removed apps/console/src/hooks/graph/RiskGraph.ts.
    • Tests: E2E for CRUD, RBAC, and tenant isolation with new factory helpers.
  • Migration

    • Run DB migration 20260421T140001Z.sql.
    • Grant RBAC actions: core:risk-assessment:*, core:risk-assessment-scope:*, core:risk-assessment-node:*, core:risk-assessment-process:*, core:risk-assessment-threat:*, core:risk-scenario:*.
    • Redeploy console and API to load the new GraphQL schema/resolvers and pkg/riskmanagement wiring.

Written for commit 30ea177. Summary will update on new commits.

@SachaProbo SachaProbo marked this pull request as draft May 11, 2026 14:36
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.

11 issues found across 47 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/console/src/pages/organizations/risks/tabs/RiskScenariosTab.tsx">

<violation number="1" location="apps/console/src/pages/organizations/risks/tabs/RiskScenariosTab.tsx:91">
P2: Do not default Relay connection IDs to an empty string; use the `@connection` record directly so edge updates always target a valid connection.

(Based on your team's feedback about treating Relay `@connection` fields as non-null after `useFragment`.) [FEEDBACK_USED]</violation>
</file>

<file name="apps/console/src/pages/organizations/risk-assessments/RiskAssessmentDetailPage.tsx">

<violation number="1" location="apps/console/src/pages/organizations/risk-assessments/RiskAssessmentDetailPage.tsx:454">
P2: Edit dialogs can show stale values because `useForm` `defaultValues` are not updated when props change.</violation>
</file>

<file name="pkg/coredata/migrations/20260421T140001Z.sql">

<violation number="1" location="pkg/coredata/migrations/20260421T140001Z.sql:53">
P1: `risk_assessment_processes` can reference nodes from a different scope because FK constraints do not enforce scope consistency.</violation>

<violation number="2" location="pkg/coredata/migrations/20260421T140001Z.sql:66">
P1: `risk_assessment_threats` does not enforce that `process_id` belongs to the same scope as `risk_assessment_scope_id`.</violation>
</file>

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

<violation number="1" location="pkg/probo/risk_assessment_service.go:124">
P2: Add GID validation for `ProcessID` in threat updates; this relation field is mutable but currently unvalidated.</violation>

<violation number="2" location="pkg/probo/risk_assessment_service.go:124">
P2: Validate `SourceNodeID` and `TargetNodeID` in process updates; they are persisted but currently unchecked.</violation>
</file>

<file name="apps/console/src/pages/organizations/risks/RiskDetailPage.tsx">

<violation number="1" location="apps/console/src/pages/organizations/risks/RiskDetailPage.tsx:160">
P2: Handle mutation errors in the delete confirm flow; otherwise failed requests can leave the confirmation promise unresolved.</violation>
</file>

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

<violation number="1" location="pkg/coredata/risk_assessment.go:192">
P2: `RiskAssessment.Insert` returns raw DB errors instead of mapping unique violations to `ErrResourceAlreadyExists` like the other risk-assessment inserts, causing inconsistent error semantics.</violation>
</file>

<file name="pkg/server/api/console/v1/risk_assessment_resolvers.go">

<violation number="1" location="pkg/server/api/console/v1/risk_assessment_resolvers.go:226">
P1: Validate that source and target nodes belong to the provided risk assessment scope before creating a process.</violation>

<violation number="2" location="pkg/server/api/console/v1/risk_assessment_resolvers.go:296">
P1: Enforce that `process_id` belongs to `risk_assessment_scope_id` when creating or updating threats.</violation>

<violation number="3" location="pkg/server/api/console/v1/risk_assessment_resolvers.go:360">
P1: Authorize and validate `ThreatID` against the caller and ensure threat/risk belong to the same organization boundary before creating a scenario.</violation>
</file>

Tip: cubic used a learning from your PR history. Let your coding agent read cubic learnings directly with the cubic MCP.

Comment thread pkg/coredata/migrations/20260421T140001Z.sql
Comment thread pkg/coredata/migrations/20260421T140001Z.sql
Comment thread pkg/server/api/console/v1/risk_assessment_resolvers.go Outdated
Comment thread pkg/server/api/console/v1/risk_assessment_resolvers.go Outdated
Comment thread pkg/server/api/console/v1/risk_assessment_resolvers.go
Comment thread pkg/riskmanagement/service.go
Comment thread pkg/riskmanagement/service.go
Comment thread apps/console/src/pages/organizations/risks/RiskDetailPage.tsx
Comment thread pkg/coredata/risk_assessment.go Outdated
@SachaProbo SachaProbo force-pushed the SachaProbo/risk-assessment branch 6 times, most recently from fad84e5 to 2baabe5 Compare May 11, 2026 15:52
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit

eslint (apps/console)

🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 22 spaces but found 24 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 16 spaces but found 18 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 16 spaces but found 18 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent

title={`${__("Processes")} (${processes.length})`}


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent

hint={__("Data flows and interactions between nodes.")}


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 16 spaces but found 18 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent

nodes={nodes.map(n => ({ id: n.id, name: n.name }))}


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 16 spaces but found 18 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 16 spaces but found 18 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 22 spaces but found 24 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 22 spaces but found 24 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 22 spaces but found 24 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 22 spaces but found 24 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 22 spaces but found 24 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 24 spaces but found 26 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 24 spaces but found 26 @stylistic/indent

<Td className="text-txt-secondary">{nodeMap.get(process.sourceNodeId)?.name ?? "—"}</Td>


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 24 spaces but found 26 @stylistic/indent

<Td className="text-txt-secondary">{nodeMap.get(process.targetNodeId)?.name ?? "—"}</Td>


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 24 spaces but found 26 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 26 spaces but found 28 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 28 spaces but found 30 @stylistic/indent

process={{ id: process.id, name: process.name }}


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 28 spaces but found 30 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 26 spaces but found 28 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 24 spaces but found 26 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 22 spaces but found 24 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 22 spaces but found 24 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 24 spaces but found 26 @stylistic/indent

<Td colSpan={4} className="text-center text-txt-secondary">{__("No processes")}</Td>


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 22 spaces but found 24 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 16 spaces but found 18 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 14 spaces but found 16 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 16 spaces but found 18 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 16 spaces but found 18 @stylistic/indent

hint={__("Potential threats targeting a process. Link threats to risks via scenarios.")}


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 14 spaces but found 16 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 16 spaces but found 18 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent

processes={processes.map(p => ({ id: p.id, name: p.name }))}


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 16 spaces but found 18 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 14 spaces but found 16 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 14 spaces but found 16 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 16 spaces but found 18 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 16 spaces but found 18 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 16 spaces but found 18 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent

const process = processes.find(p => p.id === threat.processId);


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 22 spaces but found 24 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 24 spaces but found 26 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 24 spaces but found 26 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 24 spaces but found 26 @stylistic/indent

<Td className="text-txt-secondary">{process?.name ?? "—"}</Td>


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 24 spaces but found 26 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 26 spaces but found 28 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 28 spaces but found 30 @stylistic/indent

threat={{ id: threat.id, name: threat.name, category: threat.category }}


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 28 spaces but found 30 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 26 spaces but found 28 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 24 spaces but found 26 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 22 spaces but found 24 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 22 spaces but found 24 @stylistic/indent

<Td colSpan={4} className="text-center text-txt-secondary">{__("No threats")}</Td>


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 20 spaces but found 22 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 18 spaces but found 20 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 16 spaces but found 18 @stylistic/indent


🚫 [eslint (apps/console)] reported by reviewdog 🐶
Expected indentation of 14 spaces but found 16 @stylistic/indent

@SachaProbo SachaProbo force-pushed the SachaProbo/risk-assessment branch 6 times, most recently from 2f1345c to c822c7c Compare May 11, 2026 18:18
@SachaProbo SachaProbo marked this pull request as ready for review May 12, 2026 11:34
@SachaProbo SachaProbo requested a review from a team May 12, 2026 11:34
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.

4 issues found across 47 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/console/src/pages/organizations/risk-assessments/RiskAssessmentDetailPage.tsx">

<violation number="1" location="apps/console/src/pages/organizations/risk-assessments/RiskAssessmentDetailPage.tsx:438">
P2: Avoid nesting interactive controls inside the scope toggle button; move the actions dropdown outside the `<button>` element.</violation>
</file>

<file name="apps/console/src/pages/organizations/risk-assessments/RiskAssessmentsPage.tsx">

<violation number="1" location="apps/console/src/pages/organizations/risk-assessments/RiskAssessmentsPage.tsx:246">
P2: Provide a validation message for the required Name field; currently the form can fail validation without showing feedback.</violation>
</file>

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

<violation number="1" location="pkg/coredata/risk_assessment.go:56">
P1: Authorization attribute lookup is not tenant-scoped. Querying `risk_assessments` by ID alone can expose cross-tenant `organization_id` values during authorization evaluation; this should be constrained to the current tenant/scope.</violation>
</file>

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

<violation number="1" location="pkg/coredata/risk_assessment_node_type.go:68">
P2: `Scan` should handle `[]byte` sources in addition to `string`; otherwise enum reads can fail depending on driver return type.</violation>
</file>

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

Comment thread pkg/coredata/risk_assessment.go
Comment thread apps/console/src/pages/organizations/risk-assessments/RiskAssessmentsPage.tsx Outdated
Comment thread pkg/coredata/risk_assessment_node_type.go
Copy link
Copy Markdown
Contributor

@codenem codenem left a comment

Choose a reason for hiding this comment

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

We should stop creating a tab folder (I think it is already in the guides but if not we can add it)
We should not query all tab in a details page query. The details page ins actually a layout, and each tab is a page in its own folder representing its resources, this is in the guides already.

Comment thread apps/console/src/routes/riskAssessmentRoutes.ts Outdated
Comment thread apps/console/src/routes/riskAssessmentRoutes.ts Outdated
Comment thread apps/console/src/routes/riskAssessmentRoutes.ts Outdated
Comment thread apps/console/src/pages/organizations/risks/tabs/RiskScenariosTab.tsx Outdated
Copy link
Copy Markdown
Contributor

@codenem codenem left a comment

Choose a reason for hiding this comment

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

I think we should create pkg/risk or pkg/riskmanagement and put the service there like we've started to do with esign, third party, cookie banner etc.

@SachaProbo SachaProbo force-pushed the SachaProbo/risk-assessment branch 6 times, most recently from fdc5c0c to 4a5b842 Compare May 12, 2026 15:27
@SachaProbo SachaProbo force-pushed the SachaProbo/risk-assessment branch 4 times, most recently from 29d6f7f to 50ceaa6 Compare May 12, 2026 15:54
@SachaProbo
Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai please review

@cubic-dev-ai
Copy link
Copy Markdown
Contributor

cubic-dev-ai Bot commented May 12, 2026

@cubic-dev-ai please review

@SachaProbo I have started the AI code review. It will take a few minutes to complete.

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.

4 issues found across 65 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/console/src/pages/organizations/risk-assessments/_components/CreateThreatDialog.tsx">

<violation number="1" location="apps/console/src/pages/organizations/risk-assessments/_components/CreateThreatDialog.tsx:85">
P2: Add required validation to `processId` so submit shows a field error instead of silently returning.</violation>
</file>

<file name="apps/console/src/pages/organizations/risk-assessments/RiskAssessmentDetailPage.tsx">

<violation number="1" location="apps/console/src/pages/organizations/risk-assessments/RiskAssessmentDetailPage.tsx:120">
P1: Handle GraphQL errors in `onCompleted` before navigating; otherwise failed deletes can be treated as successful and the UI redirects incorrectly.</violation>
</file>

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

<violation number="1" location="pkg/coredata/risk_assessment_node.go:57">
P1: Authorization attribute lookup is not scope-constrained, which can leak cross-tenant resource existence.

(Based on your team's feedback about returning non-revealing NotFound behavior for cross-scope mismatches.) [FEEDBACK_USED]</violation>
</file>

<file name="pkg/riskmanagement/service.go">

<violation number="1" location="pkg/riskmanagement/service.go:981">
P1: `CreateScenario` does not verify that `threat_id` belongs to the same organization as `risk_id`, allowing cross-organization threat/risk links.</violation>
</file>

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

Comment thread pkg/coredata/risk_assessment_node.go
Comment thread pkg/riskmanagement/service.go
@SachaProbo SachaProbo force-pushed the SachaProbo/risk-assessment branch 2 times, most recently from 48e5cc8 to ddcf0a0 Compare May 12, 2026 16:16
Introduce a hierarchical risk assessment model with six entity types:

- Risk Assessment: top-level container scoped to an organization
- Risk Assessment Scope: sub-container for scoping threat modeling
  exercises within an assessment
- Risk Assessment Node: DFD elements typed as ENTITY, BOUNDARY,
  ASSET, or DATA within a scope
- Risk Assessment Process: directed data flows between two nodes
- Risk Assessment Threat: descriptive threats attached to a process
  with a free-text category (e.g. Confidentiality, Integrity)
- Risk Scenario: thin join linking a threat to a risk from the
  register, carrying only a name and description

Risk scoring (likelihood, impact, treatment) remains on the existing
Risk entity. Threats are purely descriptive. Risk Scenarios connect
the threat model to the risk register without duplicating scores.

Backend: migration with PG enum for node types, coredata structs,
service layer with full CRUD and validation, GraphQL schema with
18 mutations and paginated connections, authorization actions and
policies, and base_resolvers.go Node dispatch for all entity types.

Frontend: Risk Assessments list page with create dialog, detail page
showing scopes as cards with nodes/processes/threats tables, inline
create/edit/delete actions on all entities, and a Scenarios tab on
the Risk detail page linking threats to risks. Existing RiskGraph.ts
hook file removed in favor of colocated queries in page files.

E2E tests cover CRUD for all entity types, RBAC, and tenant
isolation.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
@SachaProbo SachaProbo force-pushed the SachaProbo/risk-assessment branch from ddcf0a0 to 30ea177 Compare May 12, 2026 16:20
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.

2 participants