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
@@ -129,6 +129,30 @@ module ONCCertificationG10TestKit
129
129
  }
130
130
  end
131
131
 
132
+ group from: :smart_discovery_stu2_2 do # rubocop:disable Naming/VariableNumber
133
+ required_suite_options(G10Options::SMART_2_2_REQUIREMENT)
134
+
135
+ test from: 'g10_smart_well_known_capabilities',
136
+ config: {
137
+ options: {
138
+ required_capabilities: [
139
+ 'launch-ehr',
140
+ 'client-confidential-symmetric',
141
+ 'client-confidential-asymmetric',
142
+ 'sso-openid-connect',
143
+ 'context-banner',
144
+ 'context-style',
145
+ 'context-ehr-patient',
146
+ 'permission-offline',
147
+ 'permission-user',
148
+ 'authorize-post',
149
+ 'permission-v2',
150
+ 'permission-v1'
151
+ ]
152
+ }
153
+ }
154
+ end
155
+
132
156
  group from: :smart_ehr_launch do
133
157
  required_suite_options(G10Options::SMART_1_REQUIREMENT)
134
158
 
@@ -206,6 +230,16 @@ module ONCCertificationG10TestKit
206
230
  },
207
231
  required_suite_options: G10Options::US_CORE_6_REQUIREMENT
208
232
 
233
+ test from: :g10_encounter_context,
234
+ id: :g10_encounter_context_us_core_7, # rubocop:disable Naming/VariableNumber
235
+ config: {
236
+ inputs: {
237
+ encounter_id: { name: :ehr_encounter_id },
238
+ access_token: { name: :ehr_access_token }
239
+ }
240
+ },
241
+ required_suite_options: G10Options::US_CORE_7_REQUIREMENT
242
+
209
243
  test do
210
244
  title 'Launch context contains smart_style_url which links to valid JSON'
211
245
  description %(
@@ -362,6 +396,182 @@ module ONCCertificationG10TestKit
362
396
  },
363
397
  required_suite_options: G10Options::US_CORE_6_REQUIREMENT
364
398
 
399
+ test from: :g10_encounter_context,
400
+ id: :g10_encounter_context_us_core_7, # rubocop:disable Naming/VariableNumber
401
+ config: {
402
+ inputs: {
403
+ encounter_id: { name: :ehr_encounter_id },
404
+ access_token: { name: :ehr_access_token }
405
+ }
406
+ },
407
+ required_suite_options: G10Options::US_CORE_7_REQUIREMENT
408
+
409
+ test do
410
+ title 'Launch context contains smart_style_url which links to valid JSON'
411
+ description %(
412
+ In order to mimic the style of the SMART host more closely, SMART apps
413
+ can check for the existence of this launch context parameter and
414
+ download the JSON file referenced by the URL value.
415
+ )
416
+ uses_request :token
417
+ id :g10_smart_style_url
418
+
419
+ run do
420
+ skip_if request.status != 200, 'No token response received'
421
+ assert_valid_json response[:body]
422
+
423
+ body = JSON.parse(response[:body])
424
+
425
+ assert body['smart_style_url'].present?,
426
+ 'Token response did not contain `smart_style_url`'
427
+
428
+ get(body['smart_style_url'])
429
+
430
+ assert_response_status(200)
431
+ assert_valid_json(response[:body])
432
+ end
433
+ end
434
+
435
+ test do
436
+ title 'Launch context contains need_patient_banner'
437
+ description %(
438
+ `need_patient_banner` is a boolean value indicating whether the app
439
+ was launched in a UX context where a patient banner is required (when
440
+ true) or not required (when false).
441
+ )
442
+ uses_request :token
443
+ id :g10_smart_need_patient_banner
444
+
445
+ run do
446
+ skip_if request.status != 200, 'No token response received'
447
+ assert_valid_json response[:body]
448
+
449
+ body = JSON.parse(response[:body])
450
+
451
+ assert body.key?('need_patient_banner'),
452
+ 'Token response did not contain `need_patient_banner`'
453
+ end
454
+ end
455
+
456
+ tests[2].config(
457
+ outputs: {
458
+ incorrectly_permitted_tls_versions_messages: {
459
+ name: :auth_incorrectly_permitted_tls_versions_messages
460
+ }
461
+ }
462
+ )
463
+
464
+ tests[5].config(
465
+ outputs: {
466
+ incorrectly_permitted_tls_versions_messages: {
467
+ name: :token_incorrectly_permitted_tls_versions_messages
468
+ }
469
+ }
470
+ )
471
+ end
472
+
473
+ group from: :smart_ehr_launch_stu2_2, # rubocop:disable Naming/VariableNumber
474
+ config: {
475
+ inputs: {
476
+ use_pkce: {
477
+ default: 'true',
478
+ locked: true
479
+ },
480
+ pkce_code_challenge_method: {
481
+ locked: true
482
+ },
483
+ authorization_method: {
484
+ name: :ehr_authorization_method,
485
+ default: 'post',
486
+ locked: true
487
+ }
488
+ }
489
+ } do
490
+ required_suite_options(G10Options::SMART_2_2_REQUIREMENT)
491
+
492
+ title 'EHR Launch With Practitioner Scope'
493
+ input :client_secret,
494
+ name: :ehr_client_secret,
495
+ title: 'EHR Launch Client Secret',
496
+ description: 'Client Secret provided during registration of Inferno as an EHR launch application',
497
+ optional: false
498
+
499
+ config(
500
+ inputs: {
501
+ requested_scopes: {
502
+ default: %(
503
+ launch openid fhirUser offline_access user/Medication.rs
504
+ user/AllergyIntolerance.rs user/CarePlan.rs user/CareTeam.rs
505
+ user/Condition.rs user/Device.rs user/DiagnosticReport.rs
506
+ user/DocumentReference.rs user/Encounter.rs user/Goal.rs
507
+ user/Immunization.rs user/Location.rs user/MedicationRequest.rs
508
+ user/Observation.rs user/Organization.rs user/Patient.rs
509
+ user/Practitioner.rs user/Procedure.rs user/Provenance.rs
510
+ user/PractitionerRole.rs
511
+ ).gsub(/\s{2,}/, ' ').strip
512
+ }
513
+ }
514
+ )
515
+
516
+ test from: :g10_smart_scopes do
517
+ title 'User-level access with OpenID Connect and Refresh Token scopes used.'
518
+ config(
519
+ inputs: {
520
+ requested_scopes: { name: :ehr_requested_scopes },
521
+ received_scopes: { name: :ehr_received_scopes }
522
+ },
523
+ options: {
524
+ scope_version: :v22,
525
+ required_scope_type: 'user',
526
+ required_scopes: ['openid', 'fhirUser', 'launch', 'offline_access']
527
+ }
528
+ )
529
+ end
530
+
531
+ test from: :g10_unauthorized_access,
532
+ config: {
533
+ inputs: {
534
+ patient_id: { name: :ehr_patient_id }
535
+ }
536
+ }
537
+
538
+ test from: :g10_patient_context,
539
+ config: {
540
+ inputs: {
541
+ patient_id: { name: :ehr_patient_id },
542
+ access_token: { name: :ehr_access_token }
543
+ }
544
+ }
545
+
546
+ test from: :g10_encounter_context,
547
+ config: {
548
+ inputs: {
549
+ encounter_id: { name: :ehr_encounter_id },
550
+ access_token: { name: :ehr_access_token }
551
+ }
552
+ },
553
+ required_suite_options: G10Options::US_CORE_5_REQUIREMENT
554
+
555
+ test from: :g10_encounter_context,
556
+ id: :g10_encounter_context_us_core_6, # rubocop:disable Naming/VariableNumber
557
+ config: {
558
+ inputs: {
559
+ encounter_id: { name: :ehr_encounter_id },
560
+ access_token: { name: :ehr_access_token }
561
+ }
562
+ },
563
+ required_suite_options: G10Options::US_CORE_6_REQUIREMENT
564
+
565
+ test from: :g10_encounter_context,
566
+ id: :g10_encounter_context_us_core_7, # rubocop:disable Naming/VariableNumber
567
+ config: {
568
+ inputs: {
569
+ encounter_id: { name: :ehr_encounter_id },
570
+ access_token: { name: :ehr_access_token }
571
+ }
572
+ },
573
+ required_suite_options: G10Options::US_CORE_7_REQUIREMENT
574
+
365
575
  test do
366
576
  title 'Launch context contains smart_style_url which links to valid JSON'
367
577
  description %(
@@ -427,6 +637,30 @@ module ONCCertificationG10TestKit
427
637
  end
428
638
 
429
639
  group from: :smart_openid_connect,
640
+ required_suite_options: G10Options::SMART_1_REQUIREMENT,
641
+ config: {
642
+ inputs: {
643
+ id_token: { name: :ehr_id_token },
644
+ client_id: { name: :ehr_client_id },
645
+ requested_scopes: { name: :ehr_requested_scopes },
646
+ smart_credentials: { name: :ehr_smart_credentials }
647
+ }
648
+ }
649
+
650
+ group from: :smart_openid_connect,
651
+ required_suite_options: G10Options::SMART_2_REQUIREMENT,
652
+ id: :smart_openid_connect_stu2,
653
+ config: {
654
+ inputs: {
655
+ id_token: { name: :ehr_id_token },
656
+ client_id: { name: :ehr_client_id },
657
+ requested_scopes: { name: :ehr_requested_scopes },
658
+ smart_credentials: { name: :ehr_smart_credentials }
659
+ }
660
+ }
661
+
662
+ group from: :smart_openid_connect_stu2_2, # rubocop:disable Naming/VariableNumber
663
+ required_suite_options: G10Options::SMART_2_2_REQUIREMENT,
430
664
  config: {
431
665
  inputs: {
432
666
  id_token: { name: :ehr_id_token },
@@ -0,0 +1,188 @@
1
+ module ONCCertificationG10TestKit
2
+ class SmartFineGrainedScopesGroupSTU22 < USCoreTestKit::USCoreV610::SmartGranularScopesGroup
3
+ title 'SMART App Launch with fine-grained scopes'
4
+ short_title 'SMART Launch with Fine-Grained Scopes'
5
+
6
+ input_instructions %(
7
+ If necessary, register Inferno as a standalone application using the following information:
8
+
9
+ * Redirect URI: `#{SMARTAppLaunch::AppRedirectTest.config.options[:redirect_uri]}`
10
+
11
+ Inferno may be registered multiple times with different `client_ids`, or this
12
+ may reuse a single registration of Inferno.`
13
+
14
+ This test will perform two launches, with each launch requiring a separate
15
+ separate set of finer-grained scopes to be granted:
16
+
17
+ Group 1:
18
+ * `Condition.rs?category=http://terminology.hl7.org/CodeSystem/condition-category|encounter-diagnosis`
19
+ * `Condition.rs?category=http://hl7.org/fhir/us/core/CodeSystem/condition-category|health-concern`
20
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|laboratory`
21
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|social-history`
22
+
23
+ Group 2:
24
+ * `Condition.rs?category=http://terminology.hl7.org/CodeSystem/condition-category|problem-list-item`
25
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|vital-signs`
26
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|survey`
27
+ * `Observation.rs?category=http://hl7.org/fhir/us/core/CodeSystem/us-core-category|sdoh`
28
+ )
29
+
30
+ description <<~DESCRIPTION
31
+
32
+ As finalized in the [HTI-1 Final Rule](https://www.federalregister.gov/d/2023-28857/p-1250), Health IT Modules are
33
+ required to support SMART App Launch v2.0.0 "Finer-grained resource
34
+ constraints using search parameters" for the "category" parameter for the
35
+ Condition resource with Condition sub-resources Encounter Diagnosis, Problem
36
+ List, and Health Concern, and the Observation resource with Observation
37
+ sub-resources Clinical Test, Laboratory, Social History, SDOH, Survey, and
38
+ Vital Signs.
39
+
40
+ This is also reflected in the (g)(10) Standardized API for patient and
41
+ populations [Test
42
+ Procedure](https://www.healthit.gov/test-method/standardized-api-patient-and-population-services#test_procedure):
43
+
44
+ > [AUT-PAT-28] SMART v2 scope syntax for patient-level and user-level scopes to support
45
+ the “permission-v2” “SMART on FHIR® Capability”, including support for
46
+ finer-grained resource constraints using search parameters according to
47
+ section 3.0.2.3 of the implementation specification at § 170.215(c)(2) for
48
+ the “category” parameter for the following resources: (1) Condition
49
+ resource with Condition sub-resources Encounter Diagnosis, Problem List,
50
+ and Health Concern; and (2) Observation resource with Observation
51
+ sub-resources Clinical Test, Laboratory, Social History, SDOH, Survey, and
52
+ Vital Signs
53
+
54
+ Prior to running this scenario, first run the Single Patient API tests using
55
+ resource-level scopes, as this scenario uses content saved from that scenario
56
+ as a baseline for comparison when finer-grained scopes are granted.
57
+
58
+ This scenario contains two groups of finer-grained scope tests, each of
59
+ which includes a SMART Standalone Launch that requests a subset of
60
+ finer-grained scopes, followed by FHIR API requests to verify that scopes
61
+ are appropriately granted. The app launches require that the subset of the
62
+ requested finer-grained scopes are granted by the user. The FHIR API tests then repeat all
63
+ of the queries from the original Single Patient API tests that were run
64
+ using resource-level scopes, and verify that only resources matching the
65
+ current finer-grained scopes are returned. Each group requires a separate
66
+ set of finer-grained scopes to be granted:
67
+
68
+ Group 1:
69
+ * `Condition.rs?category=http://terminology.hl7.org/CodeSystem/condition-category|encounter-diagnosis`
70
+ * `Condition.rs?category=http://hl7.org/fhir/us/core/CodeSystem/condition-category|health-concern`
71
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|laboratory`
72
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|social-history`
73
+
74
+ Group 2:
75
+ * `Condition.rs?category=http://terminology.hl7.org/CodeSystem/condition-category|problem-list-item`
76
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|vital-signs`
77
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|survey`
78
+ * `Observation.rs?category=http://hl7.org/fhir/us/core/CodeSystem/us-core-category|sdoh`
79
+
80
+ Note that Inferno will only request the finer grained scopes in each case,
81
+ but the system under test can display more scopes to the tester during
82
+ authorization. In this case, it is expected that the tester will only
83
+ approve the appropriate scopes in each group as described above.
84
+
85
+ For more information, please refer to [finer-grained resource constraints
86
+ using search
87
+ parameters](https://hl7.org/fhir/smart-app-launch/STU2.2/scopes-and-launch-context.html#finer-grained-resource-constraints-using-search-parameters).
88
+
89
+ DESCRIPTION
90
+
91
+ id :g10_smart_fine_grained_scopes_stu2_2 # rubocop:disable Naming/VariableNumber
92
+
93
+ input :url
94
+
95
+ children.each(&:run_as_group)
96
+
97
+ # Replace generic finer-grained scope auth group with which allows standalone or
98
+ # ehr launch with just the standalone launch group
99
+ granular_scopes_group1 = children.first
100
+ granular_scopes_group1.children[0] = granular_scopes_group1.children.first.children[1]
101
+ standalone_launch_group1 = granular_scopes_group1.children[0]
102
+ standalone_launch_group1.required
103
+
104
+ granular_scopes_group2 = children.last
105
+ granular_scopes_group2.children[0] = granular_scopes_group2.children.first.children[1]
106
+ standalone_launch_group2 = granular_scopes_group2.children[0]
107
+ standalone_launch_group2.required
108
+
109
+ # Move the granular scope API groups to the top level
110
+ api_group1 = granular_scopes_group1.children.pop
111
+ api_group1.children.each do |group|
112
+ group.children.select!(&:required?)
113
+ granular_scopes_group1.children << group
114
+ end
115
+
116
+ api_group2 = granular_scopes_group2.children.pop
117
+ api_group2.children.each do |group|
118
+ group.children.select!(&:required?)
119
+ granular_scopes_group2.children << group
120
+ end
121
+
122
+ # Remove OIDC and refresh token tests
123
+ standalone_launch_group1.children.pop(2)
124
+ standalone_launch_group2.children.pop(2)
125
+
126
+ config(
127
+ inputs: {
128
+ authorization_method: {
129
+ name: :granular_scopes_authorization_method,
130
+ title: 'Granular Scopes Authorization Request Method'
131
+ },
132
+ client_auth_type: {
133
+ name: :granular_scopes_client_auth_type,
134
+ title: 'Granular Scopes Client Authentication Type'
135
+ },
136
+ received_scopes: {
137
+ name: :standalone_received_scopes
138
+ }
139
+ }
140
+ )
141
+
142
+ granular_scopes_group1.config(
143
+ inputs: {
144
+ client_id: {
145
+ name: :granular_scopes1_client_id,
146
+ title: 'Granular Scopes Group 1 Client ID'
147
+ },
148
+ client_secret: {
149
+ name: :granular_scopes1_client_secret,
150
+ title: 'Granular Scopes Group 1 Client Secret'
151
+ },
152
+ requested_scopes: {
153
+ title: 'Granular Scopes Group 1 Scopes'
154
+ }
155
+ }
156
+ )
157
+
158
+ granular_scopes_group2.config(
159
+ inputs: {
160
+ client_id: {
161
+ name: :granular_scopes2_client_id,
162
+ title: 'Granular Scopes Group 2 Client ID'
163
+ },
164
+ client_secret: {
165
+ name: :granular_scopes2_client_secret,
166
+ title: 'Granular Scopes Group 2 Client Secret'
167
+ },
168
+ requested_scopes: {
169
+ title: 'Granular Scopes Group 2 Scopes'
170
+ }
171
+ }
172
+ )
173
+
174
+ input_order :url,
175
+ :granular_scopes1_client_id,
176
+ :requested_scopes_group1,
177
+ :granular_scopes_authorization_method,
178
+ :granular_scopes_client_auth_type,
179
+ :granular_scopes1_client_secret,
180
+ :client_auth_encryption_method,
181
+ :granular_scopes2_client_id,
182
+ :requested_scopes_group2,
183
+ :granular_scopes2_client_secret,
184
+ :use_pkce,
185
+ :pkce_code_challenge_method,
186
+ :patient_ids
187
+ end
188
+ end
@@ -0,0 +1,188 @@
1
+ module ONCCertificationG10TestKit
2
+ class SmartFineGrainedScopesUSCore7Group < USCoreTestKit::USCoreV700::SmartGranularScopesGroup
3
+ title 'SMART App Launch with fine-grained scopes'
4
+ short_title 'SMART Launch with Fine-Grained Scopes'
5
+
6
+ input_instructions %(
7
+ If necessary, register Inferno as a standalone application using the following information:
8
+
9
+ * Redirect URI: `#{SMARTAppLaunch::AppRedirectTest.config.options[:redirect_uri]}`
10
+
11
+ Inferno may be registered multiple times with different `client_ids`, or this
12
+ may reuse a single registration of Inferno.`
13
+
14
+ This test will perform two launches, with each launch requiring a separate
15
+ separate set of finer-grained scopes to be granted:
16
+
17
+ Group 1:
18
+ * `Condition.rs?category=http://terminology.hl7.org/CodeSystem/condition-category|encounter-diagnosis`
19
+ * `Condition.rs?category=http://hl7.org/fhir/us/core/CodeSystem/condition-category|health-concern`
20
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|laboratory`
21
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|social-history`
22
+
23
+ Group 2:
24
+ * `Condition.rs?category=http://terminology.hl7.org/CodeSystem/condition-category|problem-list-item`
25
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|vital-signs`
26
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|survey`
27
+ * `Observation.rs?category=http://hl7.org/fhir/us/core/CodeSystem/us-core-category|sdoh`
28
+ )
29
+
30
+ description <<~DESCRIPTION
31
+
32
+ As finalized in the [HTI-1 Final Rule](https://www.federalregister.gov/d/2023-28857/p-1250), Health IT Modules are
33
+ required to support SMART App Launch v2.0.0 "Finer-grained resource
34
+ constraints using search parameters" for the "category" parameter for the
35
+ Condition resource with Condition sub-resources Encounter Diagnosis, Problem
36
+ List, and Health Concern, and the Observation resource with Observation
37
+ sub-resources Clinical Test, Laboratory, Social History, SDOH, Survey, and
38
+ Vital Signs.
39
+
40
+ This is also reflected in the (g)(10) Standardized API for patient and
41
+ populations [Test
42
+ Procedure](https://www.healthit.gov/test-method/standardized-api-patient-and-population-services#test_procedure):
43
+
44
+ > [AUT-PAT-28] SMART v2 scope syntax for patient-level and user-level scopes to support
45
+ the “permission-v2” “SMART on FHIR® Capability”, including support for
46
+ finer-grained resource constraints using search parameters according to
47
+ section 3.0.2.3 of the implementation specification at § 170.215(c)(2) for
48
+ the “category” parameter for the following resources: (1) Condition
49
+ resource with Condition sub-resources Encounter Diagnosis, Problem List,
50
+ and Health Concern; and (2) Observation resource with Observation
51
+ sub-resources Clinical Test, Laboratory, Social History, SDOH, Survey, and
52
+ Vital Signs
53
+
54
+ Prior to running this scenario, first run the Single Patient API tests using
55
+ resource-level scopes, as this scenario uses content saved from that scenario
56
+ as a baseline for comparison when finer-grained scopes are granted.
57
+
58
+ This scenario contains two groups of finer-grained scope tests, each of
59
+ which includes a SMART Standalone Launch that requests a subset of
60
+ finer-grained scopes, followed by FHIR API requests to verify that scopes
61
+ are appropriately granted. The app launches require that the subset of the
62
+ requested finer-grained scopes are granted by the user. The FHIR API tests then repeat all
63
+ of the queries from the original Single Patient API tests that were run
64
+ using resource-level scopes, and verify that only resources matching the
65
+ current finer-grained scopes are returned. Each group requires a separate
66
+ set of finer-grained scopes to be granted:
67
+
68
+ Group 1:
69
+ * `Condition.rs?category=http://terminology.hl7.org/CodeSystem/condition-category|encounter-diagnosis`
70
+ * `Condition.rs?category=http://hl7.org/fhir/us/core/CodeSystem/condition-category|health-concern`
71
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|laboratory`
72
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|social-history`
73
+
74
+ Group 2:
75
+ * `Condition.rs?category=http://terminology.hl7.org/CodeSystem/condition-category|problem-list-item`
76
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|vital-signs`
77
+ * `Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|survey`
78
+ * `Observation.rs?category=http://hl7.org/fhir/us/core/CodeSystem/us-core-category|sdoh`
79
+
80
+ Note that Inferno will only request the finer grained scopes in each case,
81
+ but the system under test can display more scopes to the tester during
82
+ authorization. In this case, it is expected that the tester will only
83
+ approve the appropriate scopes in each group as described above.
84
+
85
+ For more information, please refer to [finer-grained resource constraints
86
+ using search
87
+ parameters](https://hl7.org/fhir/smart-app-launch/STU2/scopes-and-launch-context.html#finer-grained-resource-constraints-using-search-parameters).
88
+
89
+ DESCRIPTION
90
+
91
+ id :g10_us_core_7_smart_fine_grained_scopes
92
+
93
+ input :url
94
+
95
+ children.each(&:run_as_group)
96
+
97
+ # Replace generic finer-grained scope auth group with which allows standalone or
98
+ # ehr launch with just the standalone launch group
99
+ granular_scopes_group1 = children.first
100
+ granular_scopes_group1.children[0] = granular_scopes_group1.children.first.children.first
101
+ standalone_launch_group1 = granular_scopes_group1.children[0]
102
+ standalone_launch_group1.required
103
+
104
+ granular_scopes_group2 = children.last
105
+ granular_scopes_group2.children[0] = granular_scopes_group2.children.first.children.first
106
+ standalone_launch_group2 = granular_scopes_group2.children[0]
107
+ standalone_launch_group2.required
108
+
109
+ # Move the granular scope API groups to the top level
110
+ api_group1 = granular_scopes_group1.children.pop
111
+ api_group1.children.each do |group|
112
+ group.children.select!(&:required?)
113
+ granular_scopes_group1.children << group
114
+ end
115
+
116
+ api_group2 = granular_scopes_group2.children.pop
117
+ api_group2.children.each do |group|
118
+ group.children.select!(&:required?)
119
+ granular_scopes_group2.children << group
120
+ end
121
+
122
+ # Remove OIDC and refresh token tests
123
+ standalone_launch_group1.children.pop(2)
124
+ standalone_launch_group2.children.pop(2)
125
+
126
+ config(
127
+ inputs: {
128
+ authorization_method: {
129
+ name: :granular_scopes_authorization_method,
130
+ title: 'Granular Scopes Authorization Request Method'
131
+ },
132
+ client_auth_type: {
133
+ name: :granular_scopes_client_auth_type,
134
+ title: 'Granular Scopes Client Authentication Type'
135
+ },
136
+ received_scopes: {
137
+ name: :standalone_received_scopes
138
+ }
139
+ }
140
+ )
141
+
142
+ granular_scopes_group1.config(
143
+ inputs: {
144
+ client_id: {
145
+ name: :granular_scopes1_client_id,
146
+ title: 'Granular Scopes Group 1 Client ID'
147
+ },
148
+ client_secret: {
149
+ name: :granular_scopes1_client_secret,
150
+ title: 'Granular Scopes Group 1 Client Secret'
151
+ },
152
+ requested_scopes: {
153
+ title: 'Granular Scopes Group 1 Scopes'
154
+ }
155
+ }
156
+ )
157
+
158
+ granular_scopes_group2.config(
159
+ inputs: {
160
+ client_id: {
161
+ name: :granular_scopes2_client_id,
162
+ title: 'Granular Scopes Group 2 Client ID'
163
+ },
164
+ client_secret: {
165
+ name: :granular_scopes2_client_secret,
166
+ title: 'Granular Scopes Group 2 Client Secret'
167
+ },
168
+ requested_scopes: {
169
+ title: 'Granular Scopes Group 2 Scopes'
170
+ }
171
+ }
172
+ )
173
+
174
+ input_order :url,
175
+ :granular_scopes1_client_id,
176
+ :requested_scopes_group1,
177
+ :granular_scopes_authorization_method,
178
+ :granular_scopes_client_auth_type,
179
+ :granular_scopes1_client_secret,
180
+ :client_auth_encryption_method,
181
+ :granular_scopes2_client_id,
182
+ :requested_scopes_group2,
183
+ :granular_scopes2_client_secret,
184
+ :use_pkce,
185
+ :pkce_code_challenge_method,
186
+ :patient_ids
187
+ end
188
+ end