onc_certification_g10_test_kit 3.3.1 → 3.4.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/lib/inferno/terminology/terminology_validation.rb +9 -6
- data/lib/onc_certification_g10_test_kit/bulk_data_group_export_validation.rb +2 -1
- data/lib/onc_certification_g10_test_kit/bulk_export_validation_tester.rb +20 -14
- data/lib/onc_certification_g10_test_kit/onc_program_procedure.yml +1 -1
- data/lib/onc_certification_g10_test_kit/profile_selector.rb +68 -62
- data/lib/onc_certification_g10_test_kit/resource_access_test.rb +2 -1
- data/lib/onc_certification_g10_test_kit/short_id_map.yml +1 -0
- data/lib/onc_certification_g10_test_kit/smart_scopes_test.rb +1 -1
- data/lib/onc_certification_g10_test_kit/terminology_binding_validator.rb +9 -13
- data/lib/onc_certification_g10_test_kit/token_revocation_group.rb +1 -1
- data/lib/onc_certification_g10_test_kit/version.rb +1 -1
- data/lib/onc_certification_g10_test_kit/visual_inspection_and_attestations_group.rb +70 -5
- data/lib/onc_certification_g10_test_kit.rb +12 -3
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98375c6a97ac9a9056303f326b8dbe742b636ce9aec9751d8ece7e9d2cc3850f
|
4
|
+
data.tar.gz: 63905d2ab2aed1d6ce3beddeb09ea3670885dbf78d5f86628d0dd9efd4efdbd0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 023317c28042a98b0b9ed4bce639906668463655082abaefe9e033bf133b76f8dec8bb0b9af7005f0aa65ba0bca5bd00a817e3c88b542eaf72bc17cce0818829
|
7
|
+
data.tar.gz: d216f8e2193a35a3a433b4ecda391a73c964f2df029d167b225c64c7f91f72d3bbd0ce7cd67833742ac991325634fa0080668a6cea98d5b295cf127832183db9
|
@@ -4,27 +4,30 @@ require_relative '../terminology/bcp_13'
|
|
4
4
|
module Inferno
|
5
5
|
module Terminology
|
6
6
|
module TerminologyValidation
|
7
|
-
#
|
7
|
+
# CodeSystems/ValueSets to "preprocess" prior to validation, and the
|
8
|
+
# function to use
|
8
9
|
PREPROCESS_FUNCS = {
|
9
|
-
'urn:ietf:bcp:13' => BCP13.method(:preprocess_code)
|
10
|
+
'urn:ietf:bcp:13' => BCP13.method(:preprocess_code),
|
11
|
+
'http://hl7.org/fhir/ValueSet/mimetypes' => BCP13.method(:preprocess_code)
|
10
12
|
}.freeze
|
11
13
|
|
12
14
|
def validators_repo
|
13
15
|
@validators_repo ||= Repositories::Validators.new
|
14
16
|
end
|
15
17
|
|
16
|
-
# This function accepts a valueset URL, code, and optional system, and
|
17
|
-
# if the code or code/system combination is valid for the
|
18
|
-
# represented by that URL
|
18
|
+
# This function accepts a valueset URL, code, and optional system, and
|
19
|
+
# returns true if the code or code/system combination is valid for the
|
20
|
+
# valueset represented by that URL
|
19
21
|
#
|
20
22
|
# @param String value_set_url the URL for the valueset to validate against
|
21
23
|
# @param String code the code to validate against the valueset
|
22
|
-
# @param String system an optional codesystem to validate against.
|
24
|
+
# @param String system an optional codesystem to validate against.
|
23
25
|
# @return Boolean whether the code or code/system is in the valueset
|
24
26
|
def validate_code(code:, value_set_url: nil, system: nil)
|
25
27
|
# Before we validate the code, see if there's any preprocessing steps we have to do
|
26
28
|
# To get the code "ready" for validation
|
27
29
|
code = PREPROCESS_FUNCS[system].call(code) if PREPROCESS_FUNCS[system]
|
30
|
+
code = PREPROCESS_FUNCS[value_set_url].call(code) if PREPROCESS_FUNCS[value_set_url]
|
28
31
|
|
29
32
|
# Get the valueset from the url. Redundant if the 'system' is not nil,
|
30
33
|
# but allows us to throw a better error if the valueset isn't known by Inferno
|
@@ -17,11 +17,12 @@ module ONCCertificationG10TestKit
|
|
17
17
|
optional: true
|
18
18
|
input :bulk_patient_ids_in_group,
|
19
19
|
title: 'Patient IDs in exported Group',
|
20
|
-
description: <<~DESCRIPTION
|
20
|
+
description: <<~DESCRIPTION,
|
21
21
|
Comma separated list of every Patient ID that is in the specified Group. This information is provided by
|
22
22
|
the system under test to verify that data returned matches expectations. Leave blank to not verify Group
|
23
23
|
inclusion.
|
24
24
|
DESCRIPTION
|
25
|
+
optional: true
|
25
26
|
input :bulk_device_types_in_group,
|
26
27
|
title: 'Implantable Device Type Codes in exported Group',
|
27
28
|
description: <<~DESCRIPTION,
|
@@ -107,6 +107,9 @@ module ONCCertificationG10TestKit
|
|
107
107
|
perform_must_support_test(resources[meta.profile_url])
|
108
108
|
rescue Inferno::Exceptions::PassException
|
109
109
|
next
|
110
|
+
rescue Inferno::Exceptions::SkipException => e
|
111
|
+
e.message.concat " for `#{meta.profile_url}`"
|
112
|
+
raise e
|
110
113
|
end
|
111
114
|
end
|
112
115
|
end
|
@@ -121,7 +124,7 @@ module ONCCertificationG10TestKit
|
|
121
124
|
line_count = 0
|
122
125
|
resources = Hash.new { |h, k| h[k] = [] }
|
123
126
|
|
124
|
-
process_line = proc
|
127
|
+
process_line = proc do |line|
|
125
128
|
next unless lines_to_validate.blank? ||
|
126
129
|
line_count < lines_to_validate.to_i ||
|
127
130
|
(resource_type == 'Patient' && patient_ids_seen.length < MIN_RESOURCE_COUNT)
|
@@ -139,21 +142,24 @@ module ONCCertificationG10TestKit
|
|
139
142
|
"defined in output \"#{resource_type}\""
|
140
143
|
end
|
141
144
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
145
|
+
profile_urls = determine_profile(resource)
|
146
|
+
profile_urls.each do |profile_url|
|
147
|
+
resources[profile_url] << resource
|
148
|
+
|
149
|
+
scratch[:patient_ids_seen] = patient_ids_seen | [resource.id] if resource_type == 'Patient'
|
150
|
+
|
151
|
+
profile_with_version = versioned_profile_url(profile_url)
|
152
|
+
unless resource_is_valid?(resource:, profile_url: profile_with_version)
|
153
|
+
if first_error.key?(:line_number)
|
154
|
+
@invalid_resource_count += 1
|
155
|
+
else
|
156
|
+
@invalid_resource_count = 1
|
157
|
+
first_error[:line_number] = line_count
|
158
|
+
first_error[:messages] = messages.dup
|
159
|
+
end
|
154
160
|
end
|
155
161
|
end
|
156
|
-
|
162
|
+
end
|
157
163
|
|
158
164
|
process_headers = proc { |response|
|
159
165
|
value = (response[:headers].find { |header| header.name.downcase == 'content-type' })&.value
|
@@ -960,7 +960,7 @@ procedure:
|
|
960
960
|
implementation specification adopted in § 170.215(a)(3).
|
961
961
|
inferno_supported: 'yes'
|
962
962
|
inferno_tests:
|
963
|
-
- 9.10.
|
963
|
+
- 9.10.16
|
964
964
|
inferno_notes: |
|
965
965
|
Inferno cannot verify the three month token expiration requirement
|
966
966
|
automatically during the token refresh tests, but the tester can
|
@@ -30,46 +30,50 @@ module ONCCertificationG10TestKit
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def select_profile(resource) # rubocop:disable Metrics/CyclomaticComplexity
|
33
|
+
profiles = []
|
34
|
+
|
33
35
|
case resource.resourceType
|
34
36
|
when 'Condition'
|
35
37
|
case us_core_version
|
36
38
|
when US_CORE_5
|
37
39
|
if resource_contains_category(resource, 'encounter-diagnosis', 'http://terminology.hl7.org/CodeSystem/condition-category')
|
38
|
-
extract_profile('ConditionEncounterDiagnosis')
|
40
|
+
profiles << extract_profile('ConditionEncounterDiagnosis')
|
39
41
|
elsif resource_contains_category(resource, 'problem-list-item',
|
40
42
|
'http://terminology.hl7.org/CodeSystem/condition-category') ||
|
41
|
-
resource_contains_category(resource, 'health-concern', 'http://
|
42
|
-
extract_profile('ConditionProblemsHealthConcerns')
|
43
|
+
resource_contains_category(resource, 'health-concern', 'http://hl7.org/fhir/us/core/CodeSystem/condition-category')
|
44
|
+
profiles << extract_profile('ConditionProblemsHealthConcerns')
|
43
45
|
end
|
44
46
|
else
|
45
|
-
extract_profile(resource.resourceType)
|
47
|
+
profiles << extract_profile(resource.resourceType)
|
46
48
|
end
|
47
49
|
when 'DiagnosticReport'
|
48
|
-
|
49
|
-
|
50
|
-
|
50
|
+
profiles << if resource_contains_category(resource, 'LAB', 'http://terminology.hl7.org/CodeSystem/v2-0074')
|
51
|
+
extract_profile('DiagnosticReportLab')
|
52
|
+
else
|
53
|
+
extract_profile('DiagnosticReportNote')
|
54
|
+
end
|
51
55
|
when 'Observation'
|
52
|
-
|
56
|
+
profiles << extract_profile('Smokingstatus') if observation_contains_code(resource, '72166-2')
|
53
57
|
|
54
|
-
|
58
|
+
profiles << extract_profile('ObservationLab') if resource_contains_category(resource, 'laboratory', 'http://terminology.hl7.org/CodeSystem/observation-category')
|
55
59
|
|
56
|
-
|
60
|
+
profiles << extract_profile('PediatricBmiForAge') if observation_contains_code(resource, '59576-9')
|
57
61
|
|
58
|
-
|
62
|
+
profiles << extract_profile('PediatricWeightForHeight') if observation_contains_code(resource, '77606-2')
|
59
63
|
|
60
|
-
|
64
|
+
profiles << extract_profile('PulseOximetry') if observation_contains_code(resource, '59408-5')
|
61
65
|
|
62
66
|
if observation_contains_code(resource, '8289-1')
|
63
|
-
case us_core_version
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
67
|
+
profiles << case us_core_version
|
68
|
+
when US_CORE_3
|
69
|
+
extract_profile('HeadCircumference')
|
70
|
+
else
|
71
|
+
extract_profile('HeadCircumferencePercentile')
|
72
|
+
end
|
69
73
|
end
|
70
74
|
|
71
75
|
if observation_contains_code(resource, '9843-4') && !using_us_core_3?
|
72
|
-
|
76
|
+
profiles << extract_profile('HeadCircumference')
|
73
77
|
end
|
74
78
|
|
75
79
|
# FHIR Vital Signs profiles: https://www.hl7.org/fhir/observation-vitalsigns.html
|
@@ -77,83 +81,83 @@ module ONCCertificationG10TestKit
|
|
77
81
|
# Body Mass Index is replaced by :pediatric_bmi_age Profile
|
78
82
|
# Systolic Blood Pressure, Diastolic Blood Pressure are covered by :blood_pressure Profile
|
79
83
|
# Head Circumference is replaced by US Core Head Occipital-frontal Circumference Percentile Profile
|
80
|
-
|
84
|
+
profiles << extract_profile('Bmi') if observation_contains_code(resource, '39156-5') && !using_us_core_3?
|
81
85
|
|
82
86
|
if observation_contains_code(resource, '85354-9')
|
83
|
-
case us_core_version
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
87
|
+
profiles << case us_core_version
|
88
|
+
when US_CORE_3
|
89
|
+
extract_profile('Bp')
|
90
|
+
else
|
91
|
+
extract_profile('BloodPressure')
|
92
|
+
end
|
89
93
|
end
|
90
94
|
|
91
95
|
if observation_contains_code(resource, '8302-2')
|
92
|
-
case us_core_version
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
96
|
+
profiles << case us_core_version
|
97
|
+
when US_CORE_3
|
98
|
+
extract_profile('Bodyheight')
|
99
|
+
else
|
100
|
+
extract_profile('BodyHeight')
|
101
|
+
end
|
98
102
|
end
|
99
103
|
|
100
104
|
if observation_contains_code(resource, '8310-5')
|
101
|
-
case us_core_version
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
105
|
+
profiles << case us_core_version
|
106
|
+
when US_CORE_3
|
107
|
+
extract_profile('Bodytemp')
|
108
|
+
else
|
109
|
+
extract_profile('BodyTemperature')
|
110
|
+
end
|
107
111
|
end
|
108
112
|
|
109
113
|
if observation_contains_code(resource, '29463-7')
|
110
|
-
case us_core_version
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
114
|
+
profiles << case us_core_version
|
115
|
+
when US_CORE_3
|
116
|
+
extract_profile('Bodyweight')
|
117
|
+
else
|
118
|
+
extract_profile('BodyWeight')
|
119
|
+
end
|
116
120
|
end
|
117
121
|
|
118
122
|
if observation_contains_code(resource, '8867-4')
|
119
|
-
case us_core_version
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
123
|
+
profiles << case us_core_version
|
124
|
+
when US_CORE_3
|
125
|
+
extract_profile('Heartrate')
|
126
|
+
else
|
127
|
+
extract_profile('HeartRate')
|
128
|
+
end
|
125
129
|
end
|
126
130
|
|
127
131
|
if observation_contains_code(resource, '9279-1')
|
128
|
-
case us_core_version
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
132
|
+
profiles << case us_core_version
|
133
|
+
when US_CORE_3
|
134
|
+
extract_profile('Resprate')
|
135
|
+
else
|
136
|
+
extract_profile('RespiratoryRate')
|
137
|
+
end
|
134
138
|
end
|
135
139
|
|
136
140
|
if using_us_core_5? &&
|
137
141
|
resource_contains_category(
|
138
142
|
resource, 'clinical-test', 'http://hl7.org/fhir/us/core/CodeSystem/us-core-observation-category'
|
139
143
|
)
|
140
|
-
|
144
|
+
profiles << extract_profile('ObservationClinicalTest')
|
141
145
|
end
|
142
146
|
|
143
147
|
if using_us_core_5? && observation_contains_code(resource, '76690-7')
|
144
|
-
|
148
|
+
profiles << extract_profile('ObservationSexualOrientation')
|
145
149
|
end
|
146
150
|
|
147
151
|
if using_us_core_5? &&
|
148
152
|
resource_contains_category(resource, 'social-history',
|
149
153
|
'http://terminology.hl7.org/CodeSystem/observation-category')
|
150
|
-
|
154
|
+
profiles << extract_profile('ObservationSocialHistory')
|
151
155
|
end
|
152
156
|
|
153
157
|
if using_us_core_5? &&
|
154
158
|
resource_contains_category(resource, 'imaging',
|
155
159
|
'http://terminology.hl7.org/CodeSystem/observation-category')
|
156
|
-
|
160
|
+
profiles << extract_profile('ObservationImaging')
|
157
161
|
end
|
158
162
|
|
159
163
|
# We will simply match all Observations of category "survey" to SDOH,
|
@@ -171,13 +175,15 @@ module ONCCertificationG10TestKit
|
|
171
175
|
resource_contains_category(resource, 'survey',
|
172
176
|
'http://terminology.hl7.org/CodeSystem/observation-category')
|
173
177
|
|
174
|
-
|
178
|
+
profiles << extract_profile('ObservationSdohAssessment')
|
175
179
|
end
|
176
180
|
|
177
181
|
nil
|
178
182
|
else
|
179
|
-
extract_profile(resource.resourceType)
|
183
|
+
profiles << extract_profile(resource.resourceType)
|
180
184
|
end
|
185
|
+
|
186
|
+
profiles
|
181
187
|
rescue StandardError
|
182
188
|
skip "Could not determine profile of \"#{resource.resourceType}\" resource."
|
183
189
|
end
|
@@ -87,7 +87,8 @@ module ONCCertificationG10TestKit
|
|
87
87
|
assert_response_status(200)
|
88
88
|
pass "Access expected to be granted and request properly returned #{request.status}"
|
89
89
|
else
|
90
|
-
message =
|
90
|
+
message =
|
91
|
+
"Unexpected response code: expected 403 (Forbidden) or 401 (Unauthorized), but found #{request.status}."
|
91
92
|
assert [401, 403].include?(request.status), message
|
92
93
|
end
|
93
94
|
end
|
@@ -1536,3 +1536,4 @@ g10_certification-Group06-g10_visual_inspection_and_attestations-Test12: 9.10.12
|
|
1536
1536
|
g10_certification-Group06-g10_visual_inspection_and_attestations-Test13: 9.10.13
|
1537
1537
|
g10_certification-Group06-g10_visual_inspection_and_attestations-g10_public_url_attestation: 9.10.14
|
1538
1538
|
g10_certification-Group06-g10_visual_inspection_and_attestations-g10_tls_version_attestation: 9.10.15
|
1539
|
+
g10_certification-Group06-g10_visual_inspection_and_attestations-g10_refresh_token_refresh_attestation: 9.10.16
|
@@ -41,7 +41,7 @@ module ONCCertificationG10TestKit
|
|
41
41
|
].freeze
|
42
42
|
|
43
43
|
V5_VALID_RESOURCE_TYPES =
|
44
|
-
(VALID_RESOURCE_TYPES + ['ServiceRequest', 'QuestionnaireResponse']).freeze
|
44
|
+
(VALID_RESOURCE_TYPES + ['ServiceRequest', 'QuestionnaireResponse', 'Media']).freeze
|
45
45
|
|
46
46
|
PATIENT_COMPARTMENT_RESOURCE_TYPES = [
|
47
47
|
'*',
|
@@ -18,15 +18,10 @@ module ONCCertificationG10TestKit
|
|
18
18
|
@validation_messages = []
|
19
19
|
end
|
20
20
|
|
21
|
-
def us_core_5_condition_category?
|
22
|
-
binding_definition[:path] == 'category' &&
|
23
|
-
binding_definition[:system] == 'http://hl7.org/fhir/us/core/ValueSet/us-core-problem-or-health-concern'
|
24
|
-
end
|
25
|
-
|
26
21
|
def validate
|
27
22
|
# Handle special case due to required binding on a slice
|
28
|
-
if
|
29
|
-
|
23
|
+
if binding_definition[:required_binding_slice]
|
24
|
+
validate_required_binding_slice
|
30
25
|
else
|
31
26
|
add_error(element_with_invalid_binding) if element_with_invalid_binding.present? # rubocop:disable Style/IfInsideElse
|
32
27
|
end
|
@@ -34,18 +29,19 @@ module ONCCertificationG10TestKit
|
|
34
29
|
validation_messages
|
35
30
|
end
|
36
31
|
|
37
|
-
def
|
38
|
-
|
32
|
+
def validate_required_binding_slice
|
33
|
+
valid_binding =
|
39
34
|
find_a_value_at(path_source, binding_definition[:path]) do |element|
|
40
35
|
!invalid_binding?(element)
|
41
36
|
end
|
42
37
|
|
43
|
-
return if
|
38
|
+
return if valid_binding.present?
|
39
|
+
|
40
|
+
system = binding_definition[:system].presence || 'the declared Value Set'
|
44
41
|
|
45
42
|
error_message = %(
|
46
|
-
#{resource_type}/#{resource.id}
|
47
|
-
|
48
|
-
ValueSet.
|
43
|
+
#{resource_type}/#{resource.id} at #{resource_type}.#{binding_definition[:path]}
|
44
|
+
does not contain a valid code from #{system}.
|
49
45
|
)
|
50
46
|
|
51
47
|
validation_messages << {
|
@@ -45,7 +45,7 @@ module ONCCertificationG10TestKit
|
|
45
45
|
|
46
46
|
run do
|
47
47
|
assert token_revocation_attestation == 'true',
|
48
|
-
'Health IT Module did not demonstrate
|
48
|
+
'Health IT Module did not demonstrate the ability to revoke tokens.'
|
49
49
|
pass token_revocation_notes if token_revocation_notes.present?
|
50
50
|
end
|
51
51
|
end
|
@@ -155,6 +155,9 @@ module ONCCertificationG10TestKit
|
|
155
155
|
description %(
|
156
156
|
Health IT Module attested that it is capable of issuing refresh tokens
|
157
157
|
that are valid for a period of no shorter than three months.
|
158
|
+
|
159
|
+
This attestation is necessary because automated tests cannot determine how long
|
160
|
+
the refresh token remains valid.
|
158
161
|
)
|
159
162
|
id 'Test05'
|
160
163
|
input :refresh_token_period_attestation,
|
@@ -328,16 +331,16 @@ module ONCCertificationG10TestKit
|
|
328
331
|
end
|
329
332
|
|
330
333
|
test do
|
331
|
-
title 'Health IT developer confirms the Health IT
|
334
|
+
title 'Health IT developer confirms the Health IT Module does not cache the JWK Set received ' \
|
332
335
|
'via a TLS-protected URL for longer than the cache-control header received by an application indicates.'
|
333
336
|
description %(
|
334
|
-
The Health IT developer confirms the Health IT
|
337
|
+
The Health IT developer confirms the Health IT Module does not cache the
|
335
338
|
JWK Set received via a TLS-protected URL for longer than the
|
336
339
|
cache-control header indicates.
|
337
340
|
)
|
338
341
|
id 'Test10'
|
339
342
|
input :jwks_cache_attestation,
|
340
|
-
title: 'Health IT developer confirms the Health IT
|
343
|
+
title: 'Health IT developer confirms the Health IT Module does not cache the JWK Set received via a TLS-protected URL for longer than the cache-control header indicates.', # rubocop:disable Layout/LineLength
|
341
344
|
type: 'radio',
|
342
345
|
default: 'false',
|
343
346
|
options: {
|
@@ -490,7 +493,7 @@ module ONCCertificationG10TestKit
|
|
490
493
|
end
|
491
494
|
|
492
495
|
test do
|
493
|
-
title 'Health IT developer demonstrates the public location of its base URLs'
|
496
|
+
title 'Health IT developer demonstrates the public location of its base URLs.'
|
494
497
|
description %(
|
495
498
|
To fulfill the API Maintenance of Certification requirement at §
|
496
499
|
170.404(b)(2), the health IT developer demonstrates the public location
|
@@ -542,7 +545,7 @@ module ONCCertificationG10TestKit
|
|
542
545
|
locked: true,
|
543
546
|
optional: true
|
544
547
|
input :tls_documentation_required,
|
545
|
-
title: 'Health IT developers must document how the Health IT Module enforces TLs version 1.2 or above',
|
548
|
+
title: 'Health IT developers must document how the Health IT Module enforces TLs version 1.2 or above.',
|
546
549
|
type: 'radio',
|
547
550
|
default: 'false',
|
548
551
|
locked: true,
|
@@ -572,5 +575,67 @@ module ONCCertificationG10TestKit
|
|
572
575
|
pass tls_version_attestation_notes if tls_version_attestation_notes.present?
|
573
576
|
end
|
574
577
|
end
|
578
|
+
|
579
|
+
test do
|
580
|
+
title 'Health IT developer attested that the Health IT Module is capable of issuing refresh tokens ' \
|
581
|
+
'valid for a new period of no shorter than three months without requiring ' \
|
582
|
+
're-authentication and re-authorization when a valid refresh token is supplied ' \
|
583
|
+
'by the application.'
|
584
|
+
description %(
|
585
|
+
Applications that are capable of storing a client secret and that have
|
586
|
+
received a refresh token must be able to use this refresh token to
|
587
|
+
either receive a new refresh token valid for a new period of no less
|
588
|
+
than three months, or to update the duration of the existing refresh
|
589
|
+
token to be valid for a new period of no less than three months. This
|
590
|
+
occurs during the refresh token request, when the application uses a
|
591
|
+
refresh token to receive a new access token.
|
592
|
+
|
593
|
+
This attestation is necessary because automated tests cannot determine
|
594
|
+
if the expiration date of the refresh token is updated when tokens
|
595
|
+
are refreshed.
|
596
|
+
|
597
|
+
This attestation ensures that the Health IT Module allows applications
|
598
|
+
to use refresh tokens to update the length of authorized access beyond
|
599
|
+
the initial period of no less than three months by issuing a new refresh
|
600
|
+
token or updating the duration of the existing refresh token. A
|
601
|
+
separate attestation ensures that the Health IT Module is capable of
|
602
|
+
issuing an initial refresh token that is valid for at least three
|
603
|
+
months.
|
604
|
+
)
|
605
|
+
id :g10_refresh_token_refresh_attestation
|
606
|
+
input :refresh_token_refresh_attestation,
|
607
|
+
title: 'Health IT developer attested that the Health IT Module is capable of issuing refresh tokens ' \
|
608
|
+
'valid for a new period of no shorter than three months without requiring ' \
|
609
|
+
're-authentication and re-authorization when a valid refresh token is supplied ' \
|
610
|
+
'by the application.',
|
611
|
+
type: 'radio',
|
612
|
+
default: 'false',
|
613
|
+
options: {
|
614
|
+
list_options: [
|
615
|
+
{
|
616
|
+
label: 'Yes',
|
617
|
+
value: 'true'
|
618
|
+
},
|
619
|
+
{
|
620
|
+
label: 'No',
|
621
|
+
value: 'false'
|
622
|
+
}
|
623
|
+
]
|
624
|
+
}
|
625
|
+
input :refresh_token_refresh_notes,
|
626
|
+
title: 'Notes, if applicable:',
|
627
|
+
type: 'textarea',
|
628
|
+
optional: true
|
629
|
+
|
630
|
+
run do
|
631
|
+
assert refresh_token_refresh_attestation == 'true',
|
632
|
+
'Health IT developer did not attest that the Health IT Module is capable of issuing refresh tokens ' \
|
633
|
+
'valid for a new period of no shorter than three months without requiring ' \
|
634
|
+
're-authentication and re-authorization when a valid refresh token is supplied ' \
|
635
|
+
'by the application.'
|
636
|
+
|
637
|
+
pass refresh_token_refresh_notes if refresh_token_refresh_notes.present?
|
638
|
+
end
|
639
|
+
end
|
575
640
|
end
|
576
641
|
end
|
@@ -102,13 +102,22 @@ module ONCCertificationG10TestKit
|
|
102
102
|
end
|
103
103
|
next if metadata.nil?
|
104
104
|
|
105
|
-
|
105
|
+
validation_messages = if resource.instance_of?(FHIR::Provenance)
|
106
|
+
USCoreTestKit::ProvenanceValidator.validate(resource)
|
107
|
+
else
|
108
|
+
[]
|
109
|
+
end
|
110
|
+
|
111
|
+
terminology_validation_messages = metadata.bindings
|
106
112
|
.select { |binding_definition| binding_definition[:strength] == 'required' }
|
107
113
|
.flat_map do |binding_definition|
|
108
114
|
TerminologyBindingValidator.validate(resource, binding_definition)
|
109
|
-
|
110
|
-
|
115
|
+
rescue Inferno::UnknownValueSetException, Inferno::UnknownCodeSystemException => e
|
116
|
+
{ type: 'warning', message: e.message }
|
111
117
|
end.compact
|
118
|
+
|
119
|
+
validation_messages.concat(terminology_validation_messages)
|
120
|
+
validation_messages
|
112
121
|
end
|
113
122
|
end
|
114
123
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: onc_certification_g10_test_kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen MacVicar
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bloomer
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.4.
|
47
|
+
version: 0.4.7
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.4.
|
54
|
+
version: 0.4.7
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: json-jwt
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,14 +114,14 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - '='
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 0.2.
|
117
|
+
version: 0.2.1
|
118
118
|
type: :runtime
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - '='
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 0.2.
|
124
|
+
version: 0.2.1
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: tls_test_kit
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,14 +142,14 @@ dependencies:
|
|
142
142
|
requirements:
|
143
143
|
- - '='
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: 0.4.
|
145
|
+
version: 0.4.4
|
146
146
|
type: :runtime
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - '='
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: 0.4.
|
152
|
+
version: 0.4.4
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: database_cleaner-sequel
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|