Add risk publish to document system
Replace the old snapshot-based system for risks with the publish document system, mirroring the prior vendor / processing activity / DPIA / TIA migration. Includes the GraphQL mutation, MCP tool, CLI command, n8n operation, frontend publish dialog, e2e tests, and a prosemirror register template covering name, description, category, treatment, owner, inherent and residual scoring, and notes. The risk register lives as a generated DocumentTypeRegister document on the organization, reused across publishes (the major version bumps on every republish). Approvers can be passed in to create a draft pending approval; otherwise the version is published immediately. The frontend Risks page exposes a Publish button and a Document link button when the document exists, and pre-fills the previous default approvers. Risks was the last remaining snapshot type, so this commit also removes the entire snapshot system: drop snapshotId from the Risk GraphQL type and RiskFilter; remove RiskSnapshotter, Risks.Snapshot, InsertRiskSnapshots, and the SnapshotID/SourceID fields on Risk; delete Snapshot, ControlSnapshot, SnapshotsType, SnapshotOrderField, Snapshottable, the SnapshotService, the Snapshot console resolvers and GraphQL schema, the Snapshot MCP types and operations (list/get/take/listControlSnapshots), the snapshot CLI (prb snapshot), the snapshot frontend pages, routes, banner, LinkedSnapshotsCard, SnapshotGraph, snapshot helpers, and the snapshot n8n resource and control link/unlink snapshot operations. The snapshot_id columns remain in the database but are now filtered out with snapshot_id IS NULL. Add Get/Upsert/Clear GeneratedDocumentID methods on Risk backed by a new risks_document_id column on generated_documents, matching the ProcessingActivity/Finding/Vendor pattern. The migration command migrate-risk-snapshots-to-documents uses raw SQL queries instead of the Go snapshot types, since those are gone. Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
@@ -582,144 +582,6 @@ func TestControlAuditMapping_CreateDelete(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestControlSnapshotMapping_CreateDelete(t *testing.T) {
|
||||
t.Parallel()
|
||||
owner := testutil.NewClient(t, testutil.RoleOwner)
|
||||
|
||||
// Create a framework and control
|
||||
var createFrameworkResult struct {
|
||||
CreateFramework struct {
|
||||
FrameworkEdge struct {
|
||||
Node struct {
|
||||
ID string `json:"id"`
|
||||
} `json:"node"`
|
||||
} `json:"frameworkEdge"`
|
||||
} `json:"createFramework"`
|
||||
}
|
||||
err := owner.Execute(`
|
||||
mutation($input: CreateFrameworkInput!) {
|
||||
createFramework(input: $input) {
|
||||
frameworkEdge {
|
||||
node {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`, map[string]any{
|
||||
"input": map[string]any{
|
||||
"organizationId": owner.GetOrganizationID().String(),
|
||||
"name": "Framework for ControlSnapshot Mapping",
|
||||
},
|
||||
}, &createFrameworkResult)
|
||||
require.NoError(t, err)
|
||||
frameworkID := createFrameworkResult.CreateFramework.FrameworkEdge.Node.ID
|
||||
|
||||
var createControlResult struct {
|
||||
CreateControl struct {
|
||||
ControlEdge struct {
|
||||
Node struct {
|
||||
ID string `json:"id"`
|
||||
} `json:"node"`
|
||||
} `json:"controlEdge"`
|
||||
} `json:"createControl"`
|
||||
}
|
||||
err = owner.Execute(`
|
||||
mutation($input: CreateControlInput!) {
|
||||
createControl(input: $input) {
|
||||
controlEdge {
|
||||
node {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`, map[string]any{
|
||||
"input": map[string]any{
|
||||
"frameworkId": frameworkID,
|
||||
"name": "Control for Snapshot Mapping",
|
||||
"description": "Test control",
|
||||
"sectionTitle": "Section 1",
|
||||
"bestPractice": true,
|
||||
"maturityLevel": "INITIAL",
|
||||
},
|
||||
}, &createControlResult)
|
||||
require.NoError(t, err)
|
||||
controlID := createControlResult.CreateControl.ControlEdge.Node.ID
|
||||
|
||||
// Create a snapshot
|
||||
var createSnapshotResult struct {
|
||||
CreateSnapshot struct {
|
||||
SnapshotEdge struct {
|
||||
Node struct {
|
||||
ID string `json:"id"`
|
||||
} `json:"node"`
|
||||
} `json:"snapshotEdge"`
|
||||
} `json:"createSnapshot"`
|
||||
}
|
||||
err = owner.Execute(`
|
||||
mutation($input: CreateSnapshotInput!) {
|
||||
createSnapshot(input: $input) {
|
||||
snapshotEdge {
|
||||
node {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`, map[string]any{
|
||||
"input": map[string]any{
|
||||
"organizationId": owner.GetOrganizationID().String(),
|
||||
"name": "Snapshot for Control Mapping",
|
||||
"type": "RISKS",
|
||||
},
|
||||
}, &createSnapshotResult)
|
||||
require.NoError(t, err)
|
||||
snapshotID := createSnapshotResult.CreateSnapshot.SnapshotEdge.Node.ID
|
||||
|
||||
t.Run("create mapping", func(t *testing.T) {
|
||||
_, err := owner.Do(`
|
||||
mutation($input: CreateControlSnapshotMappingInput!) {
|
||||
createControlSnapshotMapping(input: $input) {
|
||||
controlEdge {
|
||||
node {
|
||||
id
|
||||
}
|
||||
}
|
||||
snapshotEdge {
|
||||
node {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`, map[string]any{
|
||||
"input": map[string]any{
|
||||
"controlId": controlID,
|
||||
"snapshotId": snapshotID,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("delete mapping", func(t *testing.T) {
|
||||
_, err := owner.Do(`
|
||||
mutation($input: DeleteControlSnapshotMappingInput!) {
|
||||
deleteControlSnapshotMapping(input: $input) {
|
||||
deletedControlId
|
||||
deletedSnapshotId
|
||||
}
|
||||
}
|
||||
`, map[string]any{
|
||||
"input": map[string]any{
|
||||
"controlId": controlID,
|
||||
"snapshotId": snapshotID,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRiskDocumentMapping_CreateDelete(t *testing.T) {
|
||||
t.Parallel()
|
||||
owner := testutil.NewClient(t, testutil.RoleOwner)
|
||||
|
||||
Reference in New Issue
Block a user