oscal 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|