1// SPDX-License-Identifier: Apache-2.0
2
3// Schema lifecycle: experimental | stable | deprecated
4@status("stable")
5package gemara
6
7import "list"
8
9@go(gemara)
10
11// ControlCatalog describes a set of related controls and relevant metadata
12#ControlCatalog: {
13 #Catalog
14 metadata: type: "ControlCatalog"
15
16 // controls is a list of unique controls defined by this catalog
17 controls?: [#Control, ...#Control] @go(Controls)
18
19 if controls != _|_ {
20 _uniqueControlIds: {for i, c in controls {(c.id): i}}
21 groups: [#Group, ...#Group]
22 metadata: "applicability-groups": [#Group, ...#Group]
23 let _validGroupIds = [for g in groups {g.id}]
24 let _validApplicabilityIds = [for ag in metadata."applicability-groups" {ag.id}]
25
26 // Unify the valid ID list with a list.Contains constraint to require each entry's value exists
27 for i, c in controls {
28 _groupValidation: "\(i)": _validGroupIds & list.Contains(c.group)
29 for j, ar in c."assessment-requirements" {
30 for k, a in ar.applicability {
31 _applicabilityValidation: "\(i)-\(j)-\(k)": _validApplicabilityIds & list.Contains(a)
32 }
33 }
34 }
35 }
36}
37
38// Control describes a safeguard or countermeasure with a clear objective and assessment requirements
39#Control: {
40 // id allows this entry to be referenced by other elements
41 id: string
42
43 // title describes the purpose of this control at a glance
44 title: string
45
46 // objective is a unified statement of intent, which may encompass multiple situationally applicable requirements
47 objective: string
48
49 // group references by id a catalog group that this control belongs to
50 group: string @go(Group)
51
52 // assessment-requirements is a list of requirements that must be verified to confirm the control objective has been met
53 "assessment-requirements": [#AssessmentRequirement, ...#AssessmentRequirement] @go(AssessmentRequirements)
54
55 // guidelines documents relationships between this control and Layer 1 guideline artifacts
56 guidelines?: [#MultiEntryMapping, ...#MultiEntryMapping] @go(Guidelines)
57
58 // threats documents relationships between this control and Layer 2 threat artifacts
59 threats?: [#MultiEntryMapping, ...#MultiEntryMapping] @go(Threats)
60
61 // state is the lifecycle state of this control
62 state: #Lifecycle @go(State) @yaml("state,omitempty")
63
64 // replaced-by references the control that supersedes this one when deprecated or retired
65 "replaced-by"?: #EntryMapping @go(ReplacedBy,optional=nillable) @yaml("replaced-by,omitempty")
66}
67
68// AssessmentRequirement describes a tightly scoped, verifiable condition that must be satisfied and confirmed by an evaluator
69#AssessmentRequirement: {
70 // id allows this entry to be referenced by other elements
71 id: string
72
73 // text is the body of the requirement, typically written as a MUST condition
74 text: string
75
76 // applicability is a list of strings describing the situations where this text functions as a requirement for its parent control
77 applicability: [string, ...string]
78
79 // recommendation provides readers with non-binding suggestions to aid in evaluation or enforcement of the requirement
80 recommendation?: string
81
82 // state is the lifecycle state of this assessment requirement
83 state: #Lifecycle @go(State) @yaml("state,omitempty")
84
85 // replaced-by references the assessment requirement that supersedes this one when deprecated or retired
86 "replaced-by"?: #EntryMapping @go(ReplacedBy,optional=nillable) @yaml("replaced-by,omitempty")
87
88 // retired assessment requirements must not have a recommendation
89 if state == "Retired" {
90 recommendation?: _|_
91 }
92}