davinci_crd_test_kit 0.12.2 → 0.14.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/config/presets/inferno_crd_client_suite.json.erb +20 -14
- data/config/presets/inferno_crd_client_suite_prefetch_subset_v221.json.erb +125 -0
- data/config/presets/inferno_crd_client_suite_v221.json.erb +124 -0
- data/config/presets/inferno_crd_server_suite.json.erb +59 -2
- data/config/presets/inferno_crd_server_suite_v221.json.erb +94 -0
- data/config/presets/ri_crd_request_generator.json_v221.json.erb +13 -0
- data/config/presets/ri_crd_server.json.erb +19 -19
- data/lib/davinci_crd_test_kit/client/client_base_urls.rb +80 -0
- data/lib/davinci_crd_test_kit/{client_hook_request_validation.rb → client/client_hook_request_validation.rb} +1 -1
- data/lib/davinci_crd_test_kit/client/crd_client_options.rb +30 -0
- data/lib/davinci_crd_test_kit/client/endpoints/cds_services_discovery_handler.rb +34 -0
- data/lib/davinci_crd_test_kit/client/endpoints/custom_service_response.rb +342 -0
- data/lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb +410 -0
- data/lib/davinci_crd_test_kit/client/endpoints/hook_request_endpoint.rb +233 -0
- data/lib/davinci_crd_test_kit/{mock_service_response.rb → client/endpoints/mock_service_response.rb} +165 -59
- data/lib/davinci_crd_test_kit/{card_responses → client/endpoints/mocked_card_responses}/companions_prerequisites.json +1 -0
- data/lib/davinci_crd_test_kit/{card_responses → client/endpoints/mocked_card_responses}/create_update_coverage_information.json +3 -2
- data/lib/davinci_crd_test_kit/{card_responses → client/endpoints/mocked_card_responses}/launch_smart_app.json +8 -1
- data/lib/davinci_crd_test_kit/{card_responses → client/endpoints/mocked_card_responses}/propose_alternate_request.json +1 -0
- data/lib/davinci_crd_test_kit/{card_responses → client/endpoints/mocked_card_responses}/request_form_completion.json +17 -16
- data/lib/davinci_crd_test_kit/client/multi_request_message_helper.rb +35 -0
- data/lib/davinci_crd_test_kit/client/tagged_request_load_helper.rb +38 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/api/client_fhir_api_create_test.rb +43 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/api/client_fhir_api_read_test.rb +43 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/api/client_fhir_api_search_test.rb +234 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/api/client_fhir_api_update_test.rb +43 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/api/client_fhir_api_validation_test.rb +63 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/auth/decode_auth_token_test.rb +65 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/auth/retrieve_jwks_test.rb +109 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/auth/token_header_test.rb +70 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/auth/token_payload_test.rb +85 -0
- data/lib/davinci_crd_test_kit/{routes/cds-services.json → client/v2.0.1/cds-services-v201.json} +1 -1
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_appointment_book_group.rb +108 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_card_must_support_group.rb +31 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_encounter_discharge_group.rb +105 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_encounter_start_group.rb +105 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_fhir_api_group.rb +790 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_hooks_group.rb +74 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_order_dispatch_group.rb +111 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_order_select_group.rb +116 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_order_sign_group.rb +113 -0
- data/lib/davinci_crd_test_kit/{client_registration_group.rb → client/v2.0.1/client_registration_group.rb} +12 -8
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_urls.rb +13 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/crd_client_suite.rb +134 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/invocation/appointment_book_receive_request_test.rb +129 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/invocation/encounter_discharge_receive_request_test.rb +126 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/invocation/encounter_start_receive_request_test.rb +126 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/invocation/order_dispatch_receive_request_test.rb +138 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/invocation/order_select_receive_request_test.rb +134 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/invocation/order_sign_receive_request_test.rb +136 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/must_support/client_card_must_support_coverage_information.rb +93 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/must_support/client_card_must_support_external_reference.rb +62 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/must_support/client_card_must_support_instructions.rb +62 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/registration/client_registration_verification_test.rb +94 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/registration/client_service_registration_attestation_test.rb +40 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_fetched_data_test.rb +86 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_optional_fields_test.rb +63 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_prefetch_equals_queried_test.rb +96 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_required_fields_test.rb +55 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_valid_context_test.rb +70 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_valid_prefetch_test.rb +62 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_response/client_display_cards_attest.rb +83 -0
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_response/inferno_response_validation.rb +79 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/api/client_coverage_info_update_test.rb +212 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/api/client_crd_update_verification_group.rb +18 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/auth/decode_auth_token_test.rb +69 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/auth/retrieve_jwks_test.rb +120 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/auth/token_header_test.rb +92 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/auth/token_payload_test.rb +93 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/cds-services-prefetch-subset-v221.json +198 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/cds-services-v221.json +202 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_appointment_book_group.rb +102 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_cross_hook_group.rb +28 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_encounter_discharge_group.rb +96 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_encounter_start_group.rb +95 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_fhir_api_group.rb +88 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_hooks_group.rb +64 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_long_running_hook_group.rb +32 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_order_dispatch_group.rb +101 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_order_select_group.rb +102 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_order_sign_group.rb +107 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_registration_group.rb +27 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_urls.rb +27 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/crd_client_suite.rb +229 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_card_must_support_coverage_information_test.rb +63 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_fhirpath_collection_as_comma_delimited_string_test.rb +60 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_hook_instances_unique_test.rb +45 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_location_address_propagation_test.rb +135 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_prefetch_complete_and_subset_test.rb +103 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/appointment_book_receive_request_test.rb +156 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/encounter_discharge_receive_request_test.rb +157 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/encounter_start_receive_request_test.rb +157 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/order_dispatch_receive_request_test.rb +165 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/order_select_receive_request_test.rb +165 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/order_sign_receive_request_test.rb +165 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/long_running/client_long_running_receive_request_test.rb +64 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/long_running/client_skip_long_running_attestation_test.rb +49 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/registration/client_registration_verification_test.rb +161 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/registration/client_service_registration_attestation_test.rb +107 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_conformance_test.rb +47 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_coverage_verification_test.rb +152 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_data_fetch_verification_test.rb +55 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_granted_scopes_test.rb +123 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_prefetch_complete_test.rb +127 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_prefetch_profiles_test.rb +55 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_requested_version_test.rb +54 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_secured_transport_test.rb +48 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_response/client_display_cards_attest.rb +74 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_response/hook_response_support_coverage_information_test.rb +30 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_response/inferno_response_validation.rb +77 -0
- data/lib/davinci_crd_test_kit/cross_suite/base_urls.rb +20 -0
- data/lib/davinci_crd_test_kit/cross_suite/cards_identification.rb +312 -0
- data/lib/davinci_crd_test_kit/{cards_validation.rb → cross_suite/cards_validation.rb} +104 -47
- data/lib/davinci_crd_test_kit/cross_suite/coverage-information_stu201_metadata.yml +27 -0
- data/lib/davinci_crd_test_kit/cross_suite/coverage-information_stu221_metadata.yml +60 -0
- data/lib/davinci_crd_test_kit/cross_suite/fhirpath_on_cds_request.rb +177 -0
- data/lib/davinci_crd_test_kit/{hook_request_field_validation.rb → cross_suite/hook_request_field_validation.rb} +282 -203
- data/lib/davinci_crd_test_kit/cross_suite/logical_models_override_helper.rb +220 -0
- data/lib/davinci_crd_test_kit/cross_suite/prefetch_completeness_checker.rb +462 -0
- data/lib/davinci_crd_test_kit/cross_suite/prefetch_contents_validation.rb +81 -0
- data/lib/davinci_crd_test_kit/cross_suite/prefetch_profile_validation.rb +48 -0
- data/lib/davinci_crd_test_kit/cross_suite/profiles_and_resource_types.rb +63 -0
- data/lib/davinci_crd_test_kit/cross_suite/replace_tokens.rb +38 -0
- data/lib/davinci_crd_test_kit/cross_suite/requests_logical_model_validation.rb +202 -0
- data/lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb +274 -0
- data/lib/davinci_crd_test_kit/{suggestion_actions_validation.rb → cross_suite/suggestion_actions_validation.rb} +70 -50
- data/lib/davinci_crd_test_kit/cross_suite/tags.rb +42 -0
- data/lib/davinci_crd_test_kit/metadata.rb +10 -44
- data/lib/davinci_crd_test_kit/requirements/cds-hooks-library_1.0.1_requirements.xlsx +0 -0
- data/lib/davinci_crd_test_kit/requirements/cds-hooks_2.0_requirements.xlsx +0 -0
- data/lib/davinci_crd_test_kit/requirements/cds-hooks_3.0.0-ballot_requirements.xlsx +0 -0
- data/lib/davinci_crd_test_kit/requirements/davinci_crd_test_kit_requirements.csv +742 -65
- data/lib/davinci_crd_test_kit/requirements/generated/crd_client_requirements_coverage.csv +279 -54
- data/lib/davinci_crd_test_kit/requirements/generated/crd_client_v221_requirements_coverage.csv +1430 -0
- data/lib/davinci_crd_test_kit/requirements/generated/crd_server_requirements_coverage.csv +36 -45
- data/lib/davinci_crd_test_kit/requirements/generated/crd_server_v221_requirements_coverage.csv +143 -0
- data/lib/davinci_crd_test_kit/requirements/hl7.fhir.us.davinci-crd_2.0.1_requirements.xlsx +0 -0
- data/lib/davinci_crd_test_kit/requirements/hl7.fhir.us.davinci-crd_2.2.1_requirements.xlsx +0 -0
- data/lib/davinci_crd_test_kit/server/endpoints/jwk_set_endpoint_handler.rb +13 -0
- data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_create_endpoint.rb +23 -0
- data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_delete_endpoint.rb +30 -0
- data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_metadata_endpoint.rb +112 -0
- data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_read_endpoint.rb +21 -0
- data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb +261 -0
- data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_search_endpoint.rb +561 -0
- data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_update_endpoint.rb +24 -0
- data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/stress-test-Bundle.json +54687 -0
- data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr_endpoints.rb +95 -0
- data/lib/davinci_crd_test_kit/server/jobs/invoke_hook.rb +225 -0
- data/lib/davinci_crd_test_kit/{jwt_helper.rb → server/jwt_helper.rb} +1 -12
- data/lib/davinci_crd_test_kit/server/resource_extractor.rb +68 -0
- data/lib/davinci_crd_test_kit/server/server_abstract_invoke_hook_test.rb +165 -0
- data/lib/davinci_crd_test_kit/server/server_base_urls.rb +30 -0
- data/lib/davinci_crd_test_kit/{server_hook_helper.rb → server/server_hook_helper.rb} +1 -1
- data/lib/davinci_crd_test_kit/{server_hook_request_validation.rb → server/server_hook_request_validation.rb} +1 -1
- data/lib/davinci_crd_test_kit/{test_helper.rb → server/server_test_helper.rb} +7 -3
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Appointment.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/ClaimResponse.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/CommunicationRequest.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Coverage.yml +21 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Device.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/DeviceRequest.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Encounter.yml +7 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Location.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/MedicationRequest.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/NutritionOrder.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Organization.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Patient.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Practitioner.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/PractitionerRole.yml +40 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/ServiceRequest.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Task.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/VisionPrescription.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_server_suite.rb +99 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/discovery/discovery_endpoint_test.rb +90 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/discovery/discovery_services_validation_test.rb +67 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/interaction/server_invoke_hook_test.rb +12 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/must_support/coverage_information_system_action_across_hooks_validation_test.rb +34 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/must_support/external_reference_card_across_hooks_validation_test.rb +30 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/must_support/instructions_card_received_across_hooks_test.rb +27 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/server_appointment_book_group.rb +191 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/server_demonstrate_hook_response_group.rb +93 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/server_discovery_group.rb +62 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/server_encounter_discharge_group.rb +186 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/server_encounter_start_group.rb +186 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/server_hooks_group.rb +73 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/server_order_dispatch_group.rb +191 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/server_order_select_group.rb +211 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/server_order_sign_group.rb +216 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/server_required_card_response_validation_group.rb +28 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/server_urls.rb +13 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/verify_request/service_request_context_validation_test.rb +30 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/verify_request/service_request_optional_fields_validation_test.rb +39 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/verify_request/service_request_required_fields_validation_test.rb +40 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/additional_orders_validation_test.rb +59 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/card_optional_fields_validation_test.rb +51 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/coverage_information_system_action_received_test.rb +65 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/coverage_information_system_action_validation_test.rb +120 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/create_or_update_coverage_info_response_validation_test.rb +70 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/external_reference_card_validation_test.rb +37 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/form_completion_response_validation_test.rb +67 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/instructions_card_received_test.rb +30 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/launch_smart_app_card_validation_test.rb +39 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/propose_alternate_request_card_validation_test.rb +46 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/service_response_validation_test.rb +83 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Appointment_withorder.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Appointment_withoutorder.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/CommunicationRequest.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Coverage.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Device.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/DeviceRequest.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Encounter.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Location.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/MedicationRequest.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/NutritionOrder.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Organization.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Patient.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/PractitionerRole.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/ServiceRequest.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/VisionPrescription.yml +5 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_server_suite.rb +115 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/discovery/discovery_configuration_test.rb +159 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/discovery/discovery_endpoint_test.rb +90 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/discovery/discovery_prefetch_support_test.rb +43 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/discovery/discovery_services_validation_test.rb +121 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/interaction/server_invoke_hook_test.rb +17 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/must_support/coverage_information_must_support_test.rb +71 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/must_support/coverage_information_system_action_across_hooks_validation_test.rb +36 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/must_support/supported_us_core_versions_test.rb +118 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_appointment_book_group.rb +213 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_demonstrate_hook_response_group.rb +93 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_discovery_group.rb +69 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_encounter_discharge_group.rb +194 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_encounter_start_group.rb +194 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_hooks_group.rb +73 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_order_dispatch_group.rb +214 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_order_select_group.rb +219 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_order_sign_group.rb +241 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_required_card_response_validation_group.rb +30 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_urls.rb +13 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_request/service_request_context_validation_test.rb +30 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_request/service_request_no_custom_extensions_test.rb +120 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_request/service_request_optional_fields_validation_test.rb +39 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_request/service_request_required_fields_validation_test.rb +40 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/additional_orders_validation_test.rb +66 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/all_responses_include_coverage_information_test.rb +123 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/card_optional_fields_validation_test.rb +57 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/coverage_info_configuration_test.rb +83 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/coverage_information_system_action_received_test.rb +65 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/coverage_information_system_action_validation_test.rb +184 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/create_or_update_coverage_info_response_validation_test.rb +75 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/external_reference_card_validation_test.rb +47 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/form_completion_response_validation_test.rb +91 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/hook_request_resource_resolution.rb +137 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/instructions_card_received_test.rb +32 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/launch_smart_app_card_validation_test.rb +49 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/order_dispatch_coverage_information_test.rb +38 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/propose_alternate_request_card_validation_test.rb +54 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/service_response_validation_test.rb +97 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/unknown_cds_hooks_elements_test.rb +78 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/unknown_configuration_test.rb +78 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/unknown_context_test.rb +78 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/verify_response_without_billing_options_test.rb +43 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/verify_response_without_configuration_test.rb +44 -0
- data/lib/davinci_crd_test_kit/version.rb +2 -2
- data/lib/davinci_crd_test_kit.rb +4 -2
- metadata +308 -101
- data/lib/davinci_crd_test_kit/client_fhir_api_group.rb +0 -785
- data/lib/davinci_crd_test_kit/client_hooks_group.rb +0 -75
- data/lib/davinci_crd_test_kit/client_tests/appointment_book_receive_request_test.rb +0 -93
- data/lib/davinci_crd_test_kit/client_tests/client_appointment_book_group.rb +0 -75
- data/lib/davinci_crd_test_kit/client_tests/client_display_cards_attest.rb +0 -48
- data/lib/davinci_crd_test_kit/client_tests/client_encounter_discharge_group.rb +0 -73
- data/lib/davinci_crd_test_kit/client_tests/client_encounter_start_group.rb +0 -73
- data/lib/davinci_crd_test_kit/client_tests/client_fhir_api_create_test.rb +0 -41
- data/lib/davinci_crd_test_kit/client_tests/client_fhir_api_read_test.rb +0 -39
- data/lib/davinci_crd_test_kit/client_tests/client_fhir_api_search_test.rb +0 -232
- data/lib/davinci_crd_test_kit/client_tests/client_fhir_api_update_test.rb +0 -41
- data/lib/davinci_crd_test_kit/client_tests/client_fhir_api_validation_test.rb +0 -60
- data/lib/davinci_crd_test_kit/client_tests/client_order_dispatch_group.rb +0 -79
- data/lib/davinci_crd_test_kit/client_tests/client_order_select_group.rb +0 -82
- data/lib/davinci_crd_test_kit/client_tests/client_order_sign_group.rb +0 -81
- data/lib/davinci_crd_test_kit/client_tests/client_registration_verification_test.rb +0 -88
- data/lib/davinci_crd_test_kit/client_tests/decode_auth_token_test.rb +0 -60
- data/lib/davinci_crd_test_kit/client_tests/encounter_discharge_receive_request_test.rb +0 -90
- data/lib/davinci_crd_test_kit/client_tests/encounter_start_receive_request_test.rb +0 -90
- data/lib/davinci_crd_test_kit/client_tests/hook_request_optional_fields_test.rb +0 -57
- data/lib/davinci_crd_test_kit/client_tests/hook_request_required_fields_test.rb +0 -49
- data/lib/davinci_crd_test_kit/client_tests/hook_request_valid_context_test.rb +0 -68
- data/lib/davinci_crd_test_kit/client_tests/hook_request_valid_prefetch_test.rb +0 -69
- data/lib/davinci_crd_test_kit/client_tests/order_dispatch_receive_request_test.rb +0 -102
- data/lib/davinci_crd_test_kit/client_tests/order_select_receive_request_test.rb +0 -98
- data/lib/davinci_crd_test_kit/client_tests/order_sign_receive_request_test.rb +0 -101
- data/lib/davinci_crd_test_kit/client_tests/retrieve_jwks_test.rb +0 -105
- data/lib/davinci_crd_test_kit/client_tests/submitted_response_validation.rb +0 -44
- data/lib/davinci_crd_test_kit/client_tests/token_header_test.rb +0 -65
- data/lib/davinci_crd_test_kit/client_tests/token_payload_test.rb +0 -78
- data/lib/davinci_crd_test_kit/crd_client_suite.rb +0 -185
- data/lib/davinci_crd_test_kit/crd_options.rb +0 -9
- data/lib/davinci_crd_test_kit/crd_server_suite.rb +0 -125
- data/lib/davinci_crd_test_kit/igs/davinci-crd-2.0.1.tgz +0 -0
- data/lib/davinci_crd_test_kit/routes/cds_services_discovery_handler.rb +0 -18
- data/lib/davinci_crd_test_kit/routes/hook_request_endpoint.rb +0 -77
- data/lib/davinci_crd_test_kit/routes/jwk_set_endpoint_handler.rb +0 -15
- data/lib/davinci_crd_test_kit/server_appointment_book_group.rb +0 -176
- data/lib/davinci_crd_test_kit/server_demonstrate_hook_response_group.rb +0 -77
- data/lib/davinci_crd_test_kit/server_discovery_group.rb +0 -60
- data/lib/davinci_crd_test_kit/server_encounter_discharge_group.rb +0 -170
- data/lib/davinci_crd_test_kit/server_encounter_start_group.rb +0 -170
- data/lib/davinci_crd_test_kit/server_hooks_group.rb +0 -71
- data/lib/davinci_crd_test_kit/server_order_dispatch_group.rb +0 -176
- data/lib/davinci_crd_test_kit/server_order_select_group.rb +0 -195
- data/lib/davinci_crd_test_kit/server_order_sign_group.rb +0 -201
- data/lib/davinci_crd_test_kit/server_required_card_response_validation_group.rb +0 -26
- data/lib/davinci_crd_test_kit/server_tests/additional_orders_validation_test.rb +0 -68
- data/lib/davinci_crd_test_kit/server_tests/card_optional_fields_validation_test.rb +0 -47
- data/lib/davinci_crd_test_kit/server_tests/coverage_information_system_action_across_hooks_validation_test.rb +0 -32
- data/lib/davinci_crd_test_kit/server_tests/coverage_information_system_action_received_test.rb +0 -63
- data/lib/davinci_crd_test_kit/server_tests/coverage_information_system_action_validation_test.rb +0 -118
- data/lib/davinci_crd_test_kit/server_tests/create_or_update_coverage_info_response_validation_test.rb +0 -71
- data/lib/davinci_crd_test_kit/server_tests/discovery_endpoint_test.rb +0 -88
- data/lib/davinci_crd_test_kit/server_tests/discovery_services_validation_test.rb +0 -65
- data/lib/davinci_crd_test_kit/server_tests/external_reference_card_across_hooks_validation_test.rb +0 -28
- data/lib/davinci_crd_test_kit/server_tests/external_reference_card_validation_test.rb +0 -36
- data/lib/davinci_crd_test_kit/server_tests/form_completion_response_validation_test.rb +0 -78
- data/lib/davinci_crd_test_kit/server_tests/instructions_card_received_across_hooks_test.rb +0 -25
- data/lib/davinci_crd_test_kit/server_tests/instructions_card_received_test.rb +0 -26
- data/lib/davinci_crd_test_kit/server_tests/launch_smart_app_card_validation_test.rb +0 -38
- data/lib/davinci_crd_test_kit/server_tests/propose_alternate_request_card_validation_test.rb +0 -63
- data/lib/davinci_crd_test_kit/server_tests/service_call_test.rb +0 -101
- data/lib/davinci_crd_test_kit/server_tests/service_request_context_validation_test.rb +0 -28
- data/lib/davinci_crd_test_kit/server_tests/service_request_optional_fields_validation_test.rb +0 -37
- data/lib/davinci_crd_test_kit/server_tests/service_request_required_fields_validation_test.rb +0 -38
- data/lib/davinci_crd_test_kit/server_tests/service_response_validation_test.rb +0 -81
- data/lib/davinci_crd_test_kit/tags.rb +0 -10
- data/lib/davinci_crd_test_kit/urls.rb +0 -52
- /data/lib/davinci_crd_test_kit/{card_responses → client/endpoints/mocked_card_responses}/external_reference.json +0 -0
- /data/lib/davinci_crd_test_kit/{card_responses → client/endpoints/mocked_card_responses}/instructions.json +0 -0
- /data/lib/davinci_crd_test_kit/{crd_jwks.json → server/endpoints/crd_jwks.json} +0 -0
- /data/lib/davinci_crd_test_kit/{jwks.rb → server/endpoints/jwks.rb} +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require_relative '../../multi_request_message_helper'
|
|
2
|
+
require_relative '../../tagged_request_load_helper'
|
|
3
|
+
|
|
4
|
+
module DaVinciCRDTestKit
|
|
5
|
+
module V221
|
|
6
|
+
class DecodeAuthTokenTest < Inferno::Test
|
|
7
|
+
include DaVinciCRDTestKit::MultiRequestMessageHelper
|
|
8
|
+
include DaVinciCRDTestKit::TaggedRequestLoadHelper
|
|
9
|
+
|
|
10
|
+
id :crd_v221_decode_auth_token
|
|
11
|
+
title 'Bearer tokens can be decoded'
|
|
12
|
+
description %(
|
|
13
|
+
During this test, Inferno will verify that for each request the Bearer token is a properly constructed JWT.
|
|
14
|
+
As per the [CDS hooks specification](https://cds-hooks.hl7.org/2026Jan/en/#trusting-cds-clients),
|
|
15
|
+
each time a CDS client transmits a request to a CDS Service which requires authentication, the request MUST
|
|
16
|
+
include an Authorization header presenting the JWT as a "Bearer" token.
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
verifies_requirements 'cds-hooks_3.0.0-ballot@178'
|
|
20
|
+
|
|
21
|
+
output :auth_tokens, :auth_token_payloads_json, :auth_token_headers_json
|
|
22
|
+
|
|
23
|
+
run do
|
|
24
|
+
load_hook_requests
|
|
25
|
+
skip_if requests.empty?, "No #{hook_name} requests were made in a previous test as expected."
|
|
26
|
+
auth_tokens = []
|
|
27
|
+
auth_token_payloads_json = []
|
|
28
|
+
auth_token_headers_json = []
|
|
29
|
+
|
|
30
|
+
requests.each_with_index do |request, index|
|
|
31
|
+
authorization_header = request.request_header('Authorization')&.value
|
|
32
|
+
|
|
33
|
+
unless authorization_header&.start_with?('Bearer ')
|
|
34
|
+
add_request_message('error', 'Authorization token must be a JWT presented as a `Bearer` token', index)
|
|
35
|
+
auth_tokens << nil
|
|
36
|
+
auth_token_payloads_json << nil
|
|
37
|
+
auth_token_headers_json << nil
|
|
38
|
+
next
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
auth_token = authorization_header.delete_prefix('Bearer ')
|
|
42
|
+
auth_tokens << auth_token
|
|
43
|
+
|
|
44
|
+
begin
|
|
45
|
+
payload, header =
|
|
46
|
+
JWT.decode(
|
|
47
|
+
auth_token,
|
|
48
|
+
nil,
|
|
49
|
+
false
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
auth_token_payloads_json << payload.to_json
|
|
53
|
+
auth_token_headers_json << header.to_json
|
|
54
|
+
rescue StandardError => e
|
|
55
|
+
add_request_message('error', "Token is not a properly constructed JWT: #{e.message}", index)
|
|
56
|
+
auth_token_payloads_json << nil
|
|
57
|
+
auth_token_headers_json << nil
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
output auth_tokens: auth_tokens.to_json,
|
|
61
|
+
auth_token_payloads_json: auth_token_payloads_json.to_json,
|
|
62
|
+
auth_token_headers_json: auth_token_headers_json.to_json
|
|
63
|
+
|
|
64
|
+
assert_no_error_messages("#{requests_with_errors_prefix}Decoding Authorization header Bearer tokens failed. " \
|
|
65
|
+
'See Messages for details.')
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
require_relative '../../multi_request_message_helper'
|
|
2
|
+
|
|
3
|
+
module DaVinciCRDTestKit
|
|
4
|
+
module V221
|
|
5
|
+
class RetrieveJWKSTest < Inferno::Test
|
|
6
|
+
include DaVinciCRDTestKit::MultiRequestMessageHelper
|
|
7
|
+
|
|
8
|
+
id :crd_v221_retrieve_jwks
|
|
9
|
+
title 'JWKSs can be retrieved'
|
|
10
|
+
description %(
|
|
11
|
+
During this test, Inferno will verify that for each request the JWKS can be retrieved from the JWKS uri if
|
|
12
|
+
it is present in the `jku` field within the JWT token header. Additionally, keys will be extracted and
|
|
13
|
+
outputted for use in subsequent tests. If the client does not provide a uri in the `jku` field,
|
|
14
|
+
Inferno will extract keys from the raw JWKS JSON provided out of band as a part of the "Registration" group.
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
verifies_requirements 'cds-hooks_3.0.0-ballot@183', 'cds-hooks_3.0.0-ballot@185', 'cds-hooks_3.0.0-ballot@197',
|
|
18
|
+
'cds-hooks_3.0.0-ballot@199'
|
|
19
|
+
|
|
20
|
+
input :auth_token_headers_json
|
|
21
|
+
input :cds_jwk_set,
|
|
22
|
+
title: 'CRD JSON Web Key Set (JWKS)',
|
|
23
|
+
type: 'textarea',
|
|
24
|
+
description: %(
|
|
25
|
+
The client's registered JWK Set containing it's public key. Used
|
|
26
|
+
only when a request was received with a JWT without the `jku` header.
|
|
27
|
+
Inferno assumes this input, provided during the "Registration"
|
|
28
|
+
group, contains the raw JSON representation of a JWKS (if a URI was provided
|
|
29
|
+
it would be populated in the `jku` header). Run or re-run the "Registration"
|
|
30
|
+
group to set or change this value.
|
|
31
|
+
),
|
|
32
|
+
locked: true,
|
|
33
|
+
optional: true
|
|
34
|
+
output :crd_jwks_keys_json
|
|
35
|
+
|
|
36
|
+
run do
|
|
37
|
+
auth_token_headers = JSON.parse(auth_token_headers_json) # NOTE: pre-verified json
|
|
38
|
+
skip_if auth_token_headers.compact.empty?, 'No Authorization tokens produced from the previous test.'
|
|
39
|
+
skip_if cds_jwk_set.blank? && cds_jwk_set_input_needed?(auth_token_headers),
|
|
40
|
+
"JWK Set must be inputted if the client's JWK Set is not available"
|
|
41
|
+
|
|
42
|
+
crd_jwks_keys_json = []
|
|
43
|
+
auth_token_headers.each_with_index do |token_header, index|
|
|
44
|
+
unless token_header.present?
|
|
45
|
+
crd_jwks_keys_json << nil
|
|
46
|
+
next
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
jku = JSON.parse(token_header)['jku'] # NOTE: pre-verified json
|
|
50
|
+
jwks =
|
|
51
|
+
if jku.present?
|
|
52
|
+
get(jku)
|
|
53
|
+
|
|
54
|
+
if response[:status] == 200
|
|
55
|
+
parse_json_request_entity(response[:body], 'Fetched jku url response', index)
|
|
56
|
+
else
|
|
57
|
+
add_request_message('error',
|
|
58
|
+
"Unexpected response status: expected 200, but received #{response[:status]}",
|
|
59
|
+
index)
|
|
60
|
+
nil
|
|
61
|
+
end
|
|
62
|
+
else
|
|
63
|
+
parse_json_request_entity(cds_jwk_set, 'JWK Set input', index)
|
|
64
|
+
end
|
|
65
|
+
if jwks.blank?
|
|
66
|
+
crd_jwks_keys_json << nil
|
|
67
|
+
next
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
keys = jwks['keys']
|
|
71
|
+
unless keys.is_a?(Array)
|
|
72
|
+
add_request_message('error', 'JWKS `keys` field must be an array', index)
|
|
73
|
+
crd_jwks_keys_json << nil
|
|
74
|
+
next
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
if keys.blank?
|
|
78
|
+
add_request_message('error', 'The JWK set returned contains no public keys', index)
|
|
79
|
+
crd_jwks_keys_json << nil
|
|
80
|
+
next
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
keys.each do |jwk|
|
|
84
|
+
JWT::JWK.import(jwk.deep_symbolize_keys)
|
|
85
|
+
rescue StandardError
|
|
86
|
+
add_request_message('error', "Invalid JWK: #{jwk.to_json}", index)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
kid_presence = keys.all? { |key| key['kid'].present? }
|
|
90
|
+
if kid_presence.blank?
|
|
91
|
+
add_request_message('error',
|
|
92
|
+
'`kid` field must be present in each key if JWKS contains multiple keys',
|
|
93
|
+
index)
|
|
94
|
+
crd_jwks_keys_json << nil
|
|
95
|
+
next
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
kid_uniqueness = keys.map { |key| key['kid'] }.uniq.length == keys.length
|
|
99
|
+
if kid_uniqueness.blank?
|
|
100
|
+
add_request_message('error', "`kid` must be unique within the client's JWK Set.", index)
|
|
101
|
+
crd_jwks_keys_json << nil
|
|
102
|
+
next
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
crd_jwks_keys_json << keys.to_json
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
output crd_jwks_keys_json: crd_jwks_keys_json.to_json
|
|
109
|
+
|
|
110
|
+
assert_no_error_messages("#{requests_with_errors_prefix}Retrieving JWKS failed. See Messages for details.")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def cds_jwk_set_input_needed?(auth_token_headers)
|
|
114
|
+
auth_token_headers.any? do |token_header|
|
|
115
|
+
token_header.present? && JSON.parse(token_header)['jku'].blank?
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
require_relative '../../multi_request_message_helper'
|
|
2
|
+
|
|
3
|
+
module DaVinciCRDTestKit
|
|
4
|
+
module V221
|
|
5
|
+
class TokenHeaderTest < Inferno::Test
|
|
6
|
+
include DaVinciCRDTestKit::MultiRequestMessageHelper
|
|
7
|
+
|
|
8
|
+
id :crd_v221_token_header
|
|
9
|
+
title 'Authorization token headers contain required information'
|
|
10
|
+
description %(
|
|
11
|
+
During this test, Inferno will verify that for each request the JWT header is conformant to the
|
|
12
|
+
requirements in the [CDS hooks specification](https://cds-hooks.hl7.org/2026Jan/en/#trusting-cds-clients),
|
|
13
|
+
including the following:
|
|
14
|
+
- The `alg`, `kid`, and `typ` fields are required.
|
|
15
|
+
- The `typ` field must be "JWT".
|
|
16
|
+
- The key used to sign the token must be present in the JWKS.
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
verifies_requirements 'cds-hooks_3.0.0-ballot@182', 'cds-hooks_3.0.0-ballot@184', 'cds-hooks_3.0.0-ballot@202'
|
|
20
|
+
|
|
21
|
+
input :auth_token_headers_json, :crd_jwks_keys_json
|
|
22
|
+
output :auth_tokens_jwk_json
|
|
23
|
+
|
|
24
|
+
run do
|
|
25
|
+
auth_token_headers = JSON.parse(auth_token_headers_json)
|
|
26
|
+
crd_jwks_keys = JSON.parse(crd_jwks_keys_json)
|
|
27
|
+
skip_if auth_token_headers.compact.empty?, 'No Authorization tokens produced from the previous tests.'
|
|
28
|
+
skip_if crd_jwks_keys.compact.empty?, 'No JWKS keys produced from the previous test.'
|
|
29
|
+
|
|
30
|
+
auth_tokens_jwk_json = []
|
|
31
|
+
auth_token_headers.each_with_index do |token_header, index|
|
|
32
|
+
unless token_header.present?
|
|
33
|
+
auth_tokens_jwk_json << nil
|
|
34
|
+
next
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
header = JSON.parse(token_header) # NOTE: pre-verified json
|
|
38
|
+
algorithm = header['alg']
|
|
39
|
+
|
|
40
|
+
if algorithm.blank?
|
|
41
|
+
add_request_message('error', 'Token header must have the `alg` field', index)
|
|
42
|
+
auth_tokens_jwk_json << nil
|
|
43
|
+
next
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
if algorithm == 'none'
|
|
47
|
+
add_request_message('error', 'Token header `alg` field cannot be set to none', index)
|
|
48
|
+
auth_tokens_jwk_json << nil
|
|
49
|
+
next
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if header['typ'].blank?
|
|
53
|
+
add_request_message('error', 'Token header must have the `typ` field', index)
|
|
54
|
+
elsif header['typ'] != 'JWT'
|
|
55
|
+
add_request_message('error',
|
|
56
|
+
"Token header `typ` field must be set to 'JWT', instead was #{header['typ']}",
|
|
57
|
+
index)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
if header['kid'].blank?
|
|
61
|
+
add_request_message('error', 'Token header must have the `kid` field', index)
|
|
62
|
+
auth_tokens_jwk_json << nil
|
|
63
|
+
next
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
kid = header['kid']
|
|
67
|
+
if crd_jwks_keys[index].nil?
|
|
68
|
+
add_request_message('error', 'No JWKS keys available for this request', index)
|
|
69
|
+
auth_tokens_jwk_json << nil
|
|
70
|
+
next
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
keys = JSON.parse(crd_jwks_keys[index]) # NOTE: pre-verified json
|
|
74
|
+
|
|
75
|
+
jwk = keys.find { |key| key['kid'] == kid }
|
|
76
|
+
if jwk.blank?
|
|
77
|
+
add_request_message('error', "JWKS did not contain a public key with an id of `#{kid}`", index)
|
|
78
|
+
auth_tokens_jwk_json << nil
|
|
79
|
+
next
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
auth_tokens_jwk_json << jwk.to_json
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
output auth_tokens_jwk_json: auth_tokens_jwk_json.to_json
|
|
86
|
+
|
|
87
|
+
assert_no_error_messages("#{requests_with_errors_prefix}Token header missing required information. " \
|
|
88
|
+
'See Messages for details.')
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
require_relative '../../multi_request_message_helper'
|
|
2
|
+
require_relative '../../tagged_request_load_helper'
|
|
3
|
+
|
|
4
|
+
module DaVinciCRDTestKit
|
|
5
|
+
module V221
|
|
6
|
+
class TokenPayloadTest < Inferno::Test
|
|
7
|
+
include DaVinciCRDTestKit::MultiRequestMessageHelper
|
|
8
|
+
include DaVinciCRDTestKit::TaggedRequestLoadHelper
|
|
9
|
+
include ClientURLs
|
|
10
|
+
|
|
11
|
+
id :crd_v221_token_payload
|
|
12
|
+
title 'Authorization token payloads have required claims and valid signatures'
|
|
13
|
+
description %(
|
|
14
|
+
During this test, Inferno will verify that for each request the JWT payload is conformant to the
|
|
15
|
+
requirements in the [CDS hooks specification](https://cds-hooks.hl7.org/2026Jan/en/#trusting-cds-clients),
|
|
16
|
+
including the following:
|
|
17
|
+
- The `iss`, `aud`, `exp`, `iat`, and `jti` claims are required.
|
|
18
|
+
- `iss` must match the `issuer` from the **CRD JWT Issuer** input.
|
|
19
|
+
- `aud` must match the URL of the CDS Service endpoint being invoked.
|
|
20
|
+
- `exp` must represent a time in the future.
|
|
21
|
+
- `jti` must be a non-blank string that uniquely identifies this authentication JWT.
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
verifies_requirements 'cds-hooks_3.0.0-ballot@180', 'cds-hooks_3.0.0-ballot@181', 'cds-hooks_3.0.0-ballot@187',
|
|
25
|
+
'cds-hooks_3.0.0-ballot@189', 'cds-hooks_3.0.0-ballot@190', 'cds-hooks_3.0.0-ballot@191',
|
|
26
|
+
'cds-hooks_3.0.0-ballot@192', 'cds-hooks_3.0.0-ballot@196', 'cds-hooks_3.0.0-ballot@203'
|
|
27
|
+
|
|
28
|
+
REQUIRED_CLAIMS = ['iss', 'aud', 'exp', 'iat', 'jti'].freeze
|
|
29
|
+
|
|
30
|
+
def required_claims
|
|
31
|
+
REQUIRED_CLAIMS.dup
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Replace the scheme+host of request.url with the configured external host
|
|
35
|
+
# so that aud validation works correctly when Inferno is behind a reverse proxy.
|
|
36
|
+
def public_hook_url(request)
|
|
37
|
+
hook_suffix = URI.parse(request.url).path.delete_prefix(URI.parse(inferno_base_url).path)
|
|
38
|
+
inferno_base_url + hook_suffix
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
input :auth_tokens,
|
|
42
|
+
:auth_tokens_jwk_json,
|
|
43
|
+
:cds_jwt_iss
|
|
44
|
+
|
|
45
|
+
run do
|
|
46
|
+
auth_tokens_list = JSON.parse(auth_tokens)
|
|
47
|
+
auth_tokens_jwk = JSON.parse(auth_tokens_jwk_json)
|
|
48
|
+
requests = load_hook_requests
|
|
49
|
+
skip_if auth_tokens_list.compact.empty?, 'No Authorization tokens produced from the previous tests.'
|
|
50
|
+
skip_if auth_tokens_jwk.compact.empty?, 'No Authorization token JWK produced from the previous test.'
|
|
51
|
+
|
|
52
|
+
auth_tokens_jwk.each_with_index do |auth_token_jwk, index|
|
|
53
|
+
next unless auth_token_jwk.present?
|
|
54
|
+
|
|
55
|
+
request = requests[index]
|
|
56
|
+
|
|
57
|
+
begin
|
|
58
|
+
jwk = JSON.parse(auth_token_jwk).deep_symbolize_keys # NOTE: pre-verified json
|
|
59
|
+
|
|
60
|
+
payload, =
|
|
61
|
+
JWT.decode(
|
|
62
|
+
auth_tokens_list[index],
|
|
63
|
+
JWT::JWK.import(jwk).public_key,
|
|
64
|
+
true,
|
|
65
|
+
algorithms: [jwk[:alg]],
|
|
66
|
+
exp_leeway: 60,
|
|
67
|
+
iss: cds_jwt_iss,
|
|
68
|
+
aud: public_hook_url(request),
|
|
69
|
+
verify_not_before: false,
|
|
70
|
+
verify_iat: false,
|
|
71
|
+
verify_jti: true,
|
|
72
|
+
verify_iss: true,
|
|
73
|
+
verify_aud: true
|
|
74
|
+
)
|
|
75
|
+
rescue StandardError => e
|
|
76
|
+
add_request_message('error', "Token validation error: #{e.message}", index)
|
|
77
|
+
next
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
missing_claims = required_claims - payload.keys
|
|
81
|
+
missing_claims_string = missing_claims.map { |claim| "`#{claim}`" }.join(', ')
|
|
82
|
+
|
|
83
|
+
unless missing_claims.empty?
|
|
84
|
+
add_request_message('error', "JWT payload missing required claims: #{missing_claims_string}", index)
|
|
85
|
+
next
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
assert_no_error_messages("#{requests_with_errors_prefix}Token payload is missing required claims or " \
|
|
89
|
+
'does not have a valid signature. See Messages for details.')
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
|
|
2
|
+
{
|
|
3
|
+
"services": [
|
|
4
|
+
{
|
|
5
|
+
"hook": "appointment-book",
|
|
6
|
+
"title": "Appointment Booking CDS Service",
|
|
7
|
+
"description": "A simulated CDS Service requesting a subset of the standard prefetches that is invoked when user of a CRD client books a future appointment for a patient",
|
|
8
|
+
"id": "appointment-book-subset",
|
|
9
|
+
"prefetch" : {
|
|
10
|
+
"pat": "Patient/{{context.patientId}}",
|
|
11
|
+
"enc": "Encounter/{{context.encounterId}}",
|
|
12
|
+
"cov": "Coverage?patient={{context.patientId}}&status=active",
|
|
13
|
+
"devReqs" : "DeviceRequest?_id={{context.appointments.entry.resource.basedOn.extension('http://hl7.org/fhir/StructureDefinition/alternate-reference').value.resolve().ofType(DeviceRequest).id}}",
|
|
14
|
+
"servReqs" : "ServiceRequest?_id={{context.appointments.entry.resource.basedOn.resolve().ofType(ServiceRequest).id}}",
|
|
15
|
+
"medReqs" : "MedicationRequest?_id={{context.appointments.entry.resource.basedOn.extension('http://hl7.org/fhir/StructureDefinition/alternate-reference').value.resolve().ofType(MedicationRequest).id}}",
|
|
16
|
+
"devs": "Device?_id={{%devReqs.entry.resource.code.resolve().id}}",
|
|
17
|
+
"meds": "Medication?_id={{%medReqs.entry.resource.medication.resolve().id}}",
|
|
18
|
+
"roles" : "PractitionerRole?_id={{%devReqs.entry.resource.performer.resolve().ofType(PractitionerRole).id|%medReqs.entry.resource.performer.resolve().ofType(PractitionerRole).id|%servReqs.entry.resource.performer.resolve().ofType(PractitionerRole).id}}",
|
|
19
|
+
"pracs" : "Practitioner?_id={{%roles.entry.resource.practitioner.resolve().id|%devReqs.entry.resource.performer.resolve().ofType(Practitioner).id|%medReqs.entry.resource.performer.resolve().ofType(Practitioner).id|%servReqs.entry.resource.performer.resolve().ofType(Practitioner).id}}",
|
|
20
|
+
"locs" : "Location?_id={{%roles.entry.resource.location.resolve().id|%enc.location.location.resolve().id|%servReqs.entry.resource.locationReference.resolve().ofType(Location).id}}"
|
|
21
|
+
},
|
|
22
|
+
"extension" : {
|
|
23
|
+
"davinci-crd.version" : [
|
|
24
|
+
"2.2",
|
|
25
|
+
"2.0"
|
|
26
|
+
],
|
|
27
|
+
"davinci-crd.configuration-options" : [
|
|
28
|
+
{
|
|
29
|
+
"code" : "coverage-info",
|
|
30
|
+
"type" : "boolean",
|
|
31
|
+
"name" : "Coverage Information",
|
|
32
|
+
"description" : "Information related to the patient's coverage, including whether a service is covered, requires prior authorization, is approved without seeking prior authorization, and/or requires additional documentation or data collection",
|
|
33
|
+
"default" : true
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"hook": "encounter-start",
|
|
40
|
+
"title": "Encounter Start CDS Service",
|
|
41
|
+
"description": "A simulated CDS Service requesting a subset of the standard prefetches that is invoked when the user is initiating a new encounter.",
|
|
42
|
+
"id": "encounter-start-subset",
|
|
43
|
+
"prefetch" : {
|
|
44
|
+
"pat": "Patient/{{context.patientId}}",
|
|
45
|
+
"enc": "Encounter/{{context.encounterId}}",
|
|
46
|
+
"cov": "Coverage?patient={{context.patientId}}&status=active",
|
|
47
|
+
"roles" : "PractitionerRole?_id={{%enc.participant.individual.resolve().ofType(PractitionerRole).id}}",
|
|
48
|
+
"pracs" : "Practitioner?_id={{%roles.entry.resource.practitioner.resolve().id|%enc.participant.individual.resolve().ofType(Practitioner).id}}",
|
|
49
|
+
"orgs" : "Organization?_id={{%roles.entry.resource.organization.resolve().id}}",
|
|
50
|
+
"locs" : "Location?_id={{%roles.entry.resource.location.resolve().id}}"
|
|
51
|
+
},
|
|
52
|
+
"extension" : {
|
|
53
|
+
"davinci-crd.version" : [
|
|
54
|
+
"2.2",
|
|
55
|
+
"2.0"
|
|
56
|
+
],
|
|
57
|
+
"davinci-crd.configuration-options" : [
|
|
58
|
+
{
|
|
59
|
+
"code" : "coverage-info",
|
|
60
|
+
"type" : "boolean",
|
|
61
|
+
"name" : "Coverage Information",
|
|
62
|
+
"description" : "Information related to the patient's coverage, including whether a service is covered, requires prior authorization, is approved without seeking prior authorization, and/or requires additional documentation or data collection",
|
|
63
|
+
"default" : true
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"hook": "encounter-discharge",
|
|
70
|
+
"title": "Encounter Disharge CDS Service Example",
|
|
71
|
+
"description": "A simulated CDS Service requesting a subset of the standard prefetches that is invoked when the user is performing the discharge process for an encounter - typically an inpatient encounter.",
|
|
72
|
+
"id": "encounter-discharge-subset",
|
|
73
|
+
"prefetch" : {
|
|
74
|
+
"pat": "Patient/{{context.patientId}}",
|
|
75
|
+
"enc": "Encounter/{{context.encounterId}}",
|
|
76
|
+
"cov": "Coverage?patient={{context.patientId}}&status=active",
|
|
77
|
+
"roles" : "PractitionerRole?_id={{%enc.participant.individual.resolve().ofType(PractitionerRole).id}}",
|
|
78
|
+
"pracs" : "Practitioner?_id={{%roles.entry.resource.practitioner.resolve().id|%enc.participant.individual.resolve().ofType(Practitioner).id}}",
|
|
79
|
+
"orgs" : "Organization?_id={{%roles.entry.resource.organization.resolve().id}}",
|
|
80
|
+
"locs" : "Location?_id={{%roles.entry.resource.location.resolve().id}}"
|
|
81
|
+
},
|
|
82
|
+
"extension" : {
|
|
83
|
+
"davinci-crd.version" : [
|
|
84
|
+
"2.2",
|
|
85
|
+
"2.0"
|
|
86
|
+
],
|
|
87
|
+
"davinci-crd.configuration-options" : [
|
|
88
|
+
{
|
|
89
|
+
"code" : "coverage-info",
|
|
90
|
+
"type" : "boolean",
|
|
91
|
+
"name" : "Coverage Information",
|
|
92
|
+
"description" : "Information related to the patient's coverage, including whether a service is covered, requires prior authorization, is approved without seeking prior authorization, and/or requires additional documentation or data collection",
|
|
93
|
+
"default" : true
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"hook": "order-dispatch",
|
|
100
|
+
"title": "Order Dispatch CDS Service Example",
|
|
101
|
+
"description": "A simulated CDS Service requesting a subset of the standard prefetches that fires when a practitioner is selecting a candidate performer for a pre-existing order that was not tied to a specific performer",
|
|
102
|
+
"id": "order-dispatch-subset",
|
|
103
|
+
"prefetch": {
|
|
104
|
+
"pat": "Patient/{{context.patientId}}",
|
|
105
|
+
"enc": "Encounter/{{context.encounterId}}",
|
|
106
|
+
"cov": "Coverage?patient={{context.patientId}}&status=active",
|
|
107
|
+
"comReqs": "CommunicationRequest?_id={{context.dispatchedOrders.resolve().ofType(CommunicationRequest).id}}",
|
|
108
|
+
"devReqs": "DeviceRequest?_id={{context.dispatchedOrders.resolve().ofType(DeviceRequest).id}}",
|
|
109
|
+
"medReqs": "MedicationRequest?_id={{context.dispatchedOrders.resolve().ofType(MedicationRequest).id}}",
|
|
110
|
+
"nutOrds": "NutritionOrder?_id={{context.dispatchedOrders.resolve().ofType(NutritionOrder).id}}",
|
|
111
|
+
"servReqs": "ServiceRequest?_id={{context.dispatchedOrders.resolve().ofType(ServiceRequest).id}}",
|
|
112
|
+
"visRxs": "VisionPrescription?_id={{context.dispatchedOrders.resolve().ofType(VisionPrescription).id}}",
|
|
113
|
+
"devs": "Device?_id={{%devReqs.entry.resource.code.resolve().id}}",
|
|
114
|
+
"meds": "Medication?_id={{%medReqs.entry.resource.medication.resolve().id}}",
|
|
115
|
+
"roles": "PractitionerRole?_id={{%comReqs.entry.resource.sender.resolve().ofType(PractitionerRole).id|%comReqs.entry.resource.recipient.resolve().ofType(PractitionerRole).id|%devReqs.entry.resource.performer.resolve().ofType(PractitionerRole).id|%medReqs.entry.resource.performer.resolve().ofType(PractitionerRole).id|%servReqs.entry.resource.performer.resolve().ofType(PractitionerRole).id}}",
|
|
116
|
+
"pracs": "Practitioner?_id={{%roles.entry.resource.practitioner.resolve().id|%comReqs.entry.resource.sender.resolve().ofType(Practitioner).id|%comReqs.entry.resource.recipient.resolve().ofType(Practitioner).id|%devReqs.entry.resource.performer.resolve().ofType(Practitioner).id|%medReqs.entry.resource.performer.resolve().ofType(Practitioner).id|%servReqs.entry.resource.performer.resolve().ofType(Practitioner).id}}",
|
|
117
|
+
"locs": "Location?_id={{%roles.entry.resource.location.resolve().id|%enc.location.location.resolve().id|%servReqs.entry.resource.locationReference.resolve().id}}"
|
|
118
|
+
},
|
|
119
|
+
"extension" : {
|
|
120
|
+
"davinci-crd.version" : [
|
|
121
|
+
"2.2",
|
|
122
|
+
"2.0"
|
|
123
|
+
],
|
|
124
|
+
"davinci-crd.configuration-options" : [
|
|
125
|
+
{
|
|
126
|
+
"code" : "coverage-info",
|
|
127
|
+
"type" : "boolean",
|
|
128
|
+
"name" : "Coverage Information",
|
|
129
|
+
"description" : "Information related to the patient's coverage, including whether a service is covered, requires prior authorization, is approved without seeking prior authorization, and/or requires additional documentation or data collection",
|
|
130
|
+
"default" : true
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"hook": "order-select",
|
|
137
|
+
"title": "Order Select CDS Service",
|
|
138
|
+
"description": "A simulated CDS Service requesting a subset of the standard prefetches that fires when a clinician selects one or more orders to place for a patient",
|
|
139
|
+
"id": "order-select-subset",
|
|
140
|
+
"prefetch": {
|
|
141
|
+
"pat": "Patient/{{context.patientId}}",
|
|
142
|
+
"enc": "Encounter/{{context.encounterId}}",
|
|
143
|
+
"cov": "Coverage?patient={{context.patientId}}&status=active",
|
|
144
|
+
"devs": "Device?_id={{context.draftOrders.entry.resource.ofType(DeviceRequest).code.resolve().id}}",
|
|
145
|
+
"meds": "Medication?_id={{context.draftOrders.entry.resource.ofType(MedicationRequest).medication.resolve().id}}",
|
|
146
|
+
"roles": "PractitionerRole?_id={{context.draftOrders.entry.resource.sender.resolve().ofType(PractitionerRole).id|context.draftOrders.entry.resource.recipient.resolve().ofType(PractitionerRole).id|context.draftOrders.entry.resource.performer.resolve().ofType(PractitionerRole).id}}",
|
|
147
|
+
"pracs": "Practitioner?_id={{%roles.entry.resource.practitioner.resolve().id|context.draftOrders.entry.resource.sender.resolve().ofType(Practitioner).id|context.draftOrders.entry.resource.recipient.resolve().ofType(Practitioner).id|context.draftOrders.entry.resource.performer.resolve().ofType(Practitioner).id}}",
|
|
148
|
+
"locs": "Location?_id={{%roles.entry.resource.location.resolve().id|%enc.location.location.resolve().id|context.draftOrders.entry.resource.locationReference.resolve().id}}"
|
|
149
|
+
},
|
|
150
|
+
"extension" : {
|
|
151
|
+
"davinci-crd.version" : [
|
|
152
|
+
"2.2",
|
|
153
|
+
"2.0"
|
|
154
|
+
],
|
|
155
|
+
"davinci-crd.configuration-options" : [
|
|
156
|
+
{
|
|
157
|
+
"code" : "coverage-info",
|
|
158
|
+
"type" : "boolean",
|
|
159
|
+
"name" : "Coverage Information",
|
|
160
|
+
"description" : "Information related to the patient's coverage, including whether a service is covered, requires prior authorization, is approved without seeking prior authorization, and/or requires additional documentation or data collection",
|
|
161
|
+
"default" : true
|
|
162
|
+
}
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"hook": "order-sign",
|
|
168
|
+
"title": "Order Sign CDS Service",
|
|
169
|
+
"description": "A simulated CDS Service requesting a subset of the standard prefetches that fires when a clinician is ready to sign one or more orders for a patient",
|
|
170
|
+
"id": "order-sign-subset",
|
|
171
|
+
"prefetch": {
|
|
172
|
+
"pat": "Patient/{{context.patientId}}",
|
|
173
|
+
"enc": "Encounter/{{context.encounterId}}",
|
|
174
|
+
"cov": "Coverage?patient={{context.patientId}}&status=active",
|
|
175
|
+
"devs": "Device?_id={{context.draftOrders.entry.resource.ofType(DeviceRequest).code.resolve().id}}",
|
|
176
|
+
"meds": "Medication?_id={{context.draftOrders.entry.resource.ofType(MedicationRequest).medication.resolve().id}}",
|
|
177
|
+
"roles": "PractitionerRole?_id={{context.draftOrders.entry.resource.sender.resolve().ofType(PractitionerRole).id|context.draftOrders.entry.resource.recipient.resolve().ofType(PractitionerRole).id|context.draftOrders.entry.resource.performer.resolve().ofType(PractitionerRole).id}}",
|
|
178
|
+
"pracs": "Practitioner?_id={{%roles.entry.resource.practitioner.resolve().id|context.draftOrders.entry.resource.sender.resolve().ofType(Practitioner).id|context.draftOrders.entry.resource.recipient.resolve().ofType(Practitioner).id|context.draftOrders.entry.resource.performer.resolve().ofType(Practitioner).id}}",
|
|
179
|
+
"locs": "Location?_id={{%roles.entry.resource.location.resolve().id|%enc.location.location.resolve().id|context.draftOrders.entry.resource.locationReference.resolve().id}}"
|
|
180
|
+
},
|
|
181
|
+
"extension" : {
|
|
182
|
+
"davinci-crd.version" : [
|
|
183
|
+
"2.2",
|
|
184
|
+
"2.0"
|
|
185
|
+
],
|
|
186
|
+
"davinci-crd.configuration-options" : [
|
|
187
|
+
{
|
|
188
|
+
"code" : "coverage-info",
|
|
189
|
+
"type" : "boolean",
|
|
190
|
+
"name" : "Coverage Information",
|
|
191
|
+
"description" : "Information related to the patient's coverage, including whether a service is covered, requires prior authorization, is approved without seeking prior authorization, and/or requires additional documentation or data collection",
|
|
192
|
+
"default" : true
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
}
|