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>
460 lines
12 KiB
GraphQL
460 lines
12 KiB
GraphQL
enum ControlMaturityLevel
|
|
@goModel(model: "go.probo.inc/probo/pkg/coredata.ControlMaturityLevel") {
|
|
NONE
|
|
@goEnum(
|
|
value: "go.probo.inc/probo/pkg/coredata.ControlMaturityLevelNone"
|
|
)
|
|
INITIAL
|
|
@goEnum(
|
|
value: "go.probo.inc/probo/pkg/coredata.ControlMaturityLevelInitial"
|
|
)
|
|
MANAGED
|
|
@goEnum(
|
|
value: "go.probo.inc/probo/pkg/coredata.ControlMaturityLevelManaged"
|
|
)
|
|
DEFINED
|
|
@goEnum(
|
|
value: "go.probo.inc/probo/pkg/coredata.ControlMaturityLevelDefined"
|
|
)
|
|
QUANTITATIVELY_MANAGED
|
|
@goEnum(
|
|
value: "go.probo.inc/probo/pkg/coredata.ControlMaturityLevelQuantitativelyManaged"
|
|
)
|
|
OPTIMIZING
|
|
@goEnum(
|
|
value: "go.probo.inc/probo/pkg/coredata.ControlMaturityLevelOptimizing"
|
|
)
|
|
}
|
|
|
|
enum ControlOrderField
|
|
@goModel(model: "go.probo.inc/probo/pkg/coredata.ControlOrderField") {
|
|
CREATED_AT
|
|
@goEnum(
|
|
value: "go.probo.inc/probo/pkg/coredata.ControlOrderFieldCreatedAt"
|
|
)
|
|
SECTION_TITLE
|
|
@goEnum(
|
|
value: "go.probo.inc/probo/pkg/coredata.ControlOrderFieldSectionTitle"
|
|
)
|
|
}
|
|
|
|
enum ApplicabilityStatementOrderField
|
|
@goModel(model: "go.probo.inc/probo/pkg/coredata.ApplicabilityStatementOrderField") {
|
|
CREATED_AT
|
|
@goEnum(
|
|
value: "go.probo.inc/probo/pkg/coredata.ApplicabilityStatementOrderFieldCreatedAt"
|
|
)
|
|
CONTROL_SECTION_TITLE
|
|
@goEnum(
|
|
value: "go.probo.inc/probo/pkg/coredata.ApplicabilityStatementOrderFieldControlSectionTitle"
|
|
)
|
|
}
|
|
|
|
enum StatementOfApplicabilityOrderField
|
|
@goModel(
|
|
model: "go.probo.inc/probo/pkg/coredata.StatementOfApplicabilityOrderField"
|
|
) {
|
|
NAME
|
|
@goEnum(
|
|
value: "go.probo.inc/probo/pkg/coredata.StatementOfApplicabilityOrderFieldName"
|
|
)
|
|
CREATED_AT
|
|
@goEnum(
|
|
value: "go.probo.inc/probo/pkg/coredata.StatementOfApplicabilityOrderFieldCreatedAt"
|
|
)
|
|
}
|
|
|
|
input ControlOrder
|
|
@goModel(
|
|
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ControlOrderBy"
|
|
) {
|
|
direction: OrderDirection!
|
|
field: ControlOrderField!
|
|
}
|
|
|
|
input ApplicabilityStatementOrder
|
|
@goModel(
|
|
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ApplicabilityStatementOrderBy"
|
|
) {
|
|
direction: OrderDirection!
|
|
field: ApplicabilityStatementOrderField!
|
|
}
|
|
|
|
input StatementOfApplicabilityOrder
|
|
@goModel(
|
|
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.StatementOfApplicabilityOrderBy"
|
|
) {
|
|
direction: OrderDirection!
|
|
field: StatementOfApplicabilityOrderField!
|
|
}
|
|
|
|
input ControlFilter {
|
|
query: String
|
|
}
|
|
|
|
type Control implements Node {
|
|
id: ID!
|
|
organization: Organization @goField(forceResolver: true)
|
|
sectionTitle: String!
|
|
name: String!
|
|
description: String
|
|
bestPractice: Boolean!
|
|
notImplementedJustification: String
|
|
maturityLevel: ControlMaturityLevel!
|
|
regulatory: Boolean! @goField(forceResolver: true)
|
|
contractual: Boolean! @goField(forceResolver: true)
|
|
riskAssessment: Boolean! @goField(forceResolver: true)
|
|
|
|
framework: Framework! @goField(forceResolver: true)
|
|
|
|
measures(
|
|
first: Int
|
|
after: CursorKey
|
|
last: Int
|
|
before: CursorKey
|
|
orderBy: MeasureOrder
|
|
filter: MeasureFilter
|
|
): MeasureConnection! @goField(forceResolver: true)
|
|
|
|
documents(
|
|
first: Int
|
|
after: CursorKey
|
|
last: Int
|
|
before: CursorKey
|
|
orderBy: DocumentOrder
|
|
filter: DocumentFilter
|
|
): DocumentConnection! @goField(forceResolver: true)
|
|
|
|
audits(
|
|
first: Int
|
|
after: CursorKey
|
|
last: Int
|
|
before: CursorKey
|
|
orderBy: AuditOrder
|
|
): AuditConnection! @goField(forceResolver: true)
|
|
|
|
obligations(
|
|
first: Int
|
|
after: CursorKey
|
|
last: Int
|
|
before: CursorKey
|
|
orderBy: ObligationOrder
|
|
): ObligationConnection! @goField(forceResolver: true)
|
|
|
|
createdAt: Datetime!
|
|
updatedAt: Datetime!
|
|
|
|
permission(action: String!): Boolean! @goField(forceResolver: true)
|
|
}
|
|
|
|
type ControlConnection
|
|
@goModel(
|
|
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ControlConnection"
|
|
) {
|
|
totalCount: Int! @goField(forceResolver: true)
|
|
edges: [ControlEdge!]!
|
|
pageInfo: PageInfo!
|
|
}
|
|
|
|
type ControlEdge {
|
|
cursor: CursorKey!
|
|
node: Control!
|
|
}
|
|
|
|
type StatementOfApplicability implements Node {
|
|
id: ID!
|
|
name: String!
|
|
document: Document @goField(forceResolver: true)
|
|
organization: Organization @goField(forceResolver: true)
|
|
createdAt: Datetime!
|
|
updatedAt: Datetime!
|
|
|
|
applicabilityStatements(
|
|
first: Int
|
|
after: CursorKey
|
|
last: Int
|
|
before: CursorKey
|
|
orderBy: ApplicabilityStatementOrder
|
|
): ApplicabilityStatementConnection! @goField(forceResolver: true)
|
|
|
|
permission(action: String!): Boolean! @goField(forceResolver: true)
|
|
}
|
|
|
|
type ApplicabilityStatementConnection
|
|
@goModel(
|
|
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ApplicabilityStatementConnection"
|
|
) {
|
|
totalCount: Int! @goField(forceResolver: true)
|
|
edges: [ApplicabilityStatementEdge!]!
|
|
pageInfo: PageInfo!
|
|
}
|
|
|
|
type ApplicabilityStatementEdge {
|
|
cursor: CursorKey!
|
|
node: ApplicabilityStatement!
|
|
}
|
|
|
|
type ApplicabilityStatement implements Node {
|
|
id: ID!
|
|
statementOfApplicability: StatementOfApplicability! @goField(forceResolver: true)
|
|
control: Control! @goField(forceResolver: true)
|
|
applicability: Boolean!
|
|
justification: String!
|
|
createdAt: Datetime!
|
|
updatedAt: Datetime!
|
|
|
|
permission(action: String!): Boolean! @goField(forceResolver: true)
|
|
}
|
|
|
|
type StatementOfApplicabilityConnection
|
|
@goModel(
|
|
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.StatementOfApplicabilityConnection"
|
|
) {
|
|
totalCount: Int! @goField(forceResolver: true)
|
|
edges: [StatementOfApplicabilityEdge!]!
|
|
pageInfo: PageInfo!
|
|
}
|
|
|
|
type StatementOfApplicabilityEdge {
|
|
cursor: CursorKey!
|
|
node: StatementOfApplicability!
|
|
}
|
|
|
|
extend type Mutation {
|
|
createControl(input: CreateControlInput!): CreateControlPayload!
|
|
updateControl(input: UpdateControlInput!): UpdateControlPayload!
|
|
deleteControl(input: DeleteControlInput!): DeleteControlPayload!
|
|
createControlMeasureMapping(
|
|
input: CreateControlMeasureMappingInput!
|
|
): CreateControlMeasureMappingPayload!
|
|
createControlDocumentMapping(
|
|
input: CreateControlDocumentMappingInput!
|
|
): CreateControlDocumentMappingPayload!
|
|
deleteControlMeasureMapping(
|
|
input: DeleteControlMeasureMappingInput!
|
|
): DeleteControlMeasureMappingPayload!
|
|
deleteControlDocumentMapping(
|
|
input: DeleteControlDocumentMappingInput!
|
|
): DeleteControlDocumentMappingPayload!
|
|
createApplicabilityStatement(
|
|
input: CreateApplicabilityStatementInput!
|
|
): CreateApplicabilityStatementPayload!
|
|
updateApplicabilityStatement(
|
|
input: UpdateApplicabilityStatementInput!
|
|
): UpdateApplicabilityStatementPayload!
|
|
deleteApplicabilityStatement(
|
|
input: DeleteApplicabilityStatementInput!
|
|
): DeleteApplicabilityStatementPayload!
|
|
createControlAuditMapping(
|
|
input: CreateControlAuditMappingInput!
|
|
): CreateControlAuditMappingPayload
|
|
deleteControlAuditMapping(
|
|
input: DeleteControlAuditMappingInput!
|
|
): DeleteControlAuditMappingPayload
|
|
createControlObligationMapping(
|
|
input: CreateControlObligationMappingInput!
|
|
): CreateControlObligationMappingPayload!
|
|
deleteControlObligationMapping(
|
|
input: DeleteControlObligationMappingInput!
|
|
): DeleteControlObligationMappingPayload!
|
|
createStatementOfApplicability(
|
|
input: CreateStatementOfApplicabilityInput!
|
|
): CreateStatementOfApplicabilityPayload!
|
|
updateStatementOfApplicability(
|
|
input: UpdateStatementOfApplicabilityInput!
|
|
): UpdateStatementOfApplicabilityPayload!
|
|
deleteStatementOfApplicability(
|
|
input: DeleteStatementOfApplicabilityInput!
|
|
): DeleteStatementOfApplicabilityPayload!
|
|
publishStatementOfApplicability(
|
|
input: PublishStatementOfApplicabilityInput!
|
|
): PublishStatementOfApplicabilityPayload!
|
|
}
|
|
|
|
input CreateControlInput {
|
|
frameworkId: ID!
|
|
sectionTitle: String!
|
|
name: String!
|
|
description: String
|
|
bestPractice: Boolean!
|
|
maturityLevel: ControlMaturityLevel!
|
|
notImplementedJustification: String
|
|
}
|
|
|
|
input UpdateControlInput {
|
|
id: ID!
|
|
sectionTitle: String
|
|
name: String
|
|
description: String @goField(omittable: true)
|
|
bestPractice: Boolean
|
|
maturityLevel: ControlMaturityLevel
|
|
notImplementedJustification: String @goField(omittable: true)
|
|
}
|
|
|
|
input DeleteControlInput {
|
|
controlId: ID!
|
|
}
|
|
|
|
input CreateControlMeasureMappingInput {
|
|
controlId: ID!
|
|
measureId: ID!
|
|
}
|
|
|
|
input CreateControlDocumentMappingInput {
|
|
controlId: ID!
|
|
documentId: ID!
|
|
}
|
|
|
|
input DeleteControlMeasureMappingInput {
|
|
controlId: ID!
|
|
measureId: ID!
|
|
}
|
|
|
|
input DeleteControlDocumentMappingInput {
|
|
controlId: ID!
|
|
documentId: ID!
|
|
}
|
|
|
|
input CreateApplicabilityStatementInput {
|
|
statementOfApplicabilityId: ID!
|
|
controlId: ID!
|
|
applicability: Boolean!
|
|
justification: String
|
|
}
|
|
|
|
input UpdateApplicabilityStatementInput {
|
|
applicabilityStatementId: ID!
|
|
applicability: Boolean!
|
|
justification: String
|
|
}
|
|
|
|
input DeleteApplicabilityStatementInput {
|
|
applicabilityStatementId: ID!
|
|
}
|
|
|
|
input CreateControlAuditMappingInput {
|
|
controlId: ID!
|
|
auditId: ID!
|
|
}
|
|
|
|
input DeleteControlAuditMappingInput {
|
|
controlId: ID!
|
|
auditId: ID!
|
|
}
|
|
|
|
input CreateControlObligationMappingInput {
|
|
controlId: ID!
|
|
obligationId: ID!
|
|
}
|
|
|
|
input DeleteControlObligationMappingInput {
|
|
controlId: ID!
|
|
obligationId: ID!
|
|
}
|
|
|
|
input CreateStatementOfApplicabilityInput {
|
|
organizationId: ID!
|
|
name: String!
|
|
}
|
|
|
|
input UpdateStatementOfApplicabilityInput {
|
|
id: ID!
|
|
name: String
|
|
}
|
|
|
|
input ApplicabilityStatementInput {
|
|
controlId: ID!
|
|
applicability: Boolean!
|
|
justification: String
|
|
}
|
|
|
|
input DeleteStatementOfApplicabilityInput {
|
|
statementOfApplicabilityId: ID!
|
|
}
|
|
|
|
input PublishStatementOfApplicabilityInput {
|
|
statementOfApplicabilityId: ID!
|
|
approverIds: [ID!]
|
|
}
|
|
|
|
type CreateControlPayload {
|
|
controlEdge: ControlEdge!
|
|
}
|
|
|
|
type UpdateControlPayload {
|
|
control: Control!
|
|
}
|
|
|
|
type DeleteControlPayload {
|
|
deletedControlId: ID!
|
|
}
|
|
|
|
type CreateControlMeasureMappingPayload {
|
|
controlEdge: ControlEdge!
|
|
measureEdge: MeasureEdge!
|
|
}
|
|
|
|
type CreateControlDocumentMappingPayload {
|
|
controlEdge: ControlEdge!
|
|
documentEdge: DocumentEdge!
|
|
}
|
|
|
|
type DeleteControlMeasureMappingPayload {
|
|
deletedControlId: ID!
|
|
deletedMeasureId: ID!
|
|
}
|
|
|
|
type DeleteControlDocumentMappingPayload {
|
|
deletedControlId: ID!
|
|
deletedDocumentId: ID!
|
|
}
|
|
|
|
type CreateApplicabilityStatementPayload {
|
|
applicabilityStatementEdge: ApplicabilityStatementEdge!
|
|
}
|
|
|
|
type UpdateApplicabilityStatementPayload {
|
|
applicabilityStatement: ApplicabilityStatement!
|
|
}
|
|
|
|
type DeleteApplicabilityStatementPayload {
|
|
deletedApplicabilityStatementId: ID!
|
|
}
|
|
|
|
type CreateControlAuditMappingPayload {
|
|
controlEdge: ControlEdge
|
|
auditEdge: AuditEdge
|
|
}
|
|
|
|
type DeleteControlAuditMappingPayload {
|
|
deletedControlId: ID
|
|
deletedAuditId: ID
|
|
}
|
|
|
|
type CreateControlObligationMappingPayload {
|
|
controlEdge: ControlEdge!
|
|
obligationEdge: ObligationEdge!
|
|
}
|
|
|
|
type DeleteControlObligationMappingPayload {
|
|
deletedControlId: ID!
|
|
deletedObligationId: ID!
|
|
}
|
|
|
|
type CreateStatementOfApplicabilityPayload {
|
|
statementOfApplicabilityEdge: StatementOfApplicabilityEdge!
|
|
}
|
|
|
|
type UpdateStatementOfApplicabilityPayload {
|
|
statementOfApplicability: StatementOfApplicability!
|
|
}
|
|
|
|
type DeleteStatementOfApplicabilityPayload {
|
|
deletedStatementOfApplicabilityId: ID!
|
|
}
|
|
|
|
type PublishStatementOfApplicabilityPayload {
|
|
documentEdge: DocumentEdge!
|
|
documentVersionEdge: DocumentVersionEdge!
|
|
}
|