oscal 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.docker/Dockerfile +19 -0
- data/.docker/Makefile +43 -0
- data/.docker/docker-compose.yml +14 -0
- data/.docker/readme.md +61 -0
- data/.github/workflows/rake.yml +15 -0
- data/.github/workflows/release.yml +24 -0
- data/.gitignore +13 -0
- data/.gitmodules +3 -0
- data/.hound.yml +5 -0
- data/.rspec +0 -1
- data/.rubocop.yml +10 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE +25 -0
- data/Makefile +1 -0
- data/README.adoc +66 -0
- data/Rakefile +13 -6
- data/bin/console +30 -0
- data/bin/rspec +27 -0
- data/bin/setup +8 -0
- data/docker-compose.yml +1 -0
- data/exe/convert2oscalyaml.rb +560 -0
- data/lib/oscal/add.rb +26 -0
- data/lib/oscal/address.rb +22 -0
- data/lib/oscal/address_line.rb +11 -0
- data/lib/oscal/alter.rb +22 -0
- data/lib/oscal/assembly.rb +119 -0
- data/lib/oscal/assessment_plan.rb +28 -0
- data/lib/oscal/assessment_result.rb +230 -0
- data/lib/oscal/attribute_type_hash.rb +80 -0
- data/lib/oscal/back_matter.rb +20 -0
- data/lib/oscal/base64_object.rb +11 -0
- data/lib/oscal/base_class.rb +50 -0
- data/lib/oscal/catalog.rb +51 -10
- data/lib/oscal/choice.rb +11 -0
- data/lib/oscal/citation.rb +22 -0
- data/lib/oscal/combine.rb +11 -0
- data/lib/oscal/common_utils.rb +35 -0
- data/lib/oscal/constraint.rb +20 -0
- data/lib/oscal/control.rb +20 -30
- data/lib/oscal/custom.rb +22 -0
- data/lib/oscal/datatypes.rb +50 -0
- data/lib/oscal/document_id.rb +11 -0
- data/lib/oscal/email_address.rb +11 -0
- data/lib/oscal/exclude_control.rb +22 -0
- data/lib/oscal/external_id.rb +11 -0
- data/lib/oscal/group.rb +26 -34
- data/lib/oscal/guideline.rb +11 -0
- data/lib/oscal/hash_object.rb +11 -0
- data/lib/oscal/import_object.rb +22 -0
- data/lib/oscal/include_control.rb +22 -0
- data/lib/oscal/insert_control.rb +22 -0
- data/lib/oscal/link.rb +11 -0
- data/lib/oscal/list.rb +160 -0
- data/lib/oscal/location.rb +31 -0
- data/lib/oscal/location_uuid.rb +11 -0
- data/lib/oscal/logger.rb +8 -0
- data/lib/oscal/matching.rb +11 -0
- data/lib/oscal/member_of_organization.rb +11 -0
- data/lib/oscal/merge.rb +20 -0
- data/lib/oscal/metadata_block.rb +28 -13
- data/lib/oscal/modify.rb +22 -0
- data/lib/oscal/parameter.rb +22 -19
- data/lib/oscal/parsing_functions.rb +19 -0
- data/lib/oscal/part.rb +14 -22
- data/lib/oscal/party.rb +36 -0
- data/lib/oscal/party_uuid.rb +11 -0
- data/lib/oscal/profile.rb +33 -7
- data/lib/oscal/property.rb +4 -25
- data/lib/oscal/remove.rb +11 -0
- data/lib/oscal/resource.rb +29 -0
- data/lib/oscal/responsible_party.rb +24 -0
- data/lib/oscal/revision.rb +23 -0
- data/lib/oscal/rlink.rb +20 -0
- data/lib/oscal/role.rb +22 -0
- data/lib/oscal/select.rb +20 -0
- data/lib/oscal/serializer.rb +17 -4
- data/lib/oscal/set_parameter.rb +31 -0
- data/lib/oscal/telephone_number.rb +11 -0
- data/lib/oscal/test.rb +11 -0
- data/lib/oscal/url.rb +11 -0
- data/lib/oscal/value.rb +37 -0
- data/lib/oscal/version.rb +1 -1
- data/lib/oscal/with_id.rb +40 -0
- data/lib/oscal.rb +1 -13
- data/oscal.gemspec +9 -11
- data/spec/oscal/catalog_spec.rb +40 -0
- data/spec/oscal_spec.rb +7 -0
- data/spec/sample_inputs/import-ap.json +4 -0
- data/spec/spec_helper.rb +15 -0
- metadata +84 -10
- data/lib/oscal/component.rb +0 -14
- data/lib/oscal/prose.rb +0 -13
- data/lib/oscal/statement.rb +0 -12
@@ -0,0 +1,119 @@
|
|
1
|
+
require_relative "parsing_functions"
|
2
|
+
require_relative "logger"
|
3
|
+
require_relative "metadata_block"
|
4
|
+
|
5
|
+
module Oscal
|
6
|
+
class MetadataBlockWrapper < Oscal::MetadataBlock
|
7
|
+
include ParsingFunctions
|
8
|
+
def initialize(metadata_hash)
|
9
|
+
# MetadataBlock likes to get strings, but may sometimes get symbols
|
10
|
+
# this little function makes sure it gets strings everytime
|
11
|
+
super(metadata_hash.transform_keys { |key| sym2str(key) })
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Assembly
|
16
|
+
include Oscal::ParsingFunctions
|
17
|
+
include Oscal::ParsingLogger
|
18
|
+
|
19
|
+
def mandatory_attributes
|
20
|
+
if self.class.constants.include?(:MANDATORY)
|
21
|
+
self.class::MANDATORY
|
22
|
+
else
|
23
|
+
[]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def allowed_attributes
|
28
|
+
if self.class.constants.include?(:OPTIONAL)
|
29
|
+
mandatory_attributes + self.class::OPTIONAL
|
30
|
+
else
|
31
|
+
mandatory_attributes
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_json
|
36
|
+
to_h.to_json
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_h
|
40
|
+
allowed_attributes.each_with_object({}) do |var, hash|
|
41
|
+
attr_value = method(var).call
|
42
|
+
hash[sym2str(var)] = if attr_value == nil
|
43
|
+
next
|
44
|
+
elsif attr_value.class <= OscalArray
|
45
|
+
attr_value.each(&:to_h)
|
46
|
+
elsif attr_value.class <= OscalDatatype
|
47
|
+
attr_value
|
48
|
+
else
|
49
|
+
attr_value.to_h
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def check_and_normalize_input(input)
|
55
|
+
@logger.debug("Checking to see if input is a Hash")
|
56
|
+
unless input.is_a? Hash
|
57
|
+
raise Oscal::InvalidTypeError,
|
58
|
+
"Assemblies can only be created from Hash types"
|
59
|
+
end
|
60
|
+
@logger.debug("Assembly is hash with keys #{input.keys}")
|
61
|
+
|
62
|
+
@logger.debug("Attempting to transform strings to symbols.")
|
63
|
+
# Transform the keys from Strings to Symbols
|
64
|
+
input.transform_keys { |key| str2sym(key) }
|
65
|
+
end
|
66
|
+
|
67
|
+
def validate_input(input)
|
68
|
+
@logger.debug("Checking mandatory and optional values.")
|
69
|
+
missing_values?(mandatory_attributes, input)
|
70
|
+
extra_values?(allowed_attributes, input)
|
71
|
+
end
|
72
|
+
|
73
|
+
def missing_values?(mandatory, provided)
|
74
|
+
@logger.debug("Checking mandatory values: #{mandatory}")
|
75
|
+
missing_values = mandatory - provided.keys.intersection(mandatory)
|
76
|
+
if missing_values.length.positive?
|
77
|
+
raise Oscal::InvalidTypeError,
|
78
|
+
"Missing mandatory values: #{missing_values}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def extra_values?(allowed, provided)
|
83
|
+
@logger.debug("Checking allowed values: #{allowed}")
|
84
|
+
extra_values = provided.keys - provided.keys.intersection(allowed)
|
85
|
+
if extra_values.length.positive?
|
86
|
+
raise Oscal::InvalidTypeError,
|
87
|
+
"Extra attributes provided #{extra_values}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def validate_content(key, value)
|
92
|
+
@logger.info("Validating #{value}")
|
93
|
+
expected_class = Oscal::get_type_of_attribute(key)
|
94
|
+
@logger.debug("Attempting to instiate #{key} as #{expected_class}")
|
95
|
+
instantiated = expected_class.new(value)
|
96
|
+
rescue Oscal::InvalidTypeError
|
97
|
+
raise Oscal::InvalidTypeError,
|
98
|
+
"Value #{value.to_s[0, 25]} not a valid #{key}"
|
99
|
+
else
|
100
|
+
instantiated # Return the valid class
|
101
|
+
end
|
102
|
+
|
103
|
+
def initialize(input)
|
104
|
+
@logger = get_logger
|
105
|
+
@logger.debug("#{self.class}.new called with #{input.to_s[0, 25]}")
|
106
|
+
|
107
|
+
# covert String:String to Symbol:String
|
108
|
+
sym_hash = check_and_normalize_input(input)
|
109
|
+
|
110
|
+
# Make sure all required and no extra keys are provided
|
111
|
+
validate_input(sym_hash)
|
112
|
+
|
113
|
+
# Attempt to convert each value to it's registered type
|
114
|
+
sym_hash.each do |key, value|
|
115
|
+
method("#{key}=".to_sym).call(validate_content(key, value))
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative "assembly"
|
2
|
+
require_relative "metadata_block"
|
3
|
+
require_relative "datatypes"
|
4
|
+
|
5
|
+
module Oscal
|
6
|
+
module AssessmentPlan
|
7
|
+
class ImportSSP < Assembly
|
8
|
+
attr_accessor(*(MANDATORY = %i(href).freeze),
|
9
|
+
*(OPTIONAL = %i(remarks).freeze))
|
10
|
+
end
|
11
|
+
|
12
|
+
class ReviewedControls < Assembly
|
13
|
+
attr_accessor(*(MANDATORY = %i(control_selections).freeze),
|
14
|
+
*(OPTIONAL = %i(description props links
|
15
|
+
control_objective_selections
|
16
|
+
remarks).freeze))
|
17
|
+
end
|
18
|
+
|
19
|
+
class AssessmentPlan < Assembly
|
20
|
+
attr_accessor(*(MANDATORY = %i(uuid metadata import_ssp
|
21
|
+
reviewed_controls).freeze),
|
22
|
+
*(OPTIONAL = %i(local_definitions terms_and_conditions
|
23
|
+
reviewed_controls assessment_subjects
|
24
|
+
assessment_assets tasks
|
25
|
+
back_matter).freeze))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
require_relative "assembly"
|
2
|
+
require_relative "metadata_block"
|
3
|
+
require_relative "datatypes"
|
4
|
+
|
5
|
+
module Oscal
|
6
|
+
module AssessmentResult
|
7
|
+
class Activity < Assembly
|
8
|
+
attr_accessor(*(MANDATORY = %i(uuid).freeze),
|
9
|
+
*(OPTIONAL = %i(title description props links steps
|
10
|
+
related_controls responsible_roles
|
11
|
+
remarks).freeze))
|
12
|
+
end
|
13
|
+
|
14
|
+
class Attestations < Assembly
|
15
|
+
# TODO: Define this. Punting for the time being
|
16
|
+
end
|
17
|
+
|
18
|
+
class AssessmentAssets < Assembly
|
19
|
+
attr_accessor(*(MANDATORY = %i(assessment_platforms).freeze),
|
20
|
+
*(OPTIONAL = %i(components).freeze))
|
21
|
+
end
|
22
|
+
|
23
|
+
class AssessmentLog
|
24
|
+
attr_accessor(*(MANDATORY = %i(entries).freeze))
|
25
|
+
end
|
26
|
+
|
27
|
+
class AssessmentPlatform < Assembly
|
28
|
+
# TODO: Define this. Punting for the time being
|
29
|
+
end
|
30
|
+
|
31
|
+
class AssessmentTask < Assembly
|
32
|
+
attr_accessor(*(MANDATORY = %i(uuid type title).freeze),
|
33
|
+
*(OPTIONAL = %i(description props links timing dependencies
|
34
|
+
tasks associated_activities subjects
|
35
|
+
responsible_roles remarks).freeze))
|
36
|
+
end
|
37
|
+
|
38
|
+
class AssociatedActivity < Assembly
|
39
|
+
attr_accessor(*(MANDATORY = %i(activity_uuid subjects).freeze),
|
40
|
+
*(OPTIONAL = %i(props links responsible_roles
|
41
|
+
remarks).freeze))
|
42
|
+
end
|
43
|
+
|
44
|
+
class AssociatedRisk < Assembly
|
45
|
+
attr_accessor(*(MANDATORY = %i(risk_uuid).freeze))
|
46
|
+
end
|
47
|
+
|
48
|
+
class Attestation < Assembly
|
49
|
+
# TODO: Define this. Punting for the time being
|
50
|
+
end
|
51
|
+
|
52
|
+
class Component < Assembly
|
53
|
+
# TODO: Define this. Punting for the time being
|
54
|
+
end
|
55
|
+
|
56
|
+
class ControlObjectiveSelection < Assembly
|
57
|
+
attr_accessor(*(OPTIONAL = %i(description props links include_all
|
58
|
+
include_objectives exclude_objectives
|
59
|
+
remarks).freeze))
|
60
|
+
end
|
61
|
+
|
62
|
+
class ControlSelection < Assembly
|
63
|
+
attr_accessor(*(OPTIONAL = %i(description props links include_all
|
64
|
+
include_controls exclude_controls
|
65
|
+
remarks).freeze))
|
66
|
+
end
|
67
|
+
|
68
|
+
class Entry < Assembly
|
69
|
+
# TODO: Define this. Punting for the time being
|
70
|
+
end
|
71
|
+
|
72
|
+
class ExcludeControl
|
73
|
+
# TODO: Define this. Punting for the time being
|
74
|
+
# NOTE: This has the same name as profile/exclude-control, but a different
|
75
|
+
# definition!
|
76
|
+
end
|
77
|
+
|
78
|
+
class ExcludeObjective < Assembly
|
79
|
+
attr_accessor(*(MANDATORY = %i(objective_id).freeze))
|
80
|
+
end
|
81
|
+
|
82
|
+
class Finding < Assembly
|
83
|
+
attr_accessor(*(MANDATORY = %i(uuid title description target).freeze),
|
84
|
+
*(OPTIONAL = %i(implementation_statement_uuid
|
85
|
+
related_observations related_risks
|
86
|
+
remarks).freeze))
|
87
|
+
end
|
88
|
+
|
89
|
+
class ImportAP < Assembly
|
90
|
+
attr_accessor(*(MANDATORY = %i(href).freeze),
|
91
|
+
*(OPTIONAL = %i(remarks).freeze))
|
92
|
+
end
|
93
|
+
|
94
|
+
class IncludeAll < Assembly
|
95
|
+
# This is an Assembly that acts like a flag - it has no no contents
|
96
|
+
end
|
97
|
+
|
98
|
+
class IncludeControl < Assembly
|
99
|
+
attr_accessor(*(MANDATORY = %i(control_id).freeze),
|
100
|
+
*(OPTIONAL = %i(statement_ids).freeze))
|
101
|
+
end
|
102
|
+
|
103
|
+
class IncludeObjective < Assembly
|
104
|
+
attr_accessor(*(MANDATORY = %i(objective_id).freeze))
|
105
|
+
end
|
106
|
+
|
107
|
+
class InventoryItem < Assembly
|
108
|
+
# TODO: Define this. Punting for the time being
|
109
|
+
end
|
110
|
+
|
111
|
+
class LocalDefinitions < Assembly
|
112
|
+
# NOTE we deviate fromt the spec here! local-definitions is defined twice
|
113
|
+
# with different attributes. All attributes are optional, so we merge it
|
114
|
+
# into one big back of optional attributes
|
115
|
+
attr_accessor(*(OPTIONAL = %i(objectives_and_methods activities
|
116
|
+
remarks components inventory_items users
|
117
|
+
assesssment_assets tasks).freeze))
|
118
|
+
end
|
119
|
+
|
120
|
+
class ObjectivesAndMethods < Assembly
|
121
|
+
attr_accessor(*(MANDATORY = %i(control_id parts).freeze),
|
122
|
+
*(OPTIONAL = %i(description props links remarks).freeze))
|
123
|
+
end
|
124
|
+
|
125
|
+
class Observation < Assembly
|
126
|
+
attr_accessor(*(MANDATORY = %i(uuid description methods collected).freeze),
|
127
|
+
*(OPTIONAL = %i(title props links methods types origins
|
128
|
+
subjects relevent_evidence expires
|
129
|
+
remarks).freeze))
|
130
|
+
end
|
131
|
+
|
132
|
+
class RelatedControls < Assembly
|
133
|
+
attr_accessor(*(MANDATORY = %i(control_selections).freeze),
|
134
|
+
*(OPTIONAL = %i(description props links
|
135
|
+
control_objective_selections
|
136
|
+
remarks).freeze))
|
137
|
+
end
|
138
|
+
|
139
|
+
class RelatedObservation < Assembly
|
140
|
+
attr_accessor(*(MANDATORY = %i(observation_uuid).freeze),
|
141
|
+
*(OPTIONAL = %i().freeze))
|
142
|
+
end
|
143
|
+
|
144
|
+
class ResponsibleRole < Assembly
|
145
|
+
attr_accessor(*(MANDATORY = %i(role_id).freeze),
|
146
|
+
*(OPTIONAL = %i(props links party_uuids remarks).freeze))
|
147
|
+
end
|
148
|
+
|
149
|
+
class Result < Assembly
|
150
|
+
attr_accessor(*(MANDATORY = %i(uuid title description start).freeze),
|
151
|
+
*(OPTIONAL = %i(end props links local_definitions
|
152
|
+
reviewed_controls attestations
|
153
|
+
assessment_log observations risks findings
|
154
|
+
remarks).freeze))
|
155
|
+
end
|
156
|
+
|
157
|
+
class ReviewedControls < Assembly
|
158
|
+
attr_accessor(*(MANDATORY = %i(control_selections).freeze),
|
159
|
+
*(OPTIONAL = %i(description props links
|
160
|
+
control_objective_selections
|
161
|
+
remarks).freeze))
|
162
|
+
end
|
163
|
+
|
164
|
+
class Risk < Assembly
|
165
|
+
attr_accessor(*(MANDATORY = %i(uuid title description statement
|
166
|
+
status).freeze),
|
167
|
+
*(OPTIONAL = %i(propse links origins threat_ids
|
168
|
+
characterizations mitigating_factors
|
169
|
+
deadline remediations risk_log
|
170
|
+
related_observations).freeze))
|
171
|
+
end
|
172
|
+
|
173
|
+
class Status
|
174
|
+
# Status is defined twice, once as a datatype, once as an assembly
|
175
|
+
# this class figures out which is which
|
176
|
+
def initialize(input)
|
177
|
+
if input.instance_of? String
|
178
|
+
StatusString.new(input)
|
179
|
+
elsif input.instance_of? Hash
|
180
|
+
StatusAssembly.new(input)
|
181
|
+
else
|
182
|
+
raise Oscal::InvalidTypeError, "status must be a string or assembly"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
class StatusString < TokenDataType
|
188
|
+
end
|
189
|
+
|
190
|
+
class StatusAssembly < Assembly
|
191
|
+
attr_accessor(*(MANDATORY = %i(state).freeze),
|
192
|
+
*(OPTIONAL = %i(reason remarks).freeze))
|
193
|
+
end
|
194
|
+
|
195
|
+
class Step < Assembly
|
196
|
+
attr_accessor(*(MANDATORY = %i(uuid).freeze),
|
197
|
+
*(OPTIONAL = %i(title description props links
|
198
|
+
reviewed_controls responsible_roles
|
199
|
+
remarks).freeze))
|
200
|
+
end
|
201
|
+
|
202
|
+
class Subject < Assembly
|
203
|
+
attr_accessor(*(OPTIONAL = %i(subject_uuid type
|
204
|
+
description props links include_all
|
205
|
+
include_subjects exclude_subjects
|
206
|
+
remarks).freeze))
|
207
|
+
end
|
208
|
+
|
209
|
+
class Target < Assembly
|
210
|
+
attr_accessor(*(MANDATORY = %i(type target_id status).freeze),
|
211
|
+
*(OPTIONAL = %i(title description props links
|
212
|
+
implementation_status remarks).freeze))
|
213
|
+
end
|
214
|
+
|
215
|
+
class Task < Assembly
|
216
|
+
# TODO: Define this. Punting for the time being
|
217
|
+
end
|
218
|
+
|
219
|
+
class User < Assembly
|
220
|
+
# TODO: Define this. Punting for the time being
|
221
|
+
end
|
222
|
+
|
223
|
+
##########################################
|
224
|
+
|
225
|
+
class AssessmentResult < Assembly
|
226
|
+
attr_accessor(*(MANDATORY = %i(uuid metadata import_ap results).freeze),
|
227
|
+
*(OPTIONAL = %i(local_definitions back_matter).freeze))
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require_relative("datatypes")
|
2
|
+
require_relative("list")
|
3
|
+
|
4
|
+
module Oscal
|
5
|
+
ATTRIBUTE_TYPE_HASH = {
|
6
|
+
activities: AssessmentResult::ActivityArray,
|
7
|
+
activity_uuid: Uuid,
|
8
|
+
assessment_plan: AssessmentPlan::AssessmentPlan,
|
9
|
+
assessment_platforms: AssessmentResult::AssessmentPlatformArray,
|
10
|
+
assessment_results: AssessmentResult::AssessmentResult,
|
11
|
+
assessment_log: AssessmentResult::AssessmentLog,
|
12
|
+
associated_activities: AssessmentResult::AssociatedActivityArray,
|
13
|
+
attestations: AssessmentResult::AttestationArray,
|
14
|
+
collected: DateTimeWithTimezoneDataType,
|
15
|
+
components: AssessmentResult::ComponentArray,
|
16
|
+
control_id: TokenDataType,
|
17
|
+
control_objective_selections: AssessmentResult::ControlObjectiveSelectionArray,
|
18
|
+
control_selections: AssessmentResult::ControlSelectionArray,
|
19
|
+
description: MarkupMultilineDataType,
|
20
|
+
end: DateTimeWithTimezoneDataType,
|
21
|
+
entries: AssessmentResult::EntryArray,
|
22
|
+
exclude_controls: AssessmentResult::ExcludeControlArray,
|
23
|
+
exclude_objectives: AssessmentResult::ExcludeObjectiveArray,
|
24
|
+
expires: DateTimeWithTimezoneDataType,
|
25
|
+
findings: AssessmentResult::FindingArray,
|
26
|
+
href: UriReference,
|
27
|
+
implementation_statement_uuid: Uuid,
|
28
|
+
import_ap: AssessmentResult::ImportAP,
|
29
|
+
import_ssp: AssessmentPlan::ImportSSP,
|
30
|
+
include_all: AssessmentResult::IncludeAll,
|
31
|
+
include_controls: AssessmentResult::IncludeControlArray,
|
32
|
+
inventory_items: AssessmentResult::InventoryItemArray,
|
33
|
+
links: AssessmentResult::LinkArray,
|
34
|
+
local_definitions: AssessmentResult::LocalDefinitions,
|
35
|
+
metadata: MetadataBlockWrapper,
|
36
|
+
methods: AssessmentResult::MethodArray,
|
37
|
+
objective_id: TokenDataType,
|
38
|
+
objectives_and_methods: AssessmentResult::ObjectivesAndMethodsArray,
|
39
|
+
observations: AssessmentResult::ObservationArray,
|
40
|
+
observation_uuid: Uuid,
|
41
|
+
parts: AssessmentResult::PartArray,
|
42
|
+
party_uuids: AssessmentResult::PartyUuidArray,
|
43
|
+
props: AssessmentResult::PropArray,
|
44
|
+
related_controls: AssessmentResult::RelatedControls,
|
45
|
+
related_observations: AssessmentResult::RelatedObservationArray,
|
46
|
+
related_risks: AssessmentResult::RelatedRiskArray,
|
47
|
+
remarks: MarkupMultilineDataType,
|
48
|
+
responsible_roles: AssessmentResult::ResponsibleRoleArray,
|
49
|
+
results: AssessmentResult::ResultArray,
|
50
|
+
reviewed_controls: AssessmentResult::ReviewedControls,
|
51
|
+
risks: AssessmentResult::RiskArray,
|
52
|
+
risk_uuid: Uuid,
|
53
|
+
role_id: TokenDataType,
|
54
|
+
start: DateTimeWithTimezoneDataType,
|
55
|
+
state: TokenDataType,
|
56
|
+
status: AssessmentResult::Status,
|
57
|
+
statement: MarkupMultilineDataType,
|
58
|
+
statement_ids: AssessmentResult::StatementIdArray,
|
59
|
+
steps: AssessmentResult::StepArray,
|
60
|
+
subjects: AssessmentResult::SubjectArray,
|
61
|
+
subject_uuid: Uuid,
|
62
|
+
target: AssessmentResult::Target,
|
63
|
+
target_id: TokenDataType,
|
64
|
+
tasks: AssessmentResult::AssessmentTaskArray,
|
65
|
+
title: MarkupMultilineDataType,
|
66
|
+
type: TokenDataType,
|
67
|
+
types: AssessmentResult::TypeArray,
|
68
|
+
uuid: Uuid,
|
69
|
+
users: AssessmentResult::UserArray,
|
70
|
+
}.freeze
|
71
|
+
|
72
|
+
def self.get_type_of_attribute(attribute_name)
|
73
|
+
klass = Oscal::ATTRIBUTE_TYPE_HASH[attribute_name.to_sym]
|
74
|
+
if klass == nil
|
75
|
+
raise InvalidTypeError, "No type found for #{attribute_name}"
|
76
|
+
else
|
77
|
+
klass
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative "base_class"
|
2
|
+
|
3
|
+
module Oscal
|
4
|
+
class BackMatter < Oscal::BaseClass
|
5
|
+
KEY = %i(resources)
|
6
|
+
|
7
|
+
attr_accessor *KEY
|
8
|
+
|
9
|
+
attr_serializable *KEY
|
10
|
+
|
11
|
+
def set_value(key_name, val)
|
12
|
+
case key_name
|
13
|
+
when "resources"
|
14
|
+
Resource.wrap(val)
|
15
|
+
else
|
16
|
+
val
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative "serializer"
|
2
|
+
|
3
|
+
module Oscal
|
4
|
+
class BaseClass
|
5
|
+
include Serializer
|
6
|
+
|
7
|
+
KEY = %i(val)
|
8
|
+
|
9
|
+
attr_accessor *KEY
|
10
|
+
|
11
|
+
attr_serializable *KEY
|
12
|
+
|
13
|
+
def self.wrap(obj)
|
14
|
+
klass = self
|
15
|
+
return obj if obj.is_a? klass
|
16
|
+
return klass.new(obj) unless obj.is_a? Array
|
17
|
+
|
18
|
+
obj.map do |x|
|
19
|
+
klass.wrap(x)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(options = {})
|
24
|
+
klass = self.class
|
25
|
+
|
26
|
+
unless options.is_a? Hash
|
27
|
+
options = { klass::KEY.first.to_s => options }
|
28
|
+
end
|
29
|
+
|
30
|
+
options.each_pair.each do |key, val|
|
31
|
+
key_name = key.gsub("-", "_")
|
32
|
+
key_name = "klass" if key == "class"
|
33
|
+
|
34
|
+
unless klass::KEY.include?(key_name.to_sym)
|
35
|
+
raise UnknownAttributeError.new(
|
36
|
+
"Unknown key `#{key}` in #{klass.name}",
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
val = set_value(key_name, val)
|
41
|
+
|
42
|
+
send("#{key_name}=", val)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def set_value(_key_name, val)
|
47
|
+
val
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/oscal/catalog.rb
CHANGED
@@ -1,22 +1,63 @@
|
|
1
|
+
require "date"
|
2
|
+
require_relative "serializer"
|
3
|
+
require_relative "common_utils"
|
4
|
+
|
1
5
|
module Oscal
|
2
6
|
class Catalog
|
3
|
-
|
7
|
+
include Serializer
|
8
|
+
include CommonUtils
|
9
|
+
|
10
|
+
KEY = %i(uuid metadata params controls groups back_matter)
|
11
|
+
attr_accessor *KEY
|
12
|
+
|
13
|
+
attr_serializable *KEY
|
4
14
|
|
5
|
-
def initialize(metadata, groups)
|
6
|
-
@
|
7
|
-
@
|
15
|
+
def initialize(uuid, metadata, params, controls, groups, back_matter)
|
16
|
+
@uuid = uuid
|
17
|
+
@metadata = MetadataBlock.new(metadata)
|
18
|
+
@params = Parameter.wrap(params) if params
|
19
|
+
@controls = Control.wrap(controls) if controls
|
20
|
+
@groups = Group.wrap(groups) if groups
|
21
|
+
@back_matter = BackMatter.wrap(back_matter) if back_matter
|
22
|
+
|
23
|
+
@all_controls = []
|
8
24
|
end
|
9
25
|
|
10
26
|
def self.load_from_yaml(path)
|
11
|
-
yaml_data
|
27
|
+
yaml_data = safe_load_yaml(path)
|
28
|
+
yaml_catalog = yaml_data["catalog"]
|
29
|
+
|
30
|
+
uuid = yaml_catalog["uuid"]
|
31
|
+
metadata = yaml_catalog["metadata"]
|
32
|
+
params = yaml_catalog["params"]
|
33
|
+
controls = yaml_catalog["controls"]
|
34
|
+
groups = yaml_catalog["groups"]
|
35
|
+
back_matter = yaml_catalog["back-matter"]
|
12
36
|
|
13
|
-
|
37
|
+
Catalog.new(uuid, metadata, params, controls, groups, back_matter)
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_all_controls
|
41
|
+
append_all_control_group(self)
|
42
|
+
@all_controls.uniq
|
43
|
+
end
|
14
44
|
|
15
|
-
|
16
|
-
|
45
|
+
def append_all_control_group(obj)
|
46
|
+
if /Oscal::Control/.match?(obj.to_s)
|
47
|
+
@all_controls << obj
|
48
|
+
end
|
17
49
|
|
18
|
-
|
50
|
+
if obj.respond_to?(:controls) && !obj.controls.nil?
|
51
|
+
obj.controls.each do |c|
|
52
|
+
append_all_control_group(c)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
if obj.respond_to?(:groups) && !obj.groups.nil?
|
57
|
+
obj.groups.each do |g|
|
58
|
+
append_all_control_group(g)
|
59
|
+
end
|
60
|
+
end
|
19
61
|
end
|
20
62
|
end
|
21
|
-
|
22
63
|
end
|
data/lib/oscal/choice.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative "base_class"
|
2
|
+
|
3
|
+
module Oscal
|
4
|
+
class Citation < Oscal::BaseClass
|
5
|
+
KEY = %i(text props links)
|
6
|
+
|
7
|
+
attr_accessor *KEY
|
8
|
+
|
9
|
+
attr_serializable *KEY
|
10
|
+
|
11
|
+
def set_value(key_name, val)
|
12
|
+
case key_name
|
13
|
+
when "props"
|
14
|
+
Property.wrap(val)
|
15
|
+
when "links"
|
16
|
+
Link.wrap(val)
|
17
|
+
else
|
18
|
+
val
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|