onc_certification_g10_test_kit 3.3.2 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9bb1416b5f4a895760df48a2c49468074e882651237b8b76ebc81434b16df44d
4
- data.tar.gz: '09d90f9db1f4c5be41a8e7705c5b2809f81da0bb377bcc4c4bde14e5d168943e'
3
+ metadata.gz: 98375c6a97ac9a9056303f326b8dbe742b636ce9aec9751d8ece7e9d2cc3850f
4
+ data.tar.gz: 63905d2ab2aed1d6ce3beddeb09ea3670885dbf78d5f86628d0dd9efd4efdbd0
5
5
  SHA512:
6
- metadata.gz: 3bc7515b56f5680e57f7ef716b34ecf77b04abfdba314bc12d9c8a51a85b31da9a4da8895a32093431d52a18af36f7ca0cb9bb6fa2b2ff2f597f45e42442b151
7
- data.tar.gz: d37b1c5641703be96934aeaa96444be227c7eab3653c888dcc37dfd70a41f9b44383a19efb3898337f73a93552ad48c1166b9ddffcef9eb10b8a0f87a493823f
6
+ metadata.gz: 023317c28042a98b0b9ed4bce639906668463655082abaefe9e033bf133b76f8dec8bb0b9af7005f0aa65ba0bca5bd00a817e3c88b542eaf72bc17cce0818829
7
+ data.tar.gz: d216f8e2193a35a3a433b4ecda391a73c964f2df029d167b225c64c7f91f72d3bbd0ce7cd67833742ac991325634fa0080668a6cea98d5b295cf127832183db9
@@ -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 { |line|
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
- profile_url = determine_profile(resource)
143
- resources[profile_url] << resource
144
- scratch[:patient_ids_seen] = patient_ids_seen | [resource.id] if resource_type == 'Patient'
145
-
146
- profile_with_version = versioned_profile_url(profile_url)
147
- unless resource_is_valid?(resource:, profile_url: profile_with_version)
148
- if first_error.key?(:line_number)
149
- @invalid_resource_count += 1
150
- else
151
- @invalid_resource_count = 1
152
- first_error[:line_number] = line_count
153
- first_error[:messages] = messages.dup
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.05
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
43
  resource_contains_category(resource, 'health-concern', 'http://hl7.org/fhir/us/core/CodeSystem/condition-category')
42
- extract_profile('ConditionProblemsHealthConcerns')
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
- return extract_profile('DiagnosticReportLab') if resource_contains_category(resource, 'LAB', 'http://terminology.hl7.org/CodeSystem/v2-0074')
49
-
50
- extract_profile('DiagnosticReportNote')
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
- return extract_profile('Smokingstatus') if observation_contains_code(resource, '72166-2')
56
+ profiles << extract_profile('Smokingstatus') if observation_contains_code(resource, '72166-2')
53
57
 
54
- return extract_profile('ObservationLab') if resource_contains_category(resource, 'laboratory', 'http://terminology.hl7.org/CodeSystem/observation-category')
58
+ profiles << extract_profile('ObservationLab') if resource_contains_category(resource, 'laboratory', 'http://terminology.hl7.org/CodeSystem/observation-category')
55
59
 
56
- return extract_profile('PediatricBmiForAge') if observation_contains_code(resource, '59576-9')
60
+ profiles << extract_profile('PediatricBmiForAge') if observation_contains_code(resource, '59576-9')
57
61
 
58
- return extract_profile('PediatricWeightForHeight') if observation_contains_code(resource, '77606-2')
62
+ profiles << extract_profile('PediatricWeightForHeight') if observation_contains_code(resource, '77606-2')
59
63
 
60
- return extract_profile('PulseOximetry') if observation_contains_code(resource, '59408-5')
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
- when US_CORE_3
65
- return extract_profile('HeadCircumference')
66
- else
67
- return extract_profile('HeadCircumferencePercentile')
68
- end
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
- return extract_profile('HeadCircumference')
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
- return extract_profile('Bmi') if observation_contains_code(resource, '39156-5') && !using_us_core_3?
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
- when US_CORE_3
85
- return extract_profile('Bp')
86
- else
87
- return extract_profile('BloodPressure')
88
- end
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
- when US_CORE_3
94
- return extract_profile('Bodyheight')
95
- else
96
- return extract_profile('BodyHeight')
97
- end
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
- when US_CORE_3
103
- return extract_profile('Bodytemp')
104
- else
105
- return extract_profile('BodyTemperature')
106
- end
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
- when US_CORE_3
112
- return extract_profile('Bodyweight')
113
- else
114
- return extract_profile('BodyWeight')
115
- end
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
- when US_CORE_3
121
- return extract_profile('Heartrate')
122
- else
123
- return extract_profile('HeartRate')
124
- end
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
- when US_CORE_3
130
- return extract_profile('Resprate')
131
- else
132
- return extract_profile('RespiratoryRate')
133
- end
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
- return extract_profile('ObservationClinicalTest')
144
+ profiles << extract_profile('ObservationClinicalTest')
141
145
  end
142
146
 
143
147
  if using_us_core_5? && observation_contains_code(resource, '76690-7')
144
- return extract_profile('ObservationSexualOrientation')
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
- return extract_profile('ObservationSocialHistory')
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
- return extract_profile('ObservationImaging')
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
- return extract_profile('ObservationSdohAssessment')
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 = "Bad response code: expected 403 (Forbidden) or 401 (Unauthorized), but found #{request.status}."
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
@@ -1,3 +1,3 @@
1
1
  module ONCCertificationG10TestKit
2
- VERSION = '3.3.2'.freeze
2
+ VERSION = '3.4.0'.freeze
3
3
  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 module does not cache the JWK Set received ' \
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 module does not cache the
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 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
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
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.3.2
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: 2022-12-14 00:00:00.000000000 Z
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.2
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.2
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.0
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.0
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.3
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.3
152
+ version: 0.4.4
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: database_cleaner-sequel
155
155
  requirement: !ruby/object:Gem::Requirement