onc_certification_g10_test_kit 6.0.3 → 7.0.1

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.
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