1// SPDX-License-Identifier: Apache-2.0
2
3// Schema lifecycle: experimental | stable | deprecated
4@status("experimental")
5package gemara
6
7import "list"
8
9@go(gemara)
10
11// A RiskCatalog is a structured collection of documented risks that may affect an organization,
12// system, or service. It provides a centralized reference for risks that can be mapped to threats
13// and referenced by policies when documenting how those risks are mitigated or accepted.
14#RiskCatalog: {
15 #Catalog
16 metadata: type: "RiskCatalog"
17
18 // groups narrows the base groups to risk categories with appetite and severity boundaries
19 groups?: [#RiskCategory, ...#RiskCategory]
20
21 // risks is a list of risks defined by this catalog
22 risks?: [#Risk, ...#Risk] @go(Risks)
23
24 if risks != _|_ {
25 _uniqueRiskIds: {for i, r in risks {(r.id): i}}
26 // Each distinct rank value may appear at most once among risks that set rank (partial ranking allowed).
27 // Keys are stringified ranks because CUE struct labels cannot be raw integers.
28 _uniqueRiskRanks: {for i, r in risks if r.rank != _|_ {"\(r.rank)": i}}
29 groups: [#RiskCategory, ...#RiskCategory]
30 let _validGroupIds = [for g in groups {g.id}]
31
32 // Unify the valid ID list with a list.Contains constraint to require each entry's value exists
33 for i, r in risks {
34 _groupValidation: "\(i)": _validGroupIds & list.Contains(r.group)
35 }
36 }
37}
38
39// RiskCategory describes a grouping of risks and defines appetite boundaries
40#RiskCategory: {
41 #Group
42
43 // appetite defines the acceptable level of risk for this category
44 appetite: #RiskAppetite @go(Appetite)
45
46 // max-severity defines the risk tolerance boundary: the highest severity
47 // the organization will accept within this category
48 "max-severity"?: #Severity @go(MaxSeverity) @yaml("max-severity,omitempty")
49}
50
51// Severity defines the assessed level of a risk based on its potential impact and likelihood
52#Severity:
53 // minor consequence if realized; manageable within normal operations
54 "Low" |
55 // moderate consequence if realized; may impair specific functions or objectives
56 "Medium" |
57 // severe consequence if realized; likely to disrupt core operations or objectives
58 "High" |
59 // extreme consequence if realized; threatens organizational viability or mission
60 "Critical" @go(-)
61
62// RiskAppetite defines the acceptable level of exposure for a risk category
63#RiskAppetite:
64 // organization is willing to accept higher cost to minimize risk
65 "Minimal" |
66 // organization favors caution but permits limited risk
67 "Low" |
68 // organization tolerates residual risk when justified by value
69 "Moderate" |
70 // organization is willing to operate with less restrictive controls
71 "High" @go(-)
72
73// A Risk represents the potential for negative impact resulting from one or more threats.
74#Risk: {
75 // id allows this risk to be referenced by other elements
76 id: string
77
78 // title describes the risk
79 title: string
80
81 // description explains the risk scenario
82 description: string
83
84 // group references by id a catalog group that this risk belongs to
85 group: string @go(Group)
86
87 // severity describes the assessed level of this risk
88 severity: #Severity @go(Severity)
89
90 // rank optionally orders risks for the same catalog (e.g. when several share the same severity).
91 // Lower values mean higher relative importance. Omitted when the four severity levels are enough.
92 // When set, each value must be unique among all risks in the catalog that specify rank.
93 rank?: int @go(Rank) @yaml("rank,omitempty")
94
95 // owner defines the RACI roles responsible for managing this risk
96 owner?: #RACI @go(Owner)
97
98 // impact describes the business or operational impact
99 impact?: string
100
101 // threats link this risk to Layer 2 threats
102 "threats"?: [#MultiEntryMapping, ...#MultiEntryMapping] @go(Threats)
103}