generated from inferno-framework/inferno-template
-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathonc_certification_g10_test_kit.rb
438 lines (371 loc) · 18.6 KB
/
onc_certification_g10_test_kit.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
require 'smart_app_launch/smart_stu1_suite'
require 'smart_app_launch/smart_stu2_suite'
require 'us_core_test_kit'
require_relative 'onc_certification_g10_test_kit/configuration_checker'
require_relative 'onc_certification_g10_test_kit/version'
require_relative 'onc_certification_g10_test_kit/feature'
require_relative 'onc_certification_g10_test_kit/g10_options'
require_relative 'onc_certification_g10_test_kit/multi_patient_api_stu1'
require_relative 'onc_certification_g10_test_kit/multi_patient_api_stu2'
require_relative 'onc_certification_g10_test_kit/single_patient_api_group'
require_relative 'onc_certification_g10_test_kit/single_patient_us_core_4_api_group'
require_relative 'onc_certification_g10_test_kit/single_patient_us_core_5_api_group'
require_relative 'onc_certification_g10_test_kit/single_patient_us_core_6_api_group'
require_relative 'onc_certification_g10_test_kit/smart_app_launch_invalid_aud_group'
require_relative 'onc_certification_g10_test_kit/smart_asymmetric_launch_group'
require_relative 'onc_certification_g10_test_kit/smart_granular_scope_selection_group'
require_relative 'onc_certification_g10_test_kit/smart_invalid_token_group'
require_relative 'onc_certification_g10_test_kit/smart_invalid_token_group_stu2'
require_relative 'onc_certification_g10_test_kit/smart_invalid_pkce_group'
require_relative 'onc_certification_g10_test_kit/smart_limited_app_group'
require_relative 'onc_certification_g10_test_kit/smart_standalone_patient_app_group'
require_relative 'onc_certification_g10_test_kit/smart_public_standalone_launch_group'
require_relative 'onc_certification_g10_test_kit/smart_public_standalone_launch_group_stu2'
require_relative 'onc_certification_g10_test_kit/smart_ehr_patient_launch_group'
require_relative 'onc_certification_g10_test_kit/smart_ehr_patient_launch_group_stu2'
require_relative 'onc_certification_g10_test_kit/smart_ehr_practitioner_app_group'
require_relative 'onc_certification_g10_test_kit/smart_fine_grained_scopes_group'
require_relative 'onc_certification_g10_test_kit/smart_v1_scopes_group'
require_relative 'onc_certification_g10_test_kit/terminology_binding_validator'
require_relative 'onc_certification_g10_test_kit/token_introspection_group'
require_relative 'onc_certification_g10_test_kit/token_revocation_group'
require_relative 'onc_certification_g10_test_kit/visual_inspection_and_attestations_group'
require_relative 'inferno/terminology'
require_relative 'onc_certification_g10_test_kit/short_id_manager'
Inferno::Terminology::Loader.load_validators
module ONCCertificationG10TestKit
class G10CertificationSuite < Inferno::TestSuite
title 'ONC Certification (g)(10) Standardized API'
short_title '(g)(10) Standardized API'
version VERSION
id :g10_certification
links [
{
label: 'Report Issue',
url: 'https://github.com/onc-healthit/onc-certification-g10-test-kit/issues/'
},
{
label: 'Open Source',
url: 'https://github.com/onc-healthit/onc-certification-g10-test-kit/'
},
{
label: 'Download',
url: 'https://github.com/onc-healthit/onc-certification-g10-test-kit/releases'
}
]
check_configuration do
ConfigurationChecker.new.configuration_messages
end
WARNING_INCLUSION_FILTERS = [
/Unknown CodeSystem/,
/Unknown ValueSet/
].freeze
ERROR_FILTERS = [
/\A\S+: \S+: Unknown [Cc]ode/,
/\A\S+: \S+: None of the codings provided are in the value set/,
/\A\S+: \S+: The code provided \(\S*\) is not in the value set/,
/\A\S+: \S+: The Coding provided \(\S*\) is not in the value set/,
/\A\S+: \S+: The Coding provided \(\S*\) was not found in the value set/,
/\A\S+: \S+: A definition for CodeSystem '.*' could not be found, so the code cannot be validated/,
/\A\S+: \S+: URL value '.*' does not resolve/,
/\A\S+: \S+: .*\[No server available\]/, # Catch-all for certain errors when TX server is disabled
%r{\A\S+: \S+: .*\[Error from http://tx.fhir.org/r4:} # Catch-all for TX server errors that slip through
].freeze
def self.setup_validator(us_core_version_requirement) # rubocop:disable Metrics/CyclomaticComplexity
validator_method = if Feature.use_hl7_resource_validator?
method(:fhir_resource_validator)
else
method(:validator)
end
validator_method.call :default, required_suite_options: us_core_version_requirement do
if Feature.use_hl7_resource_validator?
cli_context do
txServer nil
displayWarnings true
disableDefaultResourceFetcher true
end
us_core_version_num = G10Options::US_CORE_VERSION_NUMBERS[us_core_version_requirement[:us_core_version]]
igs("hl7.fhir.us.core##{us_core_version_num}")
else
url ENV.fetch('G10_VALIDATOR_URL', 'http://validator_service:4567')
end
us_core_message_filters =
case (us_core_version_requirement[:us_core_version])
when G10Options::US_CORE_3
USCoreTestKit::USCoreV311::USCoreTestSuite::VALIDATION_MESSAGE_FILTERS
when G10Options::US_CORE_4
USCoreTestKit::USCoreV400::USCoreTestSuite::VALIDATION_MESSAGE_FILTERS
when G10Options::US_CORE_5
USCoreTestKit::USCoreV501::USCoreTestSuite::VALIDATION_MESSAGE_FILTERS
when G10Options::US_CORE_6
USCoreTestKit::USCoreV610::USCoreTestSuite::VALIDATION_MESSAGE_FILTERS
end
exclude_message do |message|
if message.type == 'info' ||
(message.type == 'warning' && WARNING_INCLUSION_FILTERS.none? do |filter|
filter.match? message.message
end) ||
us_core_message_filters.any? { |filter| filter.match? message.message } ||
(message.type == 'error' && ERROR_FILTERS.any? { |filter| message.message.match? filter })
true
else
false
end
end
perform_additional_validation do |resource, profile_url|
versionless_profile_url, profile_version = profile_url.split('|')
profile_version = case profile_version
when '6.1.0'
'610'
when '4.0.0'
'400'
when '5.0.1'
'501'
else
# This open-ended else is primarily for Vital Signs profiles in v3.1.1, which are tagged
# with the base FHIR version (4.0.1). The profiles were migrated to US Core in later
# versions.
'311'
end
us_core_suite = USCoreTestKit.const_get("USCoreV#{profile_version}")::USCoreTestSuite
metadata = us_core_suite.metadata.find do |metadata_candidate|
metadata_candidate.profile_url == versionless_profile_url
end
next if metadata.nil?
validation_messages = if resource.instance_of?(FHIR::Provenance)
USCoreTestKit::ProvenanceValidator.validate(resource)
else
[]
end
terminology_validation_messages = metadata.bindings
.select { |binding_definition| binding_definition[:strength] == 'required' }
.flat_map do |binding_definition|
TerminologyBindingValidator.validate(resource, binding_definition)
rescue Inferno::UnknownValueSetException, Inferno::UnknownCodeSystemException => e
{ type: 'warning', message: e.message }
end.compact
validation_messages.concat(terminology_validation_messages)
validation_messages
end
end
end
[
G10Options::US_CORE_3_REQUIREMENT,
G10Options::US_CORE_4_REQUIREMENT,
G10Options::US_CORE_5_REQUIREMENT,
G10Options::US_CORE_6_REQUIREMENT
].each do |us_core_version_requirement|
setup_validator(us_core_version_requirement)
end
def self.jwks_json
bulk_data_jwks = JSON.parse(File.read(
ENV.fetch('G10_BULK_DATA_JWKS',
File.join(__dir__, 'onc_certification_g10_test_kit',
'bulk_data_jwks.json'))
))
@jwks_json ||= JSON.pretty_generate(
{ keys: bulk_data_jwks['keys'].select { |key| key['key_ops']&.include?('verify') } }
)
end
def self.well_known_route_handler
->(_env) { [200, { 'Content-Type' => 'application/json' }, [jwks_json]] }
end
route(
:get,
'/.well-known/jwks.json',
well_known_route_handler
)
suite_option :us_core_version,
title: 'US Core Version',
list_options: [
{
label: 'US Core 3.1.1 / USCDI v1',
value: G10Options::US_CORE_3
},
{
label: 'US Core 4.0.0 / USCDI v1',
value: G10Options::US_CORE_4
},
{
label: 'US Core 6.1.0 / USCDI v3',
value: G10Options::US_CORE_6
}
]
suite_option :smart_app_launch_version,
title: 'SMART App Launch Version',
list_options: [
{
label: 'SMART App Launch 1.0.0',
value: G10Options::SMART_1
},
{
label: 'SMART App Launch 2.0.0',
value: G10Options::SMART_2
}
]
suite_option :multi_patient_version,
title: 'Bulk Data Version',
list_options: [
{
label: 'Bulk Data 1.0.1',
value: G10Options::BULK_DATA_1
},
{
label: 'Bulk Data 2.0.0',
value: G10Options::BULK_DATA_2
}
]
config(
inputs: {
client_auth_encryption_method: {
title: 'Client Authentication Encryption Method',
locked: true
}
},
options: {
post_authorization_uri: "#{Inferno::Application['base_url']}/custom/smart_stu2/post_auth",
incorrectly_permitted_tls_version_message_type: 'warning'
}
)
description %(
The ONC Certification (g)(10) Standardized API Test Suite is a testing
tool for Health Level 7 (HL7®) Fast Healthcare Interoperability Resources
(FHIR®) services seeking to meet the requirements of the Standardized API
for Patient and Population Services criterion § 170.315(g)(10) in the ONC
Certification Program.
This test suite is organized into testing scenarios that in sum cover all
requirements within the § 170.315(g)(10) certification criterion. The
scenarios are intended to be run in order during certification, but can
be run out of order to support testing during development or certification
preparation. Some scenarios depend on data collected during previous
scenarios to function. In these cases, the scenario description describes
these dependencies.
The best way to learn about how to use these tests is the
[(g)(10) Standardized API Test Kit walkthrough](https://github.com/onc-healthit/onc-certification-g10-test-kit/wiki/Walkthrough),
which demonstrates the tests running against a simulated system.
The first three scenarios require the system under test to demonstrate
basic SMART App Launch functionality. The fourth uses a valid token
provided during earlier tests to verify support for the Single Patient API
as described in the criterion. The fifth verifies support for the Multi
Patient API, including Backend Services for authorization. Not all
authorization-related requirements are verified in the first three
scenarios, and the 'Additional Authorization Tests' verify these
additional requirements. The last scenario contains a list of
'attestations' and 'visual inspections' for requirements that could not
be verified through automated testing.
To get started with the first group of scenarios, please first register the
Inferno client as a SMART App with the following information:
* SMART Launch URI: `#{SMARTAppLaunch::AppLaunchTest.config.options[:launch_uri]}`
* OAuth Redirect URI: `#{SMARTAppLaunch::AppRedirectTest.config.options[:redirect_uri]}`
For the multi-patient API, register Inferno with the following JWK Set
Url:
* `#{Inferno::Application[:base_url]}/custom/g10_certification/.well-known/jwks.json`
Systems must pass all tests to qualify for ONC certification.
)
suite_summary %(
The ONC Certification (g)(10) Standardized API Test Kit is a testing tool
for Health Level 7 (HL7®) Fast Healthcare Interoperability Resources
(FHIR®) services seeking to meet the requirements of the Standardized API
for Patient and Population Services criterion § 170.315(g)(10) in the ONC Certification Program.
Systems may adopt later versions of standards than those named in the rule
as approved by the ONC Standards Version Advancement Process (SVAP).
Please select which approved version of each standard to use, and click
‘Start Testing’ to begin testing.
)
input_instructions %(
Register Inferno as a SMART app using the following information:
* Launch URI: `#{SMARTAppLaunch::AppLaunchTest.config.options[:launch_uri]}`
* Redirect URI: `#{SMARTAppLaunch::AppRedirectTest.config.options[:redirect_uri]}`
For the multi-patient API, register Inferno with the following JWK Set
Url:
* `#{Inferno::Application[:base_url]}/custom/g10_certification/.well-known/jwks.json`
)
group from: 'g10_smart_standalone_patient_app'
group from: 'g10_smart_limited_app'
group from: 'g10_smart_ehr_practitioner_app'
group from: 'g10_single_patient_api',
required_suite_options: G10Options::US_CORE_3_REQUIREMENT
group from: 'g10_single_patient_us_core_4_api',
required_suite_options: G10Options::US_CORE_4_REQUIREMENT
group from: 'g10_single_patient_us_core_5_api',
required_suite_options: G10Options::US_CORE_5_REQUIREMENT
group from: 'g10_single_patient_us_core_6_api',
required_suite_options: G10Options::US_CORE_6_REQUIREMENT
group from: 'multi_patient_api',
required_suite_options: G10Options::BULK_DATA_1_REQUIREMENT
group from: 'multi_patient_api_stu2',
required_suite_options: G10Options::BULK_DATA_2_REQUIREMENT
group do
title 'Additional Authorization Tests'
id 'Group06'
description %(
The (g)(10) Standardized Test Suite attempts to minimize effort required
by testers by creating scenarios that validate as many requirements as
possible with just a handful of SMART App Launches. However, not all
SMART App Launch and (g)(10) Standardized API criterion requirements
that need to be verified fit within the first few test scenarios in this
suite.
The scenarios contained in this section verify remaining testing
requirements for the (g)(10) Standardized API criterion relevant to
the SMART App Launch implementation specification. Each of these scenarios
need to be run independently. Please read the instructions for each in
the 'About' section, as they may require special setup on the part of
the tester.
)
default_redirect_message_proc = lambda do |auth_url|
%(
### #{self.class.parent.title}
[Follow this link to authorize with the SMART server](#{auth_url}).
Tests will resume once Inferno receives a request at
`#{config.options[:redirect_uri]}` with a state of `#{state}`.
)
end
config(
inputs: {
client_auth_encryption_method: {
locked: false
}
}
)
group from: :g10_public_standalone_launch,
required_suite_options: G10Options::SMART_1_REQUIREMENT,
config: { options: { redirect_message_proc: default_redirect_message_proc } }
group from: :g10_public_standalone_launch_stu2,
required_suite_options: G10Options::SMART_2_REQUIREMENT,
config: { options: { redirect_message_proc: default_redirect_message_proc } }
group from: :g10_token_revocation
group from: :g10_smart_invalid_aud,
config: { options: { redirect_message_proc: default_redirect_message_proc } }
group from: :g10_smart_invalid_token_request,
required_suite_options: G10Options::SMART_1_REQUIREMENT,
config: { options: { redirect_message_proc: default_redirect_message_proc } }
group from: :g10_smart_invalid_token_request_stu2,
required_suite_options: G10Options::SMART_2_REQUIREMENT,
config: { options: { redirect_message_proc: default_redirect_message_proc } }
group from: :g10_smart_invalid_pkce_code_verifier_group,
required_suite_options: G10Options::SMART_2_REQUIREMENT
group from: :g10_ehr_patient_launch,
required_suite_options: G10Options::SMART_1_REQUIREMENT
group from: :g10_ehr_patient_launch_stu2,
required_suite_options: G10Options::SMART_2_REQUIREMENT
group from: :g10_token_introspection,
required_suite_options: G10Options::SMART_2_REQUIREMENT
group from: :g10_asymmetric_launch,
required_suite_options: G10Options::SMART_2_REQUIREMENT
group from: :g10_smart_v1_scopes,
required_suite_options: G10Options::SMART_2_REQUIREMENT,
config: {
inputs: {
client_auth_encryption_method: { locked: true }
}
}
group from: :g10_smart_fine_grained_scopes,
required_suite_options: G10Options::SMART_2_REQUIREMENT.merge(G10Options::US_CORE_6_REQUIREMENT),
exclude_optional: true
group from: :g10_smart_granular_scope_selection,
required_suite_options: G10Options::SMART_2_REQUIREMENT.merge(G10Options::US_CORE_6_REQUIREMENT)
end
group from: :g10_visual_inspection_and_attestations
end
end
ONCCertificationG10TestKit::ShortIDManager.assign_short_ids