onc_certification_g10_test_kit 6.0.3 → 7.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/inferno/repositiories/validators.rb +0 -6
  3. data/lib/inferno/repositiories/value_sets.rb +1 -7
  4. data/lib/inferno/terminology/expected_manifest.yml +5 -5
  5. data/lib/inferno/terminology/fhir_package_manager.rb +13 -4
  6. data/lib/inferno/terminology/loader.rb +2 -1
  7. data/lib/inferno/terminology/tasks/download_fhir_terminology.rb +2 -1
  8. data/lib/inferno/terminology/tasks/download_umls.rb +2 -1
  9. data/lib/inferno/terminology/tasks/expand_value_set_to_file.rb +1 -1
  10. data/lib/inferno/terminology/tasks/run_umls_jar.rb +2 -1
  11. data/lib/inferno/terminology/validator.rb +1 -0
  12. data/lib/inferno/terminology/value_set.rb +2 -0
  13. data/lib/onc_certification_g10_test_kit/all_resources.rb +74 -0
  14. data/lib/onc_certification_g10_test_kit/bulk_data_group_export_validation.rb +361 -59
  15. data/lib/onc_certification_g10_test_kit/bulk_export_validation_tester.rb +4 -3
  16. data/lib/onc_certification_g10_test_kit/g10_options.rb +20 -1
  17. data/lib/onc_certification_g10_test_kit/limited_scope_grant_test.rb +4 -0
  18. data/lib/onc_certification_g10_test_kit/multi_patient_api_stu1.rb +2 -1
  19. data/lib/onc_certification_g10_test_kit/multi_patient_api_stu2.rb +2 -1
  20. data/lib/onc_certification_g10_test_kit/patient_scope_test.rb +1 -1
  21. data/lib/onc_certification_g10_test_kit/profile_selector.rb +40 -15
  22. data/lib/onc_certification_g10_test_kit/restricted_resource_type_access_group.rb +89 -2
  23. data/lib/onc_certification_g10_test_kit/short_id_map.yml +1417 -12
  24. data/lib/onc_certification_g10_test_kit/single_patient_us_core_7_api_group.rb +219 -0
  25. data/lib/onc_certification_g10_test_kit/smart_app_launch_invalid_aud_group.rb +41 -1
  26. data/lib/onc_certification_g10_test_kit/smart_asymmetric_launch_group.rb +33 -1
  27. data/lib/onc_certification_g10_test_kit/smart_ehr_patient_launch_group_stu2_2.rb +128 -0
  28. data/lib/onc_certification_g10_test_kit/smart_ehr_practitioner_app_group.rb +234 -0
  29. data/lib/onc_certification_g10_test_kit/smart_fine_grained_scopes_group_stu2_2.rb +188 -0
  30. data/lib/onc_certification_g10_test_kit/smart_fine_grained_scopes_us_core_7_group.rb +188 -0
  31. data/lib/onc_certification_g10_test_kit/smart_fine_grained_scopes_us_core_7_group_stu2_2.rb +188 -0
  32. data/lib/onc_certification_g10_test_kit/smart_granular_scope_selection_group.rb +67 -1
  33. data/lib/onc_certification_g10_test_kit/smart_limited_app_group.rb +128 -1
  34. data/lib/onc_certification_g10_test_kit/smart_public_standalone_launch_group_stu2_2.rb +162 -0
  35. data/lib/onc_certification_g10_test_kit/smart_scopes_test.rb +10 -2
  36. data/lib/onc_certification_g10_test_kit/smart_standalone_patient_app_group.rb +159 -0
  37. data/lib/onc_certification_g10_test_kit/smart_v1_scopes_group.rb +117 -0
  38. data/lib/onc_certification_g10_test_kit/terminology_binding_validator.rb +5 -1
  39. data/lib/onc_certification_g10_test_kit/token_introspection_group_stu2_2.rb +97 -0
  40. data/lib/onc_certification_g10_test_kit/unrestricted_resource_type_access_group.rb +85 -31
  41. data/lib/onc_certification_g10_test_kit/version.rb +1 -1
  42. data/lib/onc_certification_g10_test_kit/visual_inspection_and_attestations_group.rb +171 -0
  43. data/lib/onc_certification_g10_test_kit/well_known_capabilities_test.rb +1 -1
  44. data/lib/onc_certification_g10_test_kit.rb +72 -5
  45. metadata +18 -10
@@ -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