onc_certification_g10_test_kit 6.0.3 → 7.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/inferno/repositiories/validators.rb +0 -6
  3. data/lib/inferno/repositiories/value_sets.rb +1 -7
  4. data/lib/inferno/terminology/expected_manifest.yml +5 -5
  5. data/lib/inferno/terminology/fhir_package_manager.rb +13 -4
  6. data/lib/inferno/terminology/loader.rb +2 -1
  7. data/lib/inferno/terminology/tasks/download_fhir_terminology.rb +2 -1
  8. data/lib/inferno/terminology/tasks/download_umls.rb +2 -1
  9. data/lib/inferno/terminology/tasks/expand_value_set_to_file.rb +1 -1
  10. data/lib/inferno/terminology/tasks/run_umls_jar.rb +2 -1
  11. data/lib/inferno/terminology/validator.rb +1 -0
  12. data/lib/inferno/terminology/value_set.rb +2 -0
  13. data/lib/onc_certification_g10_test_kit/all_resources.rb +74 -0
  14. data/lib/onc_certification_g10_test_kit/bulk_data_group_export_validation.rb +361 -59
  15. data/lib/onc_certification_g10_test_kit/bulk_export_validation_tester.rb +4 -3
  16. data/lib/onc_certification_g10_test_kit/g10_options.rb +20 -1
  17. data/lib/onc_certification_g10_test_kit/limited_scope_grant_test.rb +4 -0
  18. data/lib/onc_certification_g10_test_kit/multi_patient_api_stu1.rb +2 -1
  19. data/lib/onc_certification_g10_test_kit/multi_patient_api_stu2.rb +2 -1
  20. data/lib/onc_certification_g10_test_kit/patient_scope_test.rb +1 -1
  21. data/lib/onc_certification_g10_test_kit/profile_selector.rb +40 -15
  22. data/lib/onc_certification_g10_test_kit/restricted_resource_type_access_group.rb +89 -2
  23. data/lib/onc_certification_g10_test_kit/short_id_map.yml +1417 -12
  24. data/lib/onc_certification_g10_test_kit/single_patient_us_core_7_api_group.rb +219 -0
  25. data/lib/onc_certification_g10_test_kit/smart_app_launch_invalid_aud_group.rb +41 -1
  26. data/lib/onc_certification_g10_test_kit/smart_asymmetric_launch_group.rb +33 -1
  27. data/lib/onc_certification_g10_test_kit/smart_ehr_patient_launch_group_stu2_2.rb +128 -0
  28. data/lib/onc_certification_g10_test_kit/smart_ehr_practitioner_app_group.rb +234 -0
  29. data/lib/onc_certification_g10_test_kit/smart_fine_grained_scopes_group_stu2_2.rb +188 -0
  30. data/lib/onc_certification_g10_test_kit/smart_fine_grained_scopes_us_core_7_group.rb +188 -0
  31. data/lib/onc_certification_g10_test_kit/smart_fine_grained_scopes_us_core_7_group_stu2_2.rb +188 -0
  32. data/lib/onc_certification_g10_test_kit/smart_granular_scope_selection_group.rb +67 -1
  33. data/lib/onc_certification_g10_test_kit/smart_limited_app_group.rb +128 -1
  34. data/lib/onc_certification_g10_test_kit/smart_public_standalone_launch_group_stu2_2.rb +162 -0
  35. data/lib/onc_certification_g10_test_kit/smart_scopes_test.rb +10 -2
  36. data/lib/onc_certification_g10_test_kit/smart_standalone_patient_app_group.rb +159 -0
  37. data/lib/onc_certification_g10_test_kit/smart_v1_scopes_group.rb +117 -0
  38. data/lib/onc_certification_g10_test_kit/terminology_binding_validator.rb +5 -1
  39. data/lib/onc_certification_g10_test_kit/token_introspection_group_stu2_2.rb +97 -0
  40. data/lib/onc_certification_g10_test_kit/unrestricted_resource_type_access_group.rb +85 -31
  41. data/lib/onc_certification_g10_test_kit/version.rb +1 -1
  42. data/lib/onc_certification_g10_test_kit/visual_inspection_and_attestations_group.rb +171 -0
  43. data/lib/onc_certification_g10_test_kit/well_known_capabilities_test.rb +1 -1
  44. data/lib/onc_certification_g10_test_kit.rb +72 -5
  45. metadata +18 -10
@@ -0,0 +1,219 @@
1
+ require_relative 'incorrectly_permitted_tls_versions_messages_setup_test'
2
+
3
+ module ONCCertificationG10TestKit
4
+ class SinglePatientUSCore7APIGroup < Inferno::TestGroup
5
+ id :g10_single_patient_us_core_7_api
6
+ title 'Single Patient API (US Core 7.0.0)'
7
+ short_title 'Single Patient API'
8
+ description %(
9
+ This scenario verifies the ability of a system to provide a 'Single Patient API'
10
+ as described in the (g)(10) Standardized API certification criterion.
11
+ Prior to running this scenario, systems must recieve a verified access token
12
+ from one of the previous SMART App Launch scenarios.
13
+
14
+ For each of the relevant USCDI data elements provided in the
15
+ CapabilityStatement, this scenario executes the [required supported
16
+ searches](http://hl7.org/fhir/us/core/STU7/CapabilityStatement-us-core-server.html)
17
+ as defined by the US Core Implementation Guide v7.0.0.
18
+
19
+ The test begins by searching by one or more patients, with the expectation
20
+ that the Bearer token provided to the test grants access to all USCDI
21
+ resources. It uses results returned from that query to generate other
22
+ queries and checks that the results are consistent with the provided
23
+ search parameters. It then performs a read on each Resource returned and
24
+ validates the response against the relevant
25
+ [profile](http://hl7.org/fhir/us/core/STU7/profiles-and-extensions.html)
26
+ as currently defined in the US Core Implementation Guide.
27
+
28
+ All MUST SUPPORT elements must be seen before the test can pass, as well
29
+ as Data Absent Reason to demonstrate that the server can properly handle
30
+ missing data. Note that Organization, Practitioner, and RelatedPerson
31
+ resources must be accessible as references in some US Core profiles to
32
+ satisfy must support requirements, and those references will be validated
33
+ to their US Core profile. These resources will not be tested for FHIR
34
+ search support.
35
+ )
36
+ run_as_group
37
+
38
+ input :url,
39
+ title: 'FHIR Endpoint',
40
+ description: 'URL of the FHIR endpoint used by SMART applications'
41
+ input :patient_id,
42
+ title: 'Patient ID from SMART App Launch',
43
+ locked: true
44
+ input :additional_patient_ids,
45
+ title: 'Additional Patient IDs',
46
+ description: <<~DESCRIPTION,
47
+ Comma separated list of Patient IDs that together with the Patient
48
+ ID from the SMART App Launch contain all MUST SUPPORT elements.
49
+ DESCRIPTION
50
+ optional: true
51
+ input :smart_credentials,
52
+ title: 'SMART App Launch Credentials',
53
+ type: :oauth_credentials,
54
+ locked: true
55
+
56
+ fhir_client do
57
+ url :url
58
+ oauth_credentials :smart_credentials
59
+ end
60
+
61
+ input_order :url, :patient_id, :additional_patient_ids, :implantable_device_codes, :smart_credentials
62
+
63
+ config(
64
+ options: {
65
+ required_profiles: [
66
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-allergyintolerance',
67
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-careplan',
68
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-careteam',
69
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition-encounter-diagnosis',
70
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition-problems-health-concerns',
71
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-coverage',
72
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-implantable-device',
73
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-diagnosticreport-lab',
74
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-diagnosticreport-note',
75
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-documentreference',
76
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-encounter',
77
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-goal',
78
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-immunization',
79
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-location',
80
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-medicationdispense',
81
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-medicationrequest',
82
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-lab',
83
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-blood-pressure',
84
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-bmi',
85
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-head-circumference',
86
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-body-height',
87
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-body-weight',
88
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-body-temperature',
89
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-heart-rate',
90
+ 'http://hl7.org/fhir/us/core/StructureDefinition/pediatric-bmi-for-age',
91
+ 'http://hl7.org/fhir/us/core/StructureDefinition/head-occipital-frontal-circumference-percentile',
92
+ 'http://hl7.org/fhir/us/core/StructureDefinition/pediatric-weight-for-height',
93
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-pulse-oximetry',
94
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-respiratory-rate',
95
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-smokingstatus',
96
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-clinical-result',
97
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-occupation',
98
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-pregnancyintent',
99
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-pregnancystatus',
100
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-screening-assessment',
101
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-sexual-orientation',
102
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-treatment-intervention-preference',
103
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-care-experience-preference',
104
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-average-blood-pressure',
105
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-organization',
106
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient',
107
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-practitioner',
108
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-procedure',
109
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-provenance',
110
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-relatedperson',
111
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-servicerequest',
112
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-specimen'
113
+ ],
114
+ tag_requests: true
115
+ }
116
+ )
117
+
118
+ config(
119
+ options: {
120
+ required_resources: [
121
+ 'Patient',
122
+ 'AllergyIntolerance',
123
+ 'CarePlan',
124
+ 'CareTeam',
125
+ 'Condition',
126
+ 'Coverage',
127
+ 'Device',
128
+ 'DiagnosticReport',
129
+ 'DocumentReference',
130
+ 'Encounter',
131
+ 'Goal',
132
+ 'Immunization',
133
+ 'Location',
134
+ 'MedicationDispense',
135
+ 'MedicationRequest',
136
+ 'Observation',
137
+ 'Procedure',
138
+ 'ServiceRequest',
139
+ 'Specimen',
140
+ 'Organization',
141
+ 'Practitioner',
142
+ 'Provenance',
143
+ 'RelatedPerson'
144
+ ]
145
+ }
146
+ )
147
+
148
+ test do
149
+ id :g10_patient_id_setup
150
+ title 'Manage patient id list'
151
+
152
+ input :patient_id, :additional_patient_ids
153
+ output :patient_ids
154
+
155
+ run do
156
+ smart_app_launch_patient_id = patient_id.presence
157
+ additional_patient_ids_list =
158
+ if additional_patient_ids.present?
159
+ additional_patient_ids
160
+ .split(',')
161
+ .map(&:strip)
162
+ .map(&:presence)
163
+ .compact
164
+ else
165
+ []
166
+ end
167
+
168
+ all_patient_ids = ([smart_app_launch_patient_id] + additional_patient_ids_list).compact.uniq
169
+
170
+ output patient_ids: all_patient_ids.join(',')
171
+ end
172
+ end
173
+
174
+ USCoreTestKit::USCoreV700::USCoreTestSuite.groups.find { |g| g.title == 'US Core FHIR API' }.groups.each do |group|
175
+ test_group = group.ancestors[1]
176
+
177
+ next if test_group.optional?
178
+
179
+ id = test_group.id
180
+
181
+ group_config = {}
182
+ if test_group.respond_to?(:metadata) &&
183
+ test_group.metadata.delayed? &&
184
+ !test_group.metadata.searchable_delayed_resource?
185
+ test_group.children.reject! do |child|
186
+ child.include?(USCoreTestKit::SearchTest) &&
187
+ !child.include?(USCoreTestKit::PractitionerAddressTest)
188
+ end
189
+ group_config[:options] = { read_all_resources: true }
190
+ end
191
+
192
+ group(from: id, exclude_optional: true, config: group_config)
193
+ end
194
+
195
+ groups.first.description %(
196
+ The Capability Statement test verifies a FHIR server's ability support the
197
+ [capabilities
198
+ operation](https://www.hl7.org/fhir/R4/capabilitystatement.html#instance)
199
+ to formally describe features supported by the API as a [Capability
200
+ Statement](https://www.hl7.org/fhir/R4/capabilitystatement.html) resource.
201
+ The capabilities described in the Capability Statement must be consistent with
202
+ the required capabilities of a US Core server. This test also expects that
203
+ APIs state support for all resources types applicable to USCDI v3, as is
204
+ expected by the ONC (g)(10) Standardized API for Patient and Populations
205
+ Services certification criterion.
206
+
207
+ This test sequence accesses the server endpoint at `/metadata` using a
208
+ `GET` request. It parses the Capability Statement and verifies that:
209
+
210
+ * The endpoint is secured by an appropriate cryptographic protocol
211
+ * The resource matches the expected FHIR version defined by the tests
212
+ * The resource is a valid FHIR resource
213
+ * The server claims support for JSON encoding of resources
214
+ * The server claims support for all required USCDI resource types
215
+ )
216
+
217
+ test from: :g10_incorrectly_permitted_tls_versions_messages_setup
218
+ end
219
+ end
@@ -117,7 +117,47 @@ module ONCCertificationG10TestKit
117
117
  end
118
118
 
119
119
  test from: :smart_app_redirect_stu2 do
120
- required_suite_options G10Options::SMART_2_REQUIREMENT
120
+ id :smart_app_redirect_stu2
121
+ required_suite_options(G10Options::SMART_2_REQUIREMENT)
122
+
123
+ config(
124
+ inputs: {
125
+ use_pkce: {
126
+ default: 'true',
127
+ locked: true
128
+ },
129
+ pkce_code_challenge_method: {
130
+ locked: true
131
+ }
132
+ }
133
+ )
134
+
135
+ input :client_secret,
136
+ name: :standalone_client_secret,
137
+ title: 'Standalone Client Secret',
138
+ description: 'Client Secret provided during registration of Inferno as a standalone application'
139
+
140
+ def aud
141
+ 'https://inferno.healthit.gov/invalid_aud'
142
+ end
143
+
144
+ def wait_message(auth_url)
145
+ %(
146
+ Inferno will redirect you to an external website for authorization.
147
+ **It is expected this will fail**. If the server does not return to
148
+ Inferno automatically, but does provide an error message, you may
149
+ return to Inferno and confirm that an error was presented in this
150
+ window.
151
+
152
+ * [Perform Invalid Launch](#{auth_url})
153
+ * [Attest launch
154
+ failed](#{Inferno::Application['base_url']}/custom/smart/redirect?state=#{state}&confirm_fail=true)
155
+ )
156
+ end
157
+ end
158
+ test from: :smart_app_redirect_stu2 do
159
+ required_suite_options(G10Options::SMART_2_2_REQUIREMENT)
160
+ id :smart_app_redirect_stu2_2 # rubocop:disable Naming/VariableNumber
121
161
 
122
162
  config(
123
163
  inputs: {
@@ -142,9 +142,41 @@ module ONCCertificationG10TestKit
142
142
  :asymmetric_client_auth_type,
143
143
  :client_auth_encryption_method
144
144
 
145
- group from: :smart_discovery_stu2
145
+ group from: :smart_discovery_stu2,
146
+ required_suite_options: G10Options::SMART_2_REQUIREMENT
147
+ group from: :smart_discovery_stu2_2, # rubocop:disable Naming/VariableNumber
148
+ required_suite_options: G10Options::SMART_2_2_REQUIREMENT
146
149
 
147
150
  group from: :smart_standalone_launch_stu2 do
151
+ required_suite_options(G10Options::SMART_2_REQUIREMENT)
152
+ test from: :g10_patient_context,
153
+ config: {
154
+ inputs: {
155
+ patient_id: { name: :asymmetric_patient_id },
156
+ smart_credentials: { name: :asymmetric_smart_credentials }
157
+ }
158
+ }
159
+
160
+ test do
161
+ title 'OAuth token exchange response contains OpenID Connect id_token'
162
+ description %(
163
+ This test requires that an OpenID Connect id_token is provided to
164
+ demonstrate authentication capabilies for asymmetric clients.
165
+ )
166
+ id :g10_asymmetric_launch_id_token
167
+
168
+ input :id_token,
169
+ name: :asymmetric_id_token,
170
+ locked: true,
171
+ optional: true
172
+
173
+ run do
174
+ assert id_token.present?, 'Token response did not provide an id_token as required.'
175
+ end
176
+ end
177
+ end
178
+ group from: :smart_standalone_launch_stu2_2 do # rubocop:disable Naming/VariableNumber
179
+ required_suite_options(G10Options::SMART_2_2_REQUIREMENT)
148
180
  test from: :g10_patient_context,
149
181
  config: {
150
182
  inputs: {
@@ -0,0 +1,128 @@
1
+ require_relative 'patient_scope_test'
2
+
3
+ module ONCCertificationG10TestKit
4
+ class SMARTEHRPatientLaunchGroupSTU22 < SMARTAppLaunch::EHRLaunchGroupSTU22
5
+ title 'EHR Launch with Patient Scopes'
6
+ description %(
7
+ Systems are required to support the `permission-patient` capability as
8
+ part of the [Clinician Access for EHR Launch Capability
9
+ Set.](http://hl7.org/fhir/smart-app-launch/STU2.2/conformance.html#clinician-access-for-ehr-launch)
10
+ Previous scenarios do not verify this specific combination of capabilies.
11
+
12
+ Additionally, if an application launched from an EHR requests and is
13
+ granted a clinical scope restricted to a single patient, the EHR SHALL
14
+ establish a patient in context.
15
+
16
+ Register Inferno as an EHR-launched application using patient-level scopes
17
+ and the following URIs:
18
+
19
+ * Launch URI: `#{SMARTAppLaunch::AppLaunchTest.config.options[:launch_uri]}`
20
+ * Redirect URI: `#{SMARTAppLaunch::AppRedirectTest.config.options[:redirect_uri]}`
21
+
22
+ In this scenario, Inferno will attempt an EHR Launch with a clinical scope restricted to a
23
+ single patient and verify that a patient-level scope is granted and a
24
+ patient id is received.
25
+
26
+ For more information on the #{title}
27
+
28
+ * [Apps that launch from the
29
+ EHR](http://hl7.org/fhir/smart-app-launch/STU2.2/scopes-and-launch-context.html#apps-that-launch-from-the-ehr)
30
+ )
31
+ id :g10_ehr_patient_launch_stu2_2 # rubocop:disable Naming/VariableNumber
32
+ run_as_group
33
+
34
+ config(
35
+ inputs: {
36
+ client_id: {
37
+ name: :ehr_patient_client_id
38
+ },
39
+ client_secret: {
40
+ name: :ehr_patient_client_secret,
41
+ optional: false
42
+ },
43
+ requested_scopes: {
44
+ name: :ehr_patient_requested_scopes,
45
+ default: 'launch openid fhirUser offline_access patient/Patient.rs',
46
+ locked: true
47
+ },
48
+ code: {
49
+ name: :ehr_patient_code
50
+ },
51
+ state: {
52
+ name: :ehr_patient_state
53
+ },
54
+ launch: {
55
+ name: :ehr_patient_launch
56
+ },
57
+ received_scopes: {
58
+ name: :ehr_patient_received_scopes
59
+ },
60
+ smart_credentials: {
61
+ name: :ehr_patient_smart_credentials
62
+ },
63
+ smart_authorization_url: {
64
+ title: 'OAuth 2.0 Authorize Endpoint',
65
+ description: 'OAuth 2.0 Authorize Endpoint provided during the EHR launch'
66
+ },
67
+ smart_token_url: {
68
+ title: 'OAuth 2.0 Token Endpoint',
69
+ description: 'OAuth 2.0 Token Endpoint provided during the EHR launch'
70
+ },
71
+ client_auth_type: {
72
+ locked: true,
73
+ default: 'confidential_symmetric'
74
+ }
75
+ },
76
+ outputs: {
77
+ launch: { name: :ehr_patient_launch },
78
+ code: { name: :ehr_patient_code },
79
+ token_retrieval_time: { name: :ehr_patient_token_retrieval_time },
80
+ state: { name: :ehr_patient_state },
81
+ id_token: { name: :ehr_patient_id_token },
82
+ refresh_token: { name: :ehr_patient_refresh_token },
83
+ access_token: { name: :ehr_patient_access_token },
84
+ expires_in: { name: :ehr_patient_expires_in },
85
+ patient_id: { name: :ehr_patient_patient_id },
86
+ encounter_id: { name: :ehr_patient_encounter_id },
87
+ received_scopes: { name: :ehr_patient_received_scopes },
88
+ requested_scopes: { name: :ehr_patient_requested_scopes },
89
+ intent: { name: :ehr_patient_intent },
90
+ smart_credentials: { name: :ehr_patient_smart_credentials }
91
+ },
92
+ requests: {
93
+ redirect: { name: :ehr_patient_redirect },
94
+ token: { name: :ehr_patient_token }
95
+ }
96
+ )
97
+
98
+ input_order :url,
99
+ :ehr_patient_client_id,
100
+ :ehr_patient_client_secret,
101
+ :smart_authorization_url,
102
+ :smart_token_url,
103
+ :ehr_patient_requested_scopes,
104
+ :authorization_method,
105
+ :use_pkce,
106
+ :pkce_code_challenge_method,
107
+ :client_auth_type
108
+
109
+ test from: :g10_patient_context,
110
+ config: {
111
+ inputs: {
112
+ patient_id: { name: :ehr_patient_patient_id },
113
+ smart_credentials: { name: :ehr_patient_smart_credentials }
114
+ }
115
+ }
116
+
117
+ test from: :g10_patient_scope,
118
+ config: {
119
+ options: {
120
+ scope_version: :v22
121
+ }
122
+ }
123
+
124
+ children.each do |child|
125
+ child.inputs.delete(:client_auth_encryption_method)
126
+ end
127
+ end
128
+ end