diff --git a/app/controllers/concerns/idv/step_utilities_concern.rb b/app/controllers/concerns/idv/step_utilities_concern.rb index 59e03150f23..cd065b15560 100644 --- a/app/controllers/concerns/idv/step_utilities_concern.rb +++ b/app/controllers/concerns/idv/step_utilities_concern.rb @@ -2,15 +2,6 @@ module Idv module StepUtilitiesConcern extend ActiveSupport::Concern - def flow_session - user_session['idv/doc_auth'] - end - - # copied from doc_auth_controller - def flow_path - flow_session[:flow_path] - end - # Copied from capture_doc_flow.rb # and from doc_auth_flow.rb def acuant_sdk_ab_test_analytics_args diff --git a/app/controllers/concerns/idv/verify_info_concern.rb b/app/controllers/concerns/idv/verify_info_concern.rb index 2cbfd63dd82..4a8550ea3b0 100644 --- a/app/controllers/concerns/idv/verify_info_concern.rb +++ b/app/controllers/concerns/idv/verify_info_concern.rb @@ -86,6 +86,29 @@ def warning_url idv_session_errors_warning_url end + def process_async_state(current_async_state) + if current_async_state.none? + idv_session.invalidate_verify_info_step! + render :show + elsif current_async_state.in_progress? + render 'shared/wait' + elsif current_async_state.missing? + analytics.idv_proofing_resolution_result_missing + flash.now[:error] = I18n.t('idv.failure.timeout') + render :show + + delete_async + idv_session.invalidate_verify_info_step! + + log_idv_verification_submitted_event( + success: false, + failure_reason: { idv_verification: [:timeout] }, + ) + elsif current_async_state.done? + async_state_done(current_async_state) + end + end + def async_state_done(current_async_state) add_proofing_costs(current_async_state.result) form_response = idv_result_to_form_response( diff --git a/app/controllers/concerns/idv_step_concern.rb b/app/controllers/concerns/idv_step_concern.rb index 9f10dfdf291..fd12ca56b90 100644 --- a/app/controllers/concerns/idv_step_concern.rb +++ b/app/controllers/concerns/idv_step_concern.rb @@ -8,11 +8,21 @@ module IdvStepConcern before_action :confirm_idv_needed end - def confirm_document_capture_complete - @pii = flow_session&.[]('pii_from_doc') # hash with indifferent access - return if @pii.present? + def flow_session + user_session['idv/doc_auth'] + end + + def pii_from_doc + flow_session&.[]('pii_from_doc') + end - flow_path = flow_session&.[](:flow_path) + # copied from doc_auth_controller + def flow_path + flow_session&.[](:flow_path) + end + + def confirm_document_capture_complete + return if pii_from_doc.present? if IdentityConfig.store.doc_auth_document_capture_controller_enabled && flow_path == 'standard' diff --git a/app/controllers/idv/address_controller.rb b/app/controllers/idv/address_controller.rb index 9c07d69ed6c..29acabfd2ca 100644 --- a/app/controllers/idv/address_controller.rb +++ b/app/controllers/idv/address_controller.rb @@ -1,14 +1,14 @@ module Idv class AddressController < ApplicationController include IdvSession + include IdvStepConcern - before_action :confirm_two_factor_authenticated before_action :confirm_document_capture_complete def new analytics.idv_address_visit - @presenter = AddressPresenter.new(pii: @pii) + @presenter = AddressPresenter.new(pii: pii_from_doc) end def update @@ -24,22 +24,8 @@ def update private - def confirm_document_capture_complete - @pii = user_session.dig('idv/doc_auth', 'pii_from_doc') - return if @pii.present? - - flow_path = user_session.dig('idv/doc_auth', :flow_path) - - if IdentityConfig.store.doc_auth_document_capture_controller_enabled && - flow_path == 'standard' - redirect_to idv_document_capture_url - else - redirect_to idv_doc_auth_url - end - end - def idv_form - Idv::AddressForm.new(@pii) + Idv::AddressForm.new(pii_from_doc) end def success diff --git a/app/controllers/idv/doc_auth_controller.rb b/app/controllers/idv/doc_auth_controller.rb index b7ac16c4417..a26e6431bf0 100644 --- a/app/controllers/idv/doc_auth_controller.rb +++ b/app/controllers/idv/doc_auth_controller.rb @@ -72,17 +72,9 @@ def flow_session def check_for_outage return if flow_session[:skip_vendor_outage] - return redirect_for_proofing_vendor_outage if OutageStatus.new.any_idv_vendor_outage? return redirect_for_gpo_only if FeatureManagement.idv_gpo_only? end - def redirect_for_proofing_vendor_outage - session[:vendor_outage_redirect] = current_step - session[:vendor_outage_redirect_from_idv] = true - - redirect_to vendor_outage_url - end - def redirect_for_gpo_only return redirect_to vendor_outage_url unless FeatureManagement.gpo_verification_enabled? diff --git a/app/controllers/idv/document_capture_controller.rb b/app/controllers/idv/document_capture_controller.rb index 36aa13bfd55..bdebd9e710f 100644 --- a/app/controllers/idv/document_capture_controller.rb +++ b/app/controllers/idv/document_capture_controller.rb @@ -1,11 +1,11 @@ module Idv class DocumentCaptureController < ApplicationController include IdvSession + include IdvStepConcern include StepIndicatorConcern include StepUtilitiesConcern include DocumentCaptureConcern - before_action :render_404_if_document_capture_controller_disabled before_action :confirm_two_factor_authenticated before_action :confirm_upload_step_complete before_action :confirm_document_capture_needed @@ -58,10 +58,6 @@ def extra_view_variables private - def render_404_if_document_capture_controller_disabled - render_not_found unless IdentityConfig.store.doc_auth_document_capture_controller_enabled - end - def confirm_upload_step_complete return if flow_session['Idv::Steps::UploadStep'] diff --git a/app/controllers/idv/in_person/usps_locations_controller.rb b/app/controllers/idv/in_person/usps_locations_controller.rb index 0f149e6736e..f85b6853b41 100644 --- a/app/controllers/idv/in_person/usps_locations_controller.rb +++ b/app/controllers/idv/in_person/usps_locations_controller.rb @@ -38,21 +38,28 @@ def index render json: response.to_json end - def proofer - @proofer ||= EnrollmentHelper.usps_proofer - end - # save the Post Office location the user selected to an enrollment def update enrollment.update!( selected_location_details: update_params.as_json, issuer: current_sp&.issuer, ) + add_proofing_component render json: { success: true }, status: :ok end - protected + private + + def proofer + @proofer ||= EnrollmentHelper.usps_proofer + end + + def add_proofing_component + ProofingComponent. + create_or_find_by(user: effective_user). + update(document_check: Idp::Constants::Vendors::USPS) + end def handle_error(err) remapped_error = case err diff --git a/app/controllers/idv/in_person/verify_info_controller.rb b/app/controllers/idv/in_person/verify_info_controller.rb index 3fef4d4b638..0443352c507 100644 --- a/app/controllers/idv/in_person/verify_info_controller.rb +++ b/app/controllers/idv/in_person/verify_info_controller.rb @@ -1,19 +1,17 @@ module Idv module InPerson class VerifyInfoController < ApplicationController - include IdvSession + include IdvStepConcern include StepIndicatorConcern include StepUtilitiesConcern + include Steps::ThreatMetrixStepHelper include VerifyInfoConcern before_action :renders_404_if_flag_not_set - before_action :confirm_two_factor_authenticated before_action :confirm_ssn_step_complete before_action :confirm_verify_info_step_needed def show - @in_person_proofing = true - @verify_info_submit_path = idv_in_person_verify_info_path @step_indicator_steps = step_indicator_steps increment_step_counts @@ -44,7 +42,6 @@ def update pii[:uuid_prefix] = ServiceProvider.find_by(issuer: sp_session[:issuer])&.app_id pii[:state_id_type] = 'drivers_license' unless pii.blank? - add_proofing_component ssn_throttle.increment! if ssn_throttle.throttled? @@ -95,12 +92,6 @@ def renders_404_if_flag_not_set render_not_found unless IdentityConfig.store.in_person_verify_info_controller_enabled end - def add_proofing_component - ProofingComponent. - create_or_find_by(user: current_user). - update(document_check: Idp::Constants::Vendors::USPS) - end - # copied from address_controller def confirm_ssn_step_complete return if pii.present? && pii[:ssn].present? @@ -147,30 +138,6 @@ def analytics_arguments irs_reproofing: irs_reproofing?, }.merge(**acuant_sdk_ab_test_analytics_args) end - - # copied from verify_base_step. May want reconciliation with phone_step - def process_async_state(current_async_state) - if current_async_state.none? - idv_session.resolution_successful = false - render 'idv/verify_info/show' - elsif current_async_state.in_progress? - render 'shared/wait' - elsif current_async_state.missing? - analytics.idv_proofing_resolution_result_missing - flash.now[:error] = I18n.t('idv.failure.timeout') - render 'idv/verify_info/show' - - delete_async - idv_session.resolution_successful = false - - log_idv_verification_submitted_event( - success: false, - failure_reason: { idv_verification: [:timeout] }, - ) - elsif current_async_state.done? - async_state_done(current_async_state) - end - end end end end diff --git a/app/controllers/idv/personal_key_controller.rb b/app/controllers/idv/personal_key_controller.rb index 231bc782a46..861e0bc6308 100644 --- a/app/controllers/idv/personal_key_controller.rb +++ b/app/controllers/idv/personal_key_controller.rb @@ -22,8 +22,8 @@ def update analytics.idv_personal_key_submitted( address_verification_method: address_verification_method, deactivation_reason: idv_session.profile&.deactivation_reason, - fraud_review_pending: idv_session.profile&.fraud_review_pending, - fraud_rejection: idv_session.profile&.fraud_rejection, + fraud_review_pending: idv_session.profile&.fraud_review_pending?, + fraud_rejection: idv_session.profile&.fraud_rejection?, ) redirect_to next_step end diff --git a/app/controllers/idv/phone_controller.rb b/app/controllers/idv/phone_controller.rb index 6afe9035396..b811b2ba8ae 100644 --- a/app/controllers/idv/phone_controller.rb +++ b/app/controllers/idv/phone_controller.rb @@ -126,7 +126,7 @@ def step end def step_params - params.require(:idv_phone_form).permit(:phone, :otp_delivery_preference) + params.require(:idv_phone_form).permit(:phone, :international_code, :otp_delivery_preference) end def confirm_step_needed diff --git a/app/controllers/idv/phone_errors_controller.rb b/app/controllers/idv/phone_errors_controller.rb index fed541d4730..0c2565b26c6 100644 --- a/app/controllers/idv/phone_errors_controller.rb +++ b/app/controllers/idv/phone_errors_controller.rb @@ -1,5 +1,6 @@ module Idv class PhoneErrorsController < ApplicationController + include StepIndicatorConcern include IdvSession before_action :confirm_two_factor_authenticated @@ -9,6 +10,8 @@ class PhoneErrorsController < ApplicationController def warning @remaining_attempts = throttle.remaining_count + @phone = idv_session.previous_phone_step_params[:phone] + @country_code = idv_session.previous_phone_step_params[:international_code] track_event(type: :warning) end diff --git a/app/controllers/idv/review_controller.rb b/app/controllers/idv/review_controller.rb index 5c648c2f146..8d2dcd0e272 100644 --- a/app/controllers/idv/review_controller.rb +++ b/app/controllers/idv/review_controller.rb @@ -53,16 +53,16 @@ def create analytics.idv_review_complete( success: true, - fraud_review_pending: idv_session.profile.fraud_review_pending, - fraud_rejection: idv_session.profile.fraud_rejection, + fraud_review_pending: idv_session.profile.fraud_review_pending?, + fraud_rejection: idv_session.profile.fraud_rejection?, deactivation_reason: idv_session.profile.deactivation_reason, ) Funnel::DocAuth::RegisterStep.new(current_user.id, current_sp&.issuer). call(:verified, :view, true) analytics.idv_final( success: true, - fraud_review_pending: idv_session.profile.fraud_review_pending, - fraud_rejection: idv_session.profile.fraud_rejection, + fraud_review_pending: idv_session.profile.fraud_review_pending?, + fraud_rejection: idv_session.profile.fraud_rejection?, deactivation_reason: idv_session.profile.deactivation_reason, ) diff --git a/app/controllers/idv/ssn_controller.rb b/app/controllers/idv/ssn_controller.rb index 25945d0373f..936b331d6f3 100644 --- a/app/controllers/idv/ssn_controller.rb +++ b/app/controllers/idv/ssn_controller.rb @@ -56,7 +56,7 @@ def extra_view_variables private def next_url - if @pii[:state] == 'PR' + if pii_from_doc[:state] == 'PR' idv_address_url else idv_verify_info_url diff --git a/app/controllers/idv/unavailable_controller.rb b/app/controllers/idv/unavailable_controller.rb new file mode 100644 index 00000000000..79ffe2bf1e4 --- /dev/null +++ b/app/controllers/idv/unavailable_controller.rb @@ -0,0 +1,34 @@ +module Idv + class UnavailableController < ApplicationController + ALLOWED_FROM_LOCATIONS = [SignUp::RegistrationsController::CREATE_ACCOUNT] + + before_action :redirect_if_idv_available_and_from_create_account + + def show + analytics.vendor_outage( + vendor_status: { + acuant: IdentityConfig.store.vendor_status_acuant, + lexisnexis_instant_verify: IdentityConfig.store.vendor_status_lexisnexis_instant_verify, + lexisnexis_trueid: IdentityConfig.store.vendor_status_lexisnexis_trueid, + sms: IdentityConfig.store.vendor_status_sms, + voice: IdentityConfig.store.vendor_status_voice, + }, + redirect_from: from, + ) + end + + private + + def from + params[:from] if ALLOWED_FROM_LOCATIONS.include?(params[:from]) + end + + def from_create_account? + from == SignUp::RegistrationsController::CREATE_ACCOUNT + end + + def redirect_if_idv_available_and_from_create_account + redirect_to sign_up_email_url if FeatureManagement.idv_available? && from_create_account? + end + end +end diff --git a/app/controllers/idv/verify_info_controller.rb b/app/controllers/idv/verify_info_controller.rb index 9ea99d5ae5b..494ca2257e8 100644 --- a/app/controllers/idv/verify_info_controller.rb +++ b/app/controllers/idv/verify_info_controller.rb @@ -10,8 +10,6 @@ class VerifyInfoController < ApplicationController before_action :confirm_verify_info_step_needed def show - @in_person_proofing = false - @verify_info_submit_path = idv_verify_info_path @step_indicator_steps = step_indicator_steps increment_step_counts @@ -123,29 +121,5 @@ def current_flow_step_counts def increment_step_counts current_flow_step_counts['verify'] += 1 end - - # copied from verify_base_step. May want reconciliation with phone_step - def process_async_state(current_async_state) - if current_async_state.none? - idv_session.invalidate_verify_info_step! - render :show - elsif current_async_state.in_progress? - render 'shared/wait' - elsif current_async_state.missing? - analytics.idv_proofing_resolution_result_missing - flash.now[:error] = I18n.t('idv.failure.timeout') - render :show - - delete_async - idv_session.invalidate_verify_info_step! - - log_idv_verification_submitted_event( - success: false, - failure_reason: { idv_verification: [:timeout] }, - ) - elsif current_async_state.done? - async_state_done(current_async_state) - end - end end end diff --git a/app/controllers/sign_up/registrations_controller.rb b/app/controllers/sign_up/registrations_controller.rb index 51a9ddb7e71..0f26e3fb160 100644 --- a/app/controllers/sign_up/registrations_controller.rb +++ b/app/controllers/sign_up/registrations_controller.rb @@ -5,7 +5,7 @@ class RegistrationsController < ApplicationController before_action :confirm_two_factor_authenticated, only: [:destroy_confirm] before_action :require_no_authentication - before_action :redirect_if_ial2_and_vendor_outage + before_action :redirect_if_ial2_and_idv_unavailable CREATE_ACCOUNT = 'create_account' @@ -71,11 +71,10 @@ def sp_request_id ServiceProviderRequestProxy.from_uuid(request_id).uuid end - def redirect_if_ial2_and_vendor_outage - return unless ial2_requested? && OutageStatus.new.any_idv_vendor_outage? - - session[:vendor_outage_redirect] = CREATE_ACCOUNT - return redirect_to vendor_outage_url + def redirect_if_ial2_and_idv_unavailable + if ial2_requested? && !FeatureManagement.idv_available? + redirect_to idv_unavailable_path(from: CREATE_ACCOUNT) + end end end end diff --git a/app/controllers/users/backup_code_setup_controller.rb b/app/controllers/users/backup_code_setup_controller.rb index 191ca00855d..25e2bd61bfa 100644 --- a/app/controllers/users/backup_code_setup_controller.rb +++ b/app/controllers/users/backup_code_setup_controller.rb @@ -11,7 +11,7 @@ class BackupCodeSetupController < ApplicationController before_action :set_backup_code_setup_presenter before_action :apply_secure_headers_override before_action :authorize_backup_code_disable, only: [:delete] - before_action :confirm_recently_authenticated_2fa, if: -> do + before_action :confirm_recently_authenticated_2fa, except: [:reminder], if: -> do IdentityConfig.store.reauthentication_for_second_factor_management_enabled end diff --git a/app/controllers/vendor_outage_controller.rb b/app/controllers/vendor_outage_controller.rb index fdc023b203f..cf353672a33 100644 --- a/app/controllers/vendor_outage_controller.rb +++ b/app/controllers/vendor_outage_controller.rb @@ -1,13 +1,10 @@ class VendorOutageController < ApplicationController def show - vendor_status = OutageStatus.new( - sp: current_sp, - from: session.delete(:vendor_outage_redirect), - from_idv: session.delete(:vendor_outage_redirect_from_idv), - ) - @specific_message = vendor_status.outage_message + outage_status = OutageStatus.new + + @specific_message = outage_status.outage_message @show_gpo_option = from_idv_phone? && gpo_letter_available? - vendor_status.track_event(analytics) + outage_status.track_event(analytics) end private diff --git a/app/forms/idv/state_id_form.rb b/app/forms/idv/state_id_form.rb index 02c8b11a9a1..bbfb252ea16 100644 --- a/app/forms/idv/state_id_form.rb +++ b/app/forms/idv/state_id_form.rb @@ -4,8 +4,8 @@ class StateIdForm include FormStateIdValidator ATTRIBUTES = %i[first_name last_name dob state_id_address1 state_id_address2 - state_id_city state_id_zipcode state_id_jurisdiction state_id_number - same_address_as_id].freeze + state_id_city state_id_zipcode state_id_jurisdiction + state_id_state state_id_number same_address_as_id].freeze attr_accessor(*ATTRIBUTES) diff --git a/app/javascript/packages/document-capture/components/in-person-call-to-action.spec.tsx b/app/javascript/packages/document-capture/components/in-person-call-to-action.spec.tsx index d5e72f792a0..e5879ddf146 100644 --- a/app/javascript/packages/document-capture/components/in-person-call-to-action.spec.tsx +++ b/app/javascript/packages/document-capture/components/in-person-call-to-action.spec.tsx @@ -20,8 +20,8 @@ describe('InPersonCallToAction', () => { , ); - const link = getByRole('link', { name: 'in_person_proofing.body.cta.button' }); - await userEvent.click(link); + const button = getByRole('button', { name: 'in_person_proofing.body.cta.button' }); + await userEvent.click(button); expect(trackEvent).to.have.been.calledWith( 'IdV: verify in person troubleshooting option clicked', diff --git a/app/javascript/packages/document-capture/components/in-person-call-to-action.tsx b/app/javascript/packages/document-capture/components/in-person-call-to-action.tsx index 52c242153fa..61625ca68fc 100644 --- a/app/javascript/packages/document-capture/components/in-person-call-to-action.tsx +++ b/app/javascript/packages/document-capture/components/in-person-call-to-action.tsx @@ -2,6 +2,7 @@ import { useContext } from 'react'; import { Button } from '@18f/identity-components'; import { useInstanceId } from '@18f/identity-react-hooks'; import { t } from '@18f/identity-i18n'; +import useHistoryParam from '@18f/identity-form-steps/use-history-param'; import AnalyticsContext from '../context/analytics'; import { InPersonContext } from '../context'; @@ -15,6 +16,7 @@ function InPersonCallToAction({ altHeading, altPrompt, altButtonText }: InPerson const instanceId = useInstanceId(); const { trackEvent } = useContext(AnalyticsContext); const { inPersonCtaVariantActive } = useContext(InPersonContext); + const [, setStepName] = useHistoryParam(undefined); return (
+ onClick={() => { + setStepName('location'); trackEvent('IdV: verify in person troubleshooting option clicked', { in_person_cta_variant: inPersonCtaVariantActive, - }) - } + }); + }} > {altButtonText || t('in_person_proofing.body.cta.button')} diff --git a/app/javascript/packages/document-capture/components/in-person-location-post-office-search-step.tsx b/app/javascript/packages/document-capture/components/in-person-location-post-office-search-step.tsx index 95e73ff07e8..f5e8fce3792 100644 --- a/app/javascript/packages/document-capture/components/in-person-location-post-office-search-step.tsx +++ b/app/javascript/packages/document-capture/components/in-person-location-post-office-search-step.tsx @@ -112,7 +112,7 @@ function InPersonLocationPostOfficeSearchStep({ onChange, toPreviousStep, regist address={foundAddress?.address || ''} /> )} - + ); } diff --git a/app/javascript/packages/document-capture/components/in-person-prepare-step.spec.tsx b/app/javascript/packages/document-capture/components/in-person-prepare-step.spec.tsx index 74d2cf50ef8..74c1241355d 100644 --- a/app/javascript/packages/document-capture/components/in-person-prepare-step.spec.tsx +++ b/app/javascript/packages/document-capture/components/in-person-prepare-step.spec.tsx @@ -39,7 +39,7 @@ describe('InPersonPrepareStep', () => { { wrapper }, ); - await userEvent.click(getByRole('link', { name: 'forms.buttons.continue' })); + await userEvent.click(getByRole('button', { name: 'forms.buttons.continue' })); await waitFor(() => window.location.hash === inPersonURL); expect(trackEvent).to.have.been.calledWith('IdV: prepare submitted'); @@ -60,10 +60,10 @@ describe('InPersonPrepareStep', () => { { wrapper }, ); - const link = getByRole('link', { name: 'forms.buttons.continue' }); + const button = getByRole('button', { name: 'forms.buttons.continue' }); - const didFollowLinkOnFirstClick = fireEvent.click(link); - const didFollowLinkOnSecondClick = fireEvent.click(link); + const didFollowLinkOnFirstClick = fireEvent.click(button); + const didFollowLinkOnSecondClick = fireEvent.click(button); clock.tick(delay); diff --git a/app/javascript/packages/document-capture/components/in-person-prepare-step.tsx b/app/javascript/packages/document-capture/components/in-person-prepare-step.tsx index 91f5bbcf829..db61517b3b7 100644 --- a/app/javascript/packages/document-capture/components/in-person-prepare-step.tsx +++ b/app/javascript/packages/document-capture/components/in-person-prepare-step.tsx @@ -29,7 +29,7 @@ function InPersonPrepareStep({ toPreviousStep, value }) { setIsSubmitting(true); removeUnloadProtection(); await trackEvent('IdV: prepare submitted'); - window.location.href = (event.target as HTMLAnchorElement).href; + window.location.href = inPersonURL!; } }; @@ -59,7 +59,7 @@ function InPersonPrepareStep({ toPreviousStep, value }) { {flowPath === 'hybrid' && } {inPersonURL && flowPath === 'standard' && (
- + {t('forms.buttons.continue')}
@@ -78,7 +78,7 @@ function InPersonPrepareStep({ toPreviousStep, value }) { )}

- + ); } diff --git a/app/jobs/get_usps_proofing_results_job.rb b/app/jobs/get_usps_proofing_results_job.rb index f7f026edc7b..467f21a2ec2 100644 --- a/app/jobs/get_usps_proofing_results_job.rb +++ b/app/jobs/get_usps_proofing_results_job.rb @@ -117,6 +117,8 @@ def enrollment_analytics_attributes(enrollment, complete:) enrollment_code: enrollment.enrollment_code, enrollment_id: enrollment.id, minutes_since_last_status_check: enrollment.minutes_since_last_status_check, + minutes_since_last_status_check_completed: + enrollment.minutes_since_last_status_check_completed, minutes_since_last_status_update: enrollment.minutes_since_last_status_update, minutes_since_established: enrollment.minutes_since_established, minutes_to_completion: complete ? enrollment.minutes_since_established : nil, @@ -157,6 +159,7 @@ def handle_bad_request_error(err, enrollment) **enrollment_analytics_attributes(enrollment, complete: false), response_message: response_message, ) + enrollment.update(status_check_completed_at: Time.zone.now) elsif response_message&.match(IPP_EXPIRED_ERROR_MESSAGE) handle_expired_status_update(enrollment, err.response, response_message) elsif response_message == IPP_INVALID_ENROLLMENT_CODE_MESSAGE % enrollment.enrollment_code @@ -248,7 +251,11 @@ def handle_unsupported_id_type(enrollment, response) primary_id_type: response['primaryIdType'], reason: 'Unsupported ID type', ) - enrollment.update(status: :failed, proofed_at: proofed_at) + enrollment.update( + status: :failed, + proofed_at: proofed_at, + status_check_completed_at: Time.zone.now, + ) send_failed_email(enrollment.user, enrollment) analytics(user: enrollment.user).idv_in_person_usps_proofing_results_job_email_initiated( @@ -265,7 +272,10 @@ def handle_expired_status_update(enrollment, response, response_message) passed: false, reason: 'Enrollment has expired', ) - enrollment.update(status: :expired) + enrollment.update( + status: :expired, + status_check_completed_at: Time.zone.now, + ) begin send_deadline_passed_email(enrollment.user, enrollment) unless enrollment.deadline_passed_sent @@ -321,7 +331,11 @@ def handle_failed_status(enrollment, response) reason: 'Failed status', ) - enrollment.update(status: :failed, proofed_at: proofed_at) + enrollment.update( + status: :failed, + proofed_at: proofed_at, + status_check_completed_at: Time.zone.now, + ) if response['fraudSuspected'] send_failed_fraud_email(enrollment.user, enrollment) analytics(user: enrollment.user).idv_in_person_usps_proofing_results_job_email_initiated( @@ -347,7 +361,11 @@ def handle_successful_status_update(enrollment, response) reason: 'Successful status update', ) enrollment.profile.activate - enrollment.update(status: :passed, proofed_at: proofed_at) + enrollment.update( + status: :passed, + proofed_at: proofed_at, + status_check_completed_at: Time.zone.now, + ) analytics(user: enrollment.user).idv_in_person_usps_proofing_results_job_email_initiated( **email_analytics_attributes(enrollment), email_type: 'Success', diff --git a/app/jobs/reports/base_report.rb b/app/jobs/reports/base_report.rb index 33d2a5efe17..e424ffc8f49 100644 --- a/app/jobs/reports/base_report.rb +++ b/app/jobs/reports/base_report.rb @@ -50,14 +50,6 @@ def save_report(report_name, body, extension:) upload_file_to_s3_timestamped_and_latest(report_name, body, extension) end - def track_report_data_event(event, hash = {}) - write_hash_to_reports_log({ name: event, time: Time.zone.now.iso8601 }.merge(hash)) - end - - def write_hash_to_reports_log(log_hash) - reports_logger.info(log_hash.to_json) - end - def reports_logger @reports_logger ||= ActiveSupport::Logger.new(Rails.root.join('log', 'reports.log')) end diff --git a/app/jobs/reports/sp_active_users_report.rb b/app/jobs/reports/sp_active_users_report.rb index 184ae184140..4034e6d86b2 100644 --- a/app/jobs/reports/sp_active_users_report.rb +++ b/app/jobs/reports/sp_active_users_report.rb @@ -14,9 +14,11 @@ class SpActiveUsersReport < BaseReport # The report will run for the entire fiscal year that ended the day before rather than for the # partial day of October 1st in the current fiscal year. def perform(date) + range = reporting_range(date) + results = transaction_with_timeout do - range = reporting_range(date) - Db::Identity::SpActiveUserCounts.call(range.begin, range.end) + Db::Identity::SpActiveUserCounts.by_issuer(range.begin, range.end) + + Db::Identity::SpActiveUserCounts.overall(range.begin, range.end) end save_report(REPORT_NAME, results.to_json, extension: 'json') end diff --git a/app/jobs/reports/sp_user_counts_report.rb b/app/jobs/reports/sp_user_counts_report.rb index 64e8e76cc04..2304f951d55 100644 --- a/app/jobs/reports/sp_user_counts_report.rb +++ b/app/jobs/reports/sp_user_counts_report.rb @@ -6,53 +6,10 @@ class SpUserCountsReport < BaseReport def perform(_date) user_counts = transaction_with_timeout do - Db::Identity::SpUserCounts.call + Db::Identity::SpUserCounts.by_issuer + Db::Identity::SpUserCounts.overall end - track_report_data_events(user_counts) - results = save_report(REPORT_NAME, user_counts.to_json, extension: 'json') - - track_global_user_total_events - results - end - - private - - def track_report_data_events(user_counts) - user_counts.each do |hash| - track_report_data_event( - 'Report SP User Counts', - issuer: hash['issuer'], - user_total: hash['total'], - ial1_user_total: hash['ial1_total'], - ial2_user_total: hash['ial2_total'], - app_id: hash['app_id'].to_s, - ) - end - end - - def track_global_user_total_events - track_global_registered_users - track_users_linked_to_sps(ial: 1, event: 'Report IAL1 Users Linked to SPs Count') - track_users_linked_to_sps(ial: 2, event: 'Report IAL2 Users Linked to SPs Count') - end - - def track_global_registered_users - transaction_with_timeout do - track_report_data_event( - 'Report Registered Users Count', - count: Funnel::Registration::TotalRegisteredCount.call, - ) - end - end - - def track_users_linked_to_sps(ial:, event:) - transaction_with_timeout do - track_report_data_event( - event, - count: ServiceProviderIdentity.where(ial: ial).select(:user_id).distinct.count, - ) - end + save_report(REPORT_NAME, user_counts.to_json, extension: 'json') end end end diff --git a/app/models/in_person_enrollment.rb b/app/models/in_person_enrollment.rb index d3e450458fc..41a5a2a2e26 100644 --- a/app/models/in_person_enrollment.rb +++ b/app/models/in_person_enrollment.rb @@ -73,6 +73,11 @@ def minutes_since_last_status_check (Time.zone.now - status_check_attempted_at).seconds.in_minutes.round(2) end + def minutes_since_last_status_check_completed + return unless status_check_completed_at.present? + (Time.zone.now - status_check_completed_at).seconds.in_minutes.round(2) + end + def minutes_since_last_status_update return unless status_updated_at.present? (Time.zone.now - status_updated_at).seconds.in_minutes.round(2) diff --git a/app/models/profile.rb b/app/models/profile.rb index 66ac064e4ad..03c97de5f22 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -27,6 +27,14 @@ class Profile < ApplicationRecord attr_reader :personal_key + def fraud_review_pending? + !!(fraud_review_pending || fraud_review_pending_at) + end + + def fraud_rejection? + !!(fraud_rejection || fraud_rejection_at) + end + # rubocop:disable Rails/SkipsModelValidations def activate return if fraud_review_pending? || fraud_rejection? @@ -48,7 +56,10 @@ def activate # rubocop:enable Rails/SkipsModelValidations def activate_after_passing_review - update!(fraud_review_pending: false, fraud_rejection: false) + update!( + fraud_review_pending: false, fraud_rejection: false, fraud_review_pending_at: nil, + fraud_rejection_at: nil + ) track_fraud_review_adjudication(decision: 'pass') activate end @@ -58,11 +69,17 @@ def deactivate(reason) end def deactivate_for_fraud_review - update!(active: false, fraud_review_pending: true, fraud_rejection: false) + update!( + active: false, fraud_review_pending: true, fraud_rejection: false, + fraud_review_pending_at: Time.zone.now, fraud_rejection_at: nil + ) end def reject_for_fraud(notify_user:) - update!(active: false, fraud_review_pending: false, fraud_rejection: true) + update!( + active: false, fraud_review_pending: false, fraud_rejection: true, + fraud_review_pending_at: nil, fraud_rejection_at: Time.zone.now + ) track_fraud_review_adjudication( decision: notify_user ? 'manual_reject' : 'automatic_reject', ) diff --git a/app/models/proofing_component.rb b/app/models/proofing_component.rb index 0c6c38a5e55..011ca97381a 100644 --- a/app/models/proofing_component.rb +++ b/app/models/proofing_component.rb @@ -1,7 +1,3 @@ class ProofingComponent < ApplicationRecord belongs_to :user - - def review_eligible? - verified_at&.after?(30.days.ago) - end end diff --git a/app/models/user.rb b/app/models/user.rb index ecf8b1dff0c..021728c8381 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -102,6 +102,11 @@ def pending_profile profiles.gpo_verification_pending.order(created_at: :desc).first end + def fraud_review_eligible? + return false if !fraud_review_pending? + fraud_review_pending_profile.verified_at&.after?(30.days.ago) + end + def fraud_review_pending? fraud_review_pending_profile.present? end diff --git a/app/services/analytics_events.rb b/app/services/analytics_events.rb index a8d551a5151..512937553cf 100644 --- a/app/services/analytics_events.rb +++ b/app/services/analytics_events.rb @@ -2909,12 +2909,12 @@ def user_registration_2fa_setup_visit track_event('User Registration: 2FA Setup visited') end - # @param [String] redirect_from # @param [Hash] vendor_status + # @param [String,nil] redirect_from # Tracks when vendor has outage def vendor_outage( - redirect_from:, vendor_status:, + redirect_from: nil, **extra ) track_event( diff --git a/app/services/db/identity/sp_active_user_counts.rb b/app/services/db/identity/sp_active_user_counts.rb index bcb70bebf03..44b6034e2b3 100644 --- a/app/services/db/identity/sp_active_user_counts.rb +++ b/app/services/db/identity/sp_active_user_counts.rb @@ -1,38 +1,74 @@ module Db module Identity class SpActiveUserCounts - def self.call(start, finish = Time.zone.now) + def self.by_issuer(start, finish = Time.zone.now) params = { start: ActiveRecord::Base.connection.quote(start), finish: ActiveRecord::Base.connection.quote(finish), } + sql = format(<<~SQL, params) SELECT - service_providers.issuer, - MAX(app_id) AS app_id, - CAST(SUM(total_ial1_active) AS INTEGER) AS total_ial1_active, - CAST(SUM(total_ial2_active) AS INTEGER) AS total_ial2_active + identities.service_provider AS issuer + , MAX(service_providers.app_id) AS app_id + , COUNT(*) - SUM( + CASE + WHEN identities.last_ial2_authenticated_at BETWEEN %{start} AND %{finish} THEN 1 + ELSE 0 + END + ) AS total_ial1_active + , SUM( + CASE + WHEN identities.last_ial2_authenticated_at BETWEEN %{start} AND %{finish} THEN 1 + ELSE 0 + END + ) AS total_ial2_active + FROM identities + JOIN service_providers ON service_providers.issuer = identities.service_provider + WHERE + (identities.last_ial1_authenticated_at BETWEEN %{start} AND %{finish}) + OR (identities.last_ial2_authenticated_at BETWEEN %{start} AND %{finish}) + GROUP BY identities.service_provider + SQL + + ActiveRecord::Base.connection.execute(sql).to_a + end + + def self.overall(start, finish = Time.zone.now) + params = { + start: ActiveRecord::Base.connection.quote(start), + finish: ActiveRecord::Base.connection.quote(finish), + } + sql = format(<<~SQL, params) + SELECT + COUNT(*) AS total + , COUNT(by_user.is_ial2) AS ial2_active FROM ( - (SELECT - service_provider AS issuer, - count(*) AS total_ial1_active, - 0 AS total_ial2_active - FROM identities - WHERE %{start} <= last_ial1_authenticated_at AND last_ial1_authenticated_at <= %{finish} - GROUP BY issuer ORDER BY issuer) - UNION - (SELECT - service_provider AS issuer, - 0 AS total_ial1_active, - count(*) AS total_ial2_active + SELECT + identities.user_id + , BOOL_OR(identities.last_ial2_authenticated_at BETWEEN %{start} AND %{finish}) AS is_ial2 FROM identities - WHERE %{start} <= last_ial2_authenticated_at AND last_ial2_authenticated_at <= %{finish} - GROUP BY issuer ORDER BY issuer) - ) AS union_of_ial1_and_ial2_results, service_providers - WHERE union_of_ial1_and_ial2_results.issuer = service_providers.issuer - GROUP BY service_providers.issuer ORDER BY service_providers.issuer + WHERE + (identities.last_ial1_authenticated_at BETWEEN %{start} AND %{finish}) + OR (identities.last_ial2_authenticated_at BETWEEN %{start} AND %{finish}) + GROUP BY identities.user_id + ) by_user SQL - ActiveRecord::Base.connection.execute(sql) + + row = ActiveRecord::Base.connection.execute(sql).to_a.first + + total = row&.fetch('total') || 0 + total_ial2_active = row&.fetch('ial2_active') || 0 + total_ial1_active = total - total_ial2_active + + [ + { + issuer: nil, + app_id: nil, + total_ial1_active:, + total_ial2_active:, + }.transform_keys(&:to_s), + ] end end end diff --git a/app/services/db/identity/sp_user_counts.rb b/app/services/db/identity/sp_user_counts.rb index 47540d5a1aa..8c262230c69 100644 --- a/app/services/db/identity/sp_user_counts.rb +++ b/app/services/db/identity/sp_user_counts.rb @@ -1,7 +1,7 @@ module Db module Identity class SpUserCounts - def self.call + def self.by_issuer sql = <<~SQL SELECT service_provider AS issuer, @@ -13,7 +13,38 @@ def self.call WHERE identities.service_provider = service_providers.issuer GROUP BY identities.service_provider ORDER BY identities.service_provider SQL - ActiveRecord::Base.connection.execute(sql) + ActiveRecord::Base.connection.execute(sql).to_a + end + + def self.overall + sql = <<~SQL + SELECT + COUNT(*) AS num_users + , by_user.is_ial2 + FROM ( + SELECT + identities.user_id + , BOOL_OR(identities.verified_at IS NOT NULL) AS is_ial2 + FROM identities + GROUP BY identities.user_id + ) by_user + GROUP BY by_user.is_ial2 + SQL + + results = ActiveRecord::Base.connection.execute(sql).to_a + + ial1_total = results.find { |r| !r['is_ial2'] }&.fetch('num_users') || 0 + ial2_total = results.find { |r| r['is_ial2'] }&.fetch('num_users') || 0 + + [ + { + issuer: nil, + app_id: nil, + total: ial1_total + ial2_total, + ial1_total:, + ial2_total:, + }.transform_keys(&:to_s), + ] end end end diff --git a/app/services/idv/phone_step.rb b/app/services/idv/phone_step.rb index a8dea4dd8c9..2265d1c8d19 100644 --- a/app/services/idv/phone_step.rb +++ b/app/services/idv/phone_step.rb @@ -12,7 +12,10 @@ def submit(step_params) throttle.increment! self.step_params = step_params - idv_session.previous_phone_step_params = step_params.slice(:phone, :otp_delivery_preference) + idv_session.previous_phone_step_params = step_params.slice( + :phone, :international_code, + :otp_delivery_preference + ) proof_address end diff --git a/app/services/idv/steps/in_person/verify_step.rb b/app/services/idv/steps/in_person/verify_step.rb index 43a80d1d2eb..a74454b3505 100644 --- a/app/services/idv/steps/in_person/verify_step.rb +++ b/app/services/idv/steps/in_person/verify_step.rb @@ -14,7 +14,6 @@ def self.analytics_submitted_event def call pii[:state_id_type] = 'drivers_license' unless invalid_state? - add_proofing_component enqueue_job end @@ -28,12 +27,6 @@ def extra_view_variables private - def add_proofing_component - ProofingComponent. - create_or_find_by(user: current_user). - update(document_check: Idp::Constants::Vendors::USPS) - end - def capture_secondary_id_enabled? current_user.establishing_in_person_enrollment.capture_secondary_id_enabled end diff --git a/app/services/out_of_band_session_accessor.rb b/app/services/out_of_band_session_accessor.rb index f06e3c9a472..dd2146ca100 100644 --- a/app/services/out_of_band_session_accessor.rb +++ b/app/services/out_of_band_session_accessor.rb @@ -28,7 +28,7 @@ def load_x509 end def destroy - session_store.send(:destroy_session_from_sid, session_uuid, drop: true) + session_store.send(:delete_session, {}, Rack::Session::SessionId.new(session_uuid), drop: true) end # @api private @@ -60,13 +60,20 @@ def put(data, expiration = 5.minutes) 'warden.user.user.session' => data.to_h, } - session_store. - send(:set_session, {}, session_uuid, session_data, expire_after: expiration.to_i) + session_store.send( + :write_session, + {}, + Rack::Session::SessionId.new(session_uuid), + session_data, + expire_after: expiration.to_i, + ) end # @return [Hash] def session_data - @session_data ||= session_store.send(:load_session_from_redis, session_uuid) || {} + @session_data ||= session_store.send( + :find_session, {}, Rack::Session::SessionId.new(session_uuid) + ).last || {} end def session_store diff --git a/app/services/outage_status.rb b/app/services/outage_status.rb index 290dbde4acc..bb7b532d279 100644 --- a/app/services/outage_status.rb +++ b/app/services/outage_status.rb @@ -1,12 +1,6 @@ class OutageStatus include ActionView::Helpers::TranslationHelper - def initialize(from: nil, from_idv: nil, sp: nil) - @from = from - @from_idv = from_idv - @sp = sp - end - IDV_VENDORS = %i[acuant lexisnexis_instant_verify lexisnexis_trueid].freeze PHONE_VENDORS = %i[sms voice].freeze ALL_VENDORS = (IDV_VENDORS + PHONE_VENDORS).freeze @@ -55,31 +49,15 @@ def phone_finder_outage? all_vendor_outage?([:lexisnexis_phone_finder]) end - def from_idv? - from_idv - end - # Returns an appropriate error message based upon the type of outage or what the user was doing # when they encountered the outage. # # @return [String, nil] the localized message. def outage_message if any_idv_vendor_outage? - if from_idv? - if sp - t('vendor_outage.blocked.idv.with_sp', service_provider: sp.friendly_name) - else - t('vendor_outage.blocked.idv.without_sp') - end - else - t('vendor_outage.blocked.idv.generic') - end + t('vendor_outage.blocked.idv.generic') elsif any_phone_vendor_outage? - if from_idv? - t('vendor_outage.blocked.phone.idv') - else - t('vendor_outage.blocked.phone.default') - end + t('vendor_outage.blocked.phone.default') end end @@ -94,11 +72,6 @@ def track_event(analytics) sms: IdentityConfig.store.vendor_status_sms, voice: IdentityConfig.store.vendor_status_voice, }, - redirect_from: from, ) end - - private - - attr_reader :from, :from_idv, :sp end diff --git a/app/services/pii/attributes.rb b/app/services/pii/attributes.rb index 53119c0949b..dbe40b20471 100644 --- a/app/services/pii/attributes.rb +++ b/app/services/pii/attributes.rb @@ -10,7 +10,11 @@ module Pii # The user's residential address :address1, :address2, :city, :state, :zipcode, :same_address_as_id, # The address on a user's state-issued ID, which may be different from their residential address - :state_id_address1, :state_id_address2, :state_id_city, :state_id_jurisdiction, :state_id_zipcode, # rubocop:disable Layout/LineLength + :state_id_address1, :state_id_address2, :state_id_city, :state_id_zipcode, + # the state that issued the id, which may be different than the state in the state id address + :state_id_jurisdiction, + # the state in the state id address, which may not be the state that issued the ID + :state_id_state, :ssn, :dob, :phone, *DEPRECATED_PII_ATTRIBUTES ) do diff --git a/app/services/store_sp_metadata_in_session.rb b/app/services/store_sp_metadata_in_session.rb index 9e573f286f3..507ac40724c 100644 --- a/app/services/store_sp_metadata_in_session.rb +++ b/app/services/store_sp_metadata_in_session.rb @@ -21,14 +21,6 @@ def ial_context @ial_context ||= IalContext.new(ial: sp_request.ial, service_provider: service_provider) end - def event_attributes - { - event: 'StoreSpMetadataInSession', - request_id_present: request_id.present?, - sp_request_class: sp_request.class.to_s, - }.to_json - end - def sp_request @sp_request ||= ServiceProviderRequestProxy.from_uuid(request_id) end diff --git a/app/services/usps_in_person_proofing/enrollment_helper.rb b/app/services/usps_in_person_proofing/enrollment_helper.rb index 1c7f09d77f7..b3fc7d1ab52 100644 --- a/app/services/usps_in_person_proofing/enrollment_helper.rb +++ b/app/services/usps_in_person_proofing/enrollment_helper.rb @@ -48,7 +48,7 @@ def create_usps_enrollment(enrollment, pii) # If we're using secondary ID capture (aka double address verification), # then send the state ID address to USPS. Otherwise send the residential address. - if enrollment.capture_secondary_id_enabled? && !pii[:same_address_as_id] + if enrollment.capture_secondary_id_enabled? && !enrollment.current_address_matches_id? pii = pii.except(*SECONDARY_ID_ADDRESS_MAP.values). transform_keys(SECONDARY_ID_ADDRESS_MAP) end @@ -98,7 +98,7 @@ def usps_proofer state_id_address1: :address1, state_id_address2: :address2, state_id_city: :city, - state_id_jurisdiction: :state, + state_id_state: :state, state_id_zipcode: :zipcode, }.freeze diff --git a/app/views/idv/in_person/state_id.html.erb b/app/views/idv/in_person/state_id.html.erb index ca27486a6e3..131a646e320 100644 --- a/app/views/idv/in_person/state_id.html.erb +++ b/app/views/idv/in_person/state_id.html.erb @@ -96,6 +96,21 @@ %> + <% if capture_secondary_id_enabled %> +
+ <%= render ValidatedFieldComponent.new( + name: :state_id_jurisdiction, + collection: us_states_territories, + form: f, + hint: t('in_person_proofing.form.state_id.state_id_jurisdiction_hint'), + label: t('in_person_proofing.form.state_id.state_id_jurisdiction'), + label_html: { class: 'usa-label' }, + prompt: t('in_person_proofing.form.state_id.state_id_jurisdiction_prompt'), + required: true, + selected: pii[:state_id_jurisdiction], + ) %> +
+ <% end %>
<%= render ValidatedFieldComponent.new( name: :state_id_number, @@ -110,6 +125,17 @@
<% if capture_secondary_id_enabled %> +

<%= t('in_person_proofing.headings.id_address') %>

+ <%= render ValidatedFieldComponent.new( + name: :state_id_state, + collection: us_states_territories, + form: f, + label: t('in_person_proofing.form.state_id.state_id_state'), + label_html: { class: 'usa-label' }, + prompt: t('in_person_proofing.form.state_id.state_id_state_prompt'), + required: true, + selected: pii[:state_id_state], + ) %> <%= render ValidatedFieldComponent.new( name: :state_id_address1, form: f, @@ -140,19 +166,21 @@ required: true, ) %> <% end %> -
- <%= render ValidatedFieldComponent.new( - name: :state_id_jurisdiction, - collection: us_states_territories, - form: f, - hint: t('in_person_proofing.form.state_id.state_id_jurisdiction_hint'), - label: t('in_person_proofing.form.state_id.state_id_jurisdiction'), - label_html: { class: 'usa-label' }, - prompt: t('in_person_proofing.form.state_id.state_id_jurisdiction_prompt'), - required: true, - selected: pii[:state_id_jurisdiction], - ) %> -
+ <% unless capture_secondary_id_enabled %> +
+ <%= render ValidatedFieldComponent.new( + name: :state_id_jurisdiction, + collection: us_states_territories, + form: f, + hint: t('in_person_proofing.form.state_id.state_id_state_hint'), + label: t('in_person_proofing.form.state_id.state_id_jurisdiction'), + label_html: { class: 'usa-label' }, + prompt: t('in_person_proofing.form.state_id.state_id_jurisdiction_prompt'), + required: true, + selected: pii[:state_id_jurisdiction], + ) %> +
+ <% end %> <% if capture_secondary_id_enabled %>
<%= render ValidatedFieldComponent.new( @@ -165,19 +193,19 @@ required: true, ) %>
- <%= render ValidatedFieldComponent.new( - as: :radio_buttons, - checked: pii[:same_address_as_id], - collection: [ - [t('in_person_proofing.form.state_id.same_address_as_id_yes'), true], - [t('in_person_proofing.form.state_id.same_address_as_id_no'), false], - ], - form: f, - label: t('in_person_proofing.form.state_id.same_address_as_id'), - name: :same_address_as_id, - required: true, - wrapper: :uswds_radio_buttons, - ) %> +

<%= t('in_person_proofing.form.state_id.same_address_as_id') %>

+ <%= render ValidatedFieldComponent.new( + as: :radio_buttons, + checked: pii[:same_address_as_id], + collection: [ + [t('in_person_proofing.form.state_id.same_address_as_id_yes'), true], + [t('in_person_proofing.form.state_id.same_address_as_id_no'), false], + ], + form: f, + name: :same_address_as_id, + required: true, + wrapper: :uswds_radio_buttons, + ) %> <% end %> <%= f.submit do %> diff --git a/app/views/idv/in_person/verify_info/new.html.erb b/app/views/idv/in_person/verify_info/new.html.erb new file mode 100644 index 00000000000..e69de29bb2d diff --git a/app/views/idv/in_person/verify_info/show.html.erb b/app/views/idv/in_person/verify_info/show.html.erb new file mode 100644 index 00000000000..fd5c71f4ebb --- /dev/null +++ b/app/views/idv/in_person/verify_info/show.html.erb @@ -0,0 +1,153 @@ +<%# +locals: + @step_indicator_steps - the correct Idv::Flows variable for this flow + @pii - user's information + @had_barcode_read_failure - show warning if there's a barcode read error +%> + +<% content_for(:pre_flash_content) do %> + <%= render StepIndicatorComponent.new( + steps: @step_indicator_steps, + current_step: :verify_info, + locale_scope: 'idv', + class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', + ) %> +<% end %> + +
+ +
+ +<% if @had_barcode_read_failure %> + <%= render AlertComponent.new( + type: :warning, + class: 'margin-bottom-4', + text_tag: 'div', + ) do %> + <%= t( + 'doc_auth.headings.capture_scan_warning_html', + link: render( + FormLinkComponent.new( + href: idv_doc_auth_step_path(step: :redo_document_capture), + method: :put, + ).with_content(t('doc_auth.headings.capture_scan_warning_link')), + ), + ) %> + <% end %> +<% end %> + +<% title t('titles.idv.verify_info') %> + +<%= render PageHeadingComponent.new.with_content(t('headings.verify')) %> +
+
+
+
+
<%= t('idv.form.first_name') %>:
+
<%= @pii[:first_name] %>
+
+
+
<%= t('idv.form.last_name') %>:
+
<%= @pii[:last_name] %>
+
+
+
<%= t('idv.form.dob') %>:
+
+ <%= I18n.l(Date.parse(@pii[:dob]), format: I18n.t('time.formats.event_date')) %> +
+
+
+
<%= t('idv.form.id_number') %>:
+
<%= @pii[:state_id_number] %>
+
+
+
+ <%= button_to( + idv_in_person_step_url(step: :redo_state_id), + method: :put, + class: 'usa-button usa-button--unstyled', + 'aria-label': t('idv.buttons.change_state_id_label'), + ) { t('idv.buttons.change_label') } %> +
+
+
+
+
+
<%= t('idv.form.address1') %>:
+
<%= @pii[:address1] %>
+
+
+
<%= t('idv.form.address2') %>:
+
<%= @pii[:address2].presence %>
+
+
+
<%= t('idv.form.city') %>:
+
<%= @pii[:city] %>
+
+
+
<%= t('idv.form.state') %>:
+
<%= @pii[:state] %>
+
+
+
<%= t('idv.form.zipcode') %>:
+
<%= @pii[:zipcode] %>
+
+
+
+ <%= button_to( + idv_in_person_step_url(step: :redo_address), + method: :put, + class: 'usa-button usa-button--unstyled', + 'aria-label': t('idv.buttons.change_address_label'), + ) { t('idv.buttons.change_label') } %> +
+
+
+
+ <%= t('idv.form.ssn') %>: + <%= render( + 'shared/masked_text', + text: SsnFormatter.format(@pii[:ssn]), + masked_text: SsnFormatter.format_masked(@pii[:ssn]), + accessible_masked_text: t( + 'idv.accessible_labels.masked_ssn', + first_number: @pii[:ssn][0], + last_number: @pii[:ssn][-1], + ), + toggle_label: t('forms.ssn.show'), + ) %> +
+
+ <%= button_to( + idv_in_person_step_url(step: :redo_ssn), + method: :put, + class: 'usa-button usa-button--unstyled', + 'aria-label': t('idv.buttons.change_ssn_label'), + ) { t('idv.buttons.change_label') } %> +
+
+
+ <%= render SpinnerButtonComponent.new( + action: ->(**tag_options, &block) do + button_to(idv_in_person_verify_info_path, **tag_options, &block) + end, + big: true, + wide: true, + action_message: t('idv.messages.verifying'), + method: :put, + form: { + class: 'button_to', + data: { + form_steps_wait: '', + error_message: t('idv.failure.exceptions.internal_error'), + alert_target: '#form-steps-wait-alert', + wait_step_path: idv_in_person_verify_info_path, + poll_interval_ms: IdentityConfig.store.poll_rate_for_verify_in_seconds * 1000, + }, + }, + ).with_content(t('forms.buttons.continue')) %> +
+
+ +<% javascript_packs_tag_once 'form-steps-wait' %> +<%= render 'idv/doc_auth/cancel', step: 'verify' %> diff --git a/app/views/idv/phone_errors/_warning.html.erb b/app/views/idv/phone_errors/_warning.html.erb index 815aa1afcd5..13ff634a3c5 100644 --- a/app/views/idv/phone_errors/_warning.html.erb +++ b/app/views/idv/phone_errors/_warning.html.erb @@ -3,16 +3,18 @@ yields: Warning text to show. locals: * contact_support_option: Whether to show "Contact Support" option. Defaults to false. * name: Slug describing warning screen, for use in analytics. +* heading: Heading text, defaults to idv.failure.phone.heading %> <%= render( 'idv/shared/error', type: :warning, title: t('titles.failure.phone_verification'), - heading: t('idv.failure.phone.heading'), + heading: local_assigns.fetch(:heading, t('idv.failure.phone.heading')), action: { text: t('idv.failure.button.warning'), url: idv_phone_path, }, + current_step: :verify_phone_or_address, options: [ local_assigns[:contact_support_option] && { url: MarketingSite.contact_url, diff --git a/app/views/idv/phone_errors/failure.html.erb b/app/views/idv/phone_errors/failure.html.erb index adde1cf968d..43e8895946a 100644 --- a/app/views/idv/phone_errors/failure.html.erb +++ b/app/views/idv/phone_errors/failure.html.erb @@ -1,12 +1,9 @@ <%= render( 'idv/shared/error', title: t('titles.failure.phone_verification'), - heading: t('idv.failure.phone.heading'), + heading: t('idv.failure.phone.rate_limited.heading'), + current_step: :verify_phone_or_address, options: [ - @gpo_letter_available && { - text: t('idv.troubleshooting.options.verify_by_mail'), - url: idv_gpo_path, - }, decorated_session.sp_name && { url: return_to_sp_failure_to_proof_path(step: 'phone', location: request.params[:action]), text: t('idv.troubleshooting.options.get_help_at_sp', sp_name: decorated_session.sp_name), @@ -21,12 +18,24 @@ ) do %>

<%= t( - 'idv.failure.phone.fail_html', - timeout: distance_of_time_in_words( + 'idv.failure.phone.rate_limited.body', + time_left: distance_of_time_in_words( Time.zone.now, [@expires_at, Time.zone.now].compact.max, except: :seconds, ), ) %>

+ <% if @gpo_letter_available %> +

+ <%= t('idv.failure.phone.rate_limited.gpo.prompt') %> +

+
+ <%= render ButtonComponent.new( + action: ->(**tag_options, &block) { link_to idv_gpo_path, **tag_options, &block }, + big: true, + wide: true, + ).with_content(t('idv.failure.phone.rate_limited.gpo.button')) %> +
+ <% end %> <% end %> diff --git a/app/views/idv/phone_errors/warning.html.erb b/app/views/idv/phone_errors/warning.html.erb index 0add6f83ef4..9a2005bd2fa 100644 --- a/app/views/idv/phone_errors/warning.html.erb +++ b/app/views/idv/phone_errors/warning.html.erb @@ -1,4 +1,69 @@ -<%= render('idv/phone_errors/warning') do %> -

<%= t('idv.failure.phone.warning') %>

-

<%= t('idv.failure.attempts', count: @remaining_attempts) %>

-<% end %> +<%= render( + 'idv/shared/error', + type: :warning, + title: t('titles.failure.phone_verification'), + heading: t('idv.failure.phone.warning.heading'), + current_step: :verify_phone_or_address, + options: [ + decorated_session.sp_name && { + url: return_to_sp_failure_to_proof_path( + step: 'phone', + location: local_assigns.fetch(:name, 'warning'), + ), + text: t('idv.troubleshooting.options.get_help_at_sp', sp_name: decorated_session.sp_name), + new_tab: true, + }, + ].select(&:present?), + ) do %> + +

+ <%= t('idv.failure.phone.warning.you_entered') %> + <%= PhoneFormatter.format(@phone, country_code: @country_code) %> +

+ +

+ <%= t('idv.failure.phone.warning.next_steps_html') %> + <%= new_window_link_to( + t('idv.failure.phone.warning.learn_more_link'), + help_center_redirect_path( + category: 'verify-your-identity', + article: 'phone-number', + flow: :idv, + step: :phone, + location: 'learn_more', + ), + ) %> +

+ +

+ <%= t('idv.failure.phone.warning.attempts', count: @remaining_attempts) %> +

+ +
+ <%= render ButtonComponent.new( + action: ->(**tag_options, &block) { link_to idv_phone_path, **tag_options, &block }, + big: true, + wide: true, + ).with_content(t('idv.failure.phone.warning.try_again_button')) %> +
+ + <% if @gpo_letter_available %> +
+ +

<%= t('idv.failure.phone.warning.gpo.heading') %>

+ +

+ <%= t('idv.failure.phone.warning.gpo.explanation') %> + <%= t('idv.failure.phone.warning.gpo.how_long_it_takes') %> +

+ +
+ <%= render ButtonComponent.new( + action: ->(**tag_options, &block) { link_to idv_gpo_path, **tag_options, &block }, + big: true, + wide: true, + outline: true, + ).with_content(t('idv.failure.phone.warning.gpo.button')) %> +
+ <% end %> + <% end %> diff --git a/app/views/idv/shared/_error.html.erb b/app/views/idv/shared/_error.html.erb index b6b0cd71640..f9ca9393bb1 100644 --- a/app/views/idv/shared/_error.html.erb +++ b/app/views/idv/shared/_error.html.erb @@ -6,6 +6,7 @@ locals: * title: Optional custom page title, defaulting to the heading. * action: Optional hash of `text`, `url`, optional `method` of a primary action link. * action_secondary: Optional hash of `text`, `url`, optional `method` of a secondary action link. +* current_step: Optionally identify the current step of the IdV flow. If provided, the step indicator will be rendered. * options: Array of troubleshooting options. %> <% if local_assigns.fetch(:type, :error) == :error @@ -15,7 +16,20 @@ else icon_name = :warning troubleshooting_heading = t('components.troubleshooting_options.default_heading') end %> + <% title local_assigns.fetch(:title, heading) %> + +<% if local_assigns[:current_step] and defined?(step_indicator_steps) %> + <% content_for(:pre_flash_content) do %> + <%= render StepIndicatorComponent.new( + steps: step_indicator_steps, + current_step: local_assigns[:current_step], + locale_scope: 'idv', + class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', + ) %> + <% end %> +<% end %> + <%= render AlertIconComponent.new(icon_name: icon_name, class: 'display-block margin-bottom-4') %> <%= render PageHeadingComponent.new.with_content(heading) %> diff --git a/app/views/idv/shared/_verify.html.erb b/app/views/idv/shared/_verify.html.erb index 5f20a1d332f..7e9ee3d3501 100644 --- a/app/views/idv/shared/_verify.html.erb +++ b/app/views/idv/shared/_verify.html.erb @@ -29,6 +29,12 @@ locals: <%= I18n.l(Date.parse(pii[:dob]), format: I18n.t('time.formats.event_date')) %> + <% if !remote_identity_proofing && capture_secondary_id_enabled %> +
+
<%= t('idv.form.issuing_state') %>:
+
<%= pii[:state_id_jurisdiction] %>
+
+ <% end %> <% if !remote_identity_proofing %>
<%= t('idv.form.id_number') %>:
@@ -36,7 +42,7 @@ locals:
<% end %> <% if !remote_identity_proofing && capture_secondary_id_enabled %> -
+
<%= t('idv.form.address1') %>:
<%= pii[:state_id_address1] %>
@@ -50,7 +56,7 @@ locals:
<%= t('idv.form.state') %>:
-
<%= pii[:state_id_jurisdiction] %>
+
<%= pii[:state_id_state] %>
<%= t('idv.form.zipcode') %>:
diff --git a/app/views/idv/unavailable/show.html.erb b/app/views/idv/unavailable/show.html.erb new file mode 100644 index 00000000000..6a2f8c8bade --- /dev/null +++ b/app/views/idv/unavailable/show.html.erb @@ -0,0 +1,42 @@ +<% title t('idv.titles.unavailable') %> + +<%= render StatusPageComponent.new(status: :error) do |c| %> + + <% c.header { t('idv.titles.unavailable') } %> + +

+ <% if decorated_session.sp_name.present? %> + <%= t('idv.unavailable.idv_explanation.with_sp_html', sp: decorated_session.sp_name) %> + <% else %> + <%= t('idv.unavailable.idv_explanation.without_sp') %> + <% end %> +

+ +

+ <%= t('idv.unavailable.technical_difficulties') %> +

+ +

+ <%= t( + 'idv.unavailable.next_steps_html', + app_name: APP_NAME, + status_page_link: new_window_link_to( + t('idv.unavailable.status_page_link'), + StatusPage.base_url, + ), + ) %> +

+ + <% c.action_button( + action: ->(**tag_options, &block) do + link_to( + return_to_sp_failure_to_proof_path(location: :unavailable), + **tag_options, + &block + ) + end, + big: true, + wide: true, + ).with_content(t('idv.unavailable.exit_button', app_name: APP_NAME)) %> + +<% end %> \ No newline at end of file diff --git a/app/views/idv/verify_info/show.html.erb b/app/views/idv/verify_info/show.html.erb index 48843b1f3e7..40a4bfa6c29 100644 --- a/app/views/idv/verify_info/show.html.erb +++ b/app/views/idv/verify_info/show.html.erb @@ -1,10 +1,8 @@ <%# locals: - @verify_info_submit_path - either idv_verify_info_path or idv_in_person_verify_info_path @step_indicator_steps - the correct Idv::Flows variable for this flow @pii - user's information @had_barcode_read_failure - show warning if there's a barcode read error - @in_person_proofing - true for in person proofing %> <% content_for(:pre_flash_content) do %> @@ -58,23 +56,7 @@ locals: <%= I18n.l(Date.parse(@pii[:dob]), format: I18n.t('time.formats.event_date')) %>
- <% if @in_person_proofing %> -
-
<%= t('idv.form.id_number') %>:
-
<%= @pii[:state_id_number] %>
-
- <% end %> - <% if @in_person_proofing %> -
- <%= button_to( - idv_in_person_step_url(step: :redo_state_id), - method: :put, - class: 'usa-button usa-button--unstyled', - 'aria-label': t('idv.buttons.change_state_id_label'), - ) { t('idv.buttons.change_label') } %> -
- <% end %>
@@ -134,7 +116,7 @@ locals:
<%= render SpinnerButtonComponent.new( action: ->(**tag_options, &block) do - button_to(@verify_info_submit_path, **tag_options, &block) + button_to(idv_verify_info_path, **tag_options, &block) end, big: true, wide: true, @@ -146,7 +128,7 @@ locals: form_steps_wait: '', error_message: t('idv.failure.exceptions.internal_error'), alert_target: '#form-steps-wait-alert', - wait_step_path: @verify_info_submit_path, + wait_step_path: idv_verify_info_path, poll_interval_ms: IdentityConfig.store.poll_rate_for_verify_in_seconds * 1000, }, }, diff --git a/config/application.rb b/config/application.rb index e21996ebbcf..cb186ffee26 100644 --- a/config/application.rb +++ b/config/application.rb @@ -54,8 +54,6 @@ class Application < Rails::Application end config.load_defaults '7.0' - # Delete after deploying once - config.active_support.cache_format_version = 6.1 config.active_record.belongs_to_required_by_default = false config.active_record.legacy_connection_handling = false config.assets.unknown_asset_fallback = true diff --git a/config/application.yml.default b/config/application.yml.default index 1562ace5eba..dc0d86c0267 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -120,6 +120,7 @@ hide_phone_mfa_signup: false identity_pki_disabled: false identity_pki_local_dev: false idv_attempt_window_in_hours: 6 +idv_available: true idv_contact_phone_number: (844) 555-5555 idv_max_attempts: 5 idv_min_age_years: 13 @@ -398,7 +399,7 @@ development: recurring_jobs_disabled_names: "[]" s3_report_bucket_prefix: '' s3_report_public_bucket_prefix: '' - saml_endpoint_configs: '[{"suffix":"2021","secret_key_passphrase":"trust-but-verify"},{"suffix":"2022","secret_key_passphrase":"trust-but-verify"}]' + saml_endpoint_configs: '[{"suffix":"2022","secret_key_passphrase":"trust-but-verify"},{"suffix":"2023","secret_key_passphrase":"trust-but-verify"}]' scrypt_cost: 10000$8$1$ secret_key_base: development_secret_key_base session_encryption_key: 27bad3c25711099429c1afdfd1890910f3b59f5a4faec1c85e945cb8b02b02f261ba501d99cfbb4fab394e0102de6fecf8ffe260f322f610db3e96b2a775c120 @@ -567,7 +568,7 @@ test: reset_password_email_window_in_minutes: 80 s3_report_bucket_prefix: '' s3_report_public_bucket_prefix: '' - saml_endpoint_configs: '[{"suffix":"2022","secret_key_passphrase":"trust-but-verify"}]' + saml_endpoint_configs: '[{"suffix":"2023","secret_key_passphrase":"trust-but-verify"}]' saml_internal_post: true scrypt_cost: 800$8$1$ secret_key_base: test_secret_key_base diff --git a/config/artifacts.example/local/saml2023.crt b/config/artifacts.example/local/saml2023.crt deleted file mode 120000 index 3adf05b96cb..00000000000 --- a/config/artifacts.example/local/saml2023.crt +++ /dev/null @@ -1 +0,0 @@ -saml2022.crt \ No newline at end of file diff --git a/config/artifacts.example/local/saml2023.crt b/config/artifacts.example/local/saml2023.crt new file mode 100644 index 00000000000..914a417e994 --- /dev/null +++ b/config/artifacts.example/local/saml2023.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDajCCAlICCQCbZpJCM572hTANBgkqhkiG9w0BAQsFADB3MQswCQYDVQQGEwJV +UzEdMBsGA1UECAwURGlzdHJpY3Qgb2YgQ29sdW1iaWExEzARBgNVBAcMCldhc2hp +bmd0b24xDDAKBgNVBAoMA0dTQTESMBAGA1UECwwJTG9naW4uZ292MRIwEAYDVQQD +DAlsb2dpbi5nb3YwHhcNMjMwNDA0MTYwNzIxWhcNMjQwNDAyMTYwNzIxWjB3MQsw +CQYDVQQGEwJVUzEdMBsGA1UECAwURGlzdHJpY3Qgb2YgQ29sdW1iaWExEzARBgNV +BAcMCldhc2hpbmd0b24xDDAKBgNVBAoMA0dTQTESMBAGA1UECwwJTG9naW4uZ292 +MRIwEAYDVQQDDAlsb2dpbi5nb3YwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCdToDm3/j0j0PMjca8bc7H0H3FNSTW4l6hpUSywkC/kg2fZ5W6f0hIYYID +TbDYAkpeIiKKE/FDI3TlaQT9+LLe6AbkelLmteS+wMehCPtaBPeRfHKaRNQKsSTk +c5JAf4OWaZKj+F3Fu0e5+dJ2nuYcT2VV7DLoG3KKTw+pcHuXCQZfrPbquyyNbKvo +K4ELVIueQQ5F3EiahP3XchGw+H5FCH5QJPVl57WaCB2gLM8kueELKIzta7roIYHf +GEhdaC71ZYCjGRvsKtAqomNdL2Je67E56dEwJ1fWS242PkSvQTH5vtkYzelE2H9m +V+sPf5lLfc599iLZoTemEe5p6NydAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAH88 +Yl+KbT3NPjrXH7SITWr1wOIemJ8b2/vukz7aS9TiTJnlw6IzsLnD+tiJa1q5CO23 +3/NCaa6piocbD1fC/H7PB6lXu+0ypMwpaStTThpxbpQ6bMUklxKKFyuaX5RpNZn4 +YicYGEnCr7h70+R/01ztgYNOzNdgM6MjHMvEnb8KVkuckuCE1JUoX+LxaE9cxkxX +Auwdct14efBFuyB2HgvWUvqvjN9NDhfS6BG5FgTZWpWJnn7xmjUNUfq1VC4XHQsv +mqoPiDhR1GwB191ZVz7Rq00yysfr7tSUJeWp//5GPZRjSZsrs1wtO6x/tFjngELl +d0/LPNS3OWvaMvvGzgc= +-----END CERTIFICATE----- diff --git a/config/artifacts.example/local/saml2023.key.enc b/config/artifacts.example/local/saml2023.key.enc deleted file mode 120000 index 35bacae1de4..00000000000 --- a/config/artifacts.example/local/saml2023.key.enc +++ /dev/null @@ -1 +0,0 @@ -saml2022.key.enc \ No newline at end of file diff --git a/config/artifacts.example/local/saml2023.key.enc b/config/artifacts.example/local/saml2023.key.enc new file mode 100644 index 00000000000..c1c1a03fa5d --- /dev/null +++ b/config/artifacts.example/local/saml2023.key.enc @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIfgN2KJrydvECAggA +MB0GCWCGSAFlAwQBKgQQEF8wtPY1ps4bJfQ4sV0xeQSCBND598BOsn9cAgqBGUEE +yQgCp+DIpDKFmgwXOiFjjuY1H3vsAFh0lhOoWN2z2UsAWUq8RwWs41UNSajgUllq +wPP3dm+U2BG661AmZEj5+fJ6ckCLX+BZHcv2bjx7cRF8oMv3Z1wlmTvxyARcFlct +b5Rxjl+moDwuBGFUaCg80hL2NZmUSuf/GZ5bj5yHZqGdc/KAXRts6knqLfsBxhrh +uECYUaz11NRN+JCNg8TcQSUJs01QVrhS7MrNhr1WGIwdIYg0AsqHqluzKr4nzjqG +u8vfRV7oraUhNDKrfXfxjGcyy/o4zYnuJO3zBRWPV4Ueesf3efGY3bNyZzoY2BrD +ZlpQwHf7NmANZqHnCAH9dDrk3mcNkfPEnSs/oguhIk05ZHMaZeGR+bIJd1LjxjLY +KOhgw9u+I4WR35GsZRFArwUnHfvAcLTwBbsChMk7ykj16F/rdIknMWiyZX3p31Cm +ZW/tB5j4lm9caA9iPn/d3S/H7O3zG3SSuwQvrwQguImqEegMq2FA6MLT+66R+DU/ +AB/M8WgwIhaLWr136GhGBjJO4Tm21DrNjHzS8NYWcXL8PWdDgagwbTGAL6jLLulr +iCrkEsQoNzX11WiwYgmhrPLKVqophHK4v3dzuY+naMV5GekqhPA+8IfWZfvmizb7 +LVoxb6TKBI0U3p31lhRI9car+Yxa7z5ZSAl0n03TCeZOYvUmKAwj81E23g1XC3Fx ++xB+nrDWQQjvD+ZRXQxqUg58o0qitM9tKsIkh2Qj4IRpATTyTyNO40seGni8AWsU +ftsll8OVWEdHlnOGLNjSPC/uVMYSa8YOcv+xIqErty2Q40yrOsXufX0ompzONNZH +rUbifoY3T8En88m7wCDBQAw38pUdgPniL0VyADdvkc4To5pjkK7B4g7fD+WbjdrD +V7UhU+4wxZkSK9ijaq/4Cj/ZIg5m29qOoCtI/vn2A/DnhLJmomQ8B21xgtUsa/pM +Pi1Z4rz2OLEND1EPuJSm/xijxVGUgYpkOYHoRQmvbpPst9FvXPIXcBdpahbVvqOq +Iv8LcKatTKqTjxyXoOxxUWQ16MYXaOSk8sEbDYqp/YK2N9ItIPiHiYio/Wt+uQM8 +/VbyZGY+e0O9mAGtoWLDuqCziH5HHXjH7sX0mJmrVCc8V7eKewEEYT6jCjvOMG+V +tABCJQXoaOV8Tk5f3rMDVYg+DQaqFfuvOEahj0CLm4xLuEK9mGvNz7HjxgPjRfS1 +CFn93oBKnhJbzeEkNEHWw2sG1/twiOjhSkMs5CbdcpAjm6wNoKE3/e23HbUuFGos +yOb/2mm5oAr/EjBCUSilyNSkIuUTzIKnootLJ4bxHmTHFlpJlYvFBKWT7RIRT21g +LErRAgUHF/f93yNjgEbdzf8lzKfYWBnZK1E2RGbVay3W1OtQQ7Om01CbKd0THt9y +4bwD/rS29+xa4NVImMXmq/aftLLoedaY9TWHz2FOInXhms9vw0wsehmc1aoQ1yrl +DVx+T7raO6YJ8MK385ryjupsZd4J5dYcvHjlkpnZOyvVyzfdNqHvVhtfd765d5rw +GyX2UKPByjECQskxKjeqadjZ8zaAecW/4ujg0wcmdX7l4lfXcdy6+0WiPr3qBwQE +hrcBC92oNEzyorgjdcMEz2RATw== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index 713df6f1ae8..26a20481647 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -9,6 +9,9 @@ # cookie expires with browser close expire_after: nil, + write_fallback: true, + read_fallback: true, + # Redis expires session after N minutes ttl: IdentityConfig.store.session_timeout_in_minutes.minutes, diff --git a/config/locales/idv/en.yml b/config/locales/idv/en.yml index 824e97c1e6e..7a2cb739cbf 100644 --- a/config/locales/idv/en.yml +++ b/config/locales/idv/en.yml @@ -76,14 +76,36 @@ en: back later. text_html: Please try again. If you keep getting these errors, %{link}. phone: - fail_html: 'Please try again in %{timeout}. For your security, - we limit the number of times you can attempt to verify your phone - number online.' heading: We could not match this phone number to other records jobfail: Something went wrong and we cannot process your request at this time. Please try again. + rate_limited: + body: For security reasons, we limit the number of times you can attempt to + verify your phone number online. You will need to wait %{time_left} + and start over before trying to verify by phone again. + gpo: + button: Verify by mail + prompt: Continue now by verifying by mail, which typically takes 3 - 7 business + days. + heading: 'We couldn’t verify your identity by phone' timeout: Our request to verify your information timed out. Please try again. - warning: Please check the information you entered and try again. + warning: + attempts: + one: For security reasons, you have one attempt remaining. + other: For security reasons, you have %{count} attempts remaining. + gpo: + button: Verify by mail + explanation: If you don’t have another phone number to try, verify by mail + instead. + heading: Verify by mail + how_long_it_takes: This typically takes 3 - 7 business days. + heading: We couldn’t match you to this number + learn_more_link: 'Learn more about what phone number to use' + next_steps_html: 'Please try again with another number that you + use often and have used for a long time. This can be a work or home + number.' + try_again_button: 'Try another number' + you_entered: 'You entered:' sessions: exception: There was an internal error processing your request. fail_html: 'Please try again in %{timeout}. For your security, @@ -121,6 +143,7 @@ en: dob: Date of birth first_name: First name id_number: ID number + issuing_state: Issuing state last_name: Last name password: Password ssn: Social Security number @@ -203,6 +226,7 @@ en: session: phone: Enter your phone number review: Re-enter your %{app_name} password to protect your data + unavailable: 'We are working to resolve an error' troubleshooting: headings: missing_required_items: Are you missing one of these items? @@ -219,6 +243,17 @@ en: learn_more_verify_in_person: Learn more about verifying in person supported_documents: See a list of accepted state-issued IDs verify_by_mail: Verify your address by mail instead + unavailable: + exit_button: 'Exit %{app_name}' + idv_explanation: + with_sp_html: '%{sp} needs to make sure you are you — not + someone pretending to be you.' + without_sp: 'The agency that you are trying to access needs to make sure you are + you — not someone pretending to be you.' + next_steps_html: '%{status_page_link} or exit %{app_name} and try again later.' + status_page_link: 'Get updates on our status page' + technical_difficulties: Unfortunately, we are having technical difficulties and + cannot verify your identity at this time. welcome: no_js_header: You must enable JavaScript to verify your identity. no_js_intro: '%{sp_name} needs you to verify your identity. You need to enable diff --git a/config/locales/idv/es.yml b/config/locales/idv/es.yml index b4852c5381e..75d4453a739 100644 --- a/config/locales/idv/es.yml +++ b/config/locales/idv/es.yml @@ -81,16 +81,39 @@ es: continúa, regrese más tarde. text_html: Inténtalo de nuevo. Si sigues recibiendo estos errores, %{link}. phone: - fail_html: 'Por favor, inténtelo de nuevo en %{timeout}. Por su - seguridad, limitamos el número de veces que puede intentar verificar - su número de teléfono en línea.' heading: No pudimos encontrar coincidencias entre este número de teléfono y otros registros jobfail: Algo ha fallado y no podemos procesar tu solicitud en este momento. Vuelve a intentarlo. + rate_limited: + body: Por motivos de seguridad, se limita el número de veces que puede intentar + verificar su número de teléfono por Internet. Tendrás que esperar + %{time_left} y volver a empezar antes de volver a intentar la + verificación por teléfono. + gpo: + button: Verificar por correo + prompt: Continúa ahora con la verificación por correo, que suele tardar entre 3 + y 7 días laborables. + heading: 'No hemos podido verificar su identidad por teléfono' timeout: Nuestra solicitud para verificar tu información ha caducado. Vuelve a intentarlo. - warning: Por favor, verifique la información que ingresó y vuelva a intentarlo. + warning: + attempts: + one: Por razones de seguridad, dispone de un solo intento. + other: Por razones de seguridad, le quedan %{count} intentos. + gpo: + button: Verificar por correo + explanation: Si no dispones de otro número de teléfono para intentarlo, + verifícalo por correo. + heading: Verificar por correo + how_long_it_takes: Suele tardar entre 3 y 7 días laborables. + heading: No pudimos asociarlo a este número + learn_more_link: 'Más información sobre qué número de teléfono usar' + next_steps_html: 'Vuelva a intentarlo con otro número que + utilice a menudo y desde hace tiempo. Puede ser un número del + trabajo o particular.' + try_again_button: 'Intente con otro número' + you_entered: 'Ud. entregó:' sessions: exception: Hubo un error interno al procesar su solicitud. fail_html: 'Por favor, inténtelo de nuevo en %{timeout}. Por su @@ -130,6 +153,7 @@ es: dob: Fecha de nacimiento first_name: Nombre de pila id_number: Número de cédula + issuing_state: Estado emisor last_name: Apellido password: Contraseña ssn: Número de seguridad social @@ -217,6 +241,7 @@ es: session: phone: Introduzca su número de teléfono review: Vuelve a ingresar tu contraseña de %{app_name} para encriptar tus datos + unavailable: Estamos trabajando para resolver un error troubleshooting: headings: missing_required_items: '¿Le falta alguno de estos puntos?' @@ -235,6 +260,18 @@ es: supported_documents: Vea la lista de documentos de identidad emitidos por el estado que son aceptados verify_by_mail: Verifique su dirección por correo + unavailable: + exit_button: 'Salir de %{app_name}' + idv_explanation: + with_sp_html: '%{sp} necesita asegurarse de que es usted + realmente y no alguien que se hace pasar por usted.' + without_sp: 'La agencia a la que está intentando acceder debe asegurarse de que + usted sea quien dice ser, y no alguien que se hace pasar por usted.' + next_steps_html: '%{status_page_link} o salga de %{app_name} y vuelva a + intentarlo más tarde.' + status_page_link: 'Consulte las actualizaciones en nuestra página de estado' + technical_difficulties: Lamentablemente, debido a problemas técnicos por nuestra + parte, tal vez no podamos verificar su identidad en estos momentos. welcome: no_js_header: Debe habilitar JavaScript para verificar su identidad. no_js_intro: '%{sp_name} requiere que usted verifique su identidad. Debe diff --git a/config/locales/idv/fr.yml b/config/locales/idv/fr.yml index 87b78d0702e..e31d216c680 100644 --- a/config/locales/idv/fr.yml +++ b/config/locales/idv/fr.yml @@ -85,16 +85,39 @@ fr: problème persiste, revenez plus tard. text_html: Veuillez réessayer. Si vous continuez à recevoir ces erreurs, %{link} phone: - fail_html: 'Veuillez réessayer dans %{timeout}. Pour votre - sécurité, nous limitons le nombre de fois où vous pouvez tenter de - vérifier votre numéro de téléphone en ligne.' heading: Nous n’avons pas pu faire correspondre ce numéro de téléphone à d’autres enregistrements jobfail: Un problème s’est produit et nous ne pouvons pas traiter votre demande pour le moment. Veuillez réessayer. + rate_limited: + body: Pour des raisons de sécurité, nous limitons le nombre de tentatives de + vérification de votre numéro de téléphone en ligne. Vous devrez + attendre %{time_left} et recommencer avant d’essayer à nouveau de + vérifier votre identité par téléphone. + gpo: + button: Vérifier par courrier + prompt: Continuez maintenant en vérifiant par courrier, ce qui prend + généralement de 3 à 7 jours ouvrables. + heading: Nous n’avons pas pu vérifier votre identité par téléphone timeout: Notre demande de vérification de vos renseignements a expiré. Veuillez réessayer. - warning: Veuillez vérifier les informations que vous avez saisies et réessayer. + warning: + attempts: + one: Pour des raisons de sécurité, il vous reste une tentative. + other: Pour des raisons de sécurité, il vous reste %{count} tentatives. + gpo: + button: Vérifier par courrier + explanation: Si vous n’avez pas d’autre numéro de téléphone à essayer, vérifiez + plutôt par courrier. + heading: Vérifier par courrier + how_long_it_takes: Cette procédure prend typiquement 3 à 7 jours ouvrables. + heading: Nous n’avons pas pu vous associer à ce numéro + learn_more_link: 'Apprenez-en plus sur quel numéro de téléphone utiliser' + next_steps_html: 'Veuillez réessayer avec un autre numéro que + vous utilisez souvent et depuis longtemps. Il peut s’agir d’un + numéro professionnel ou personnel.' + try_again_button: 'Essayez un autre numéro' + you_entered: 'Tu as soumis:' sessions: exception: Une erreur interne s’est produite lors du traitement de votre demande. fail_html: 'Veuillez réessayer dans %{timeout}. Pour votre @@ -135,6 +158,7 @@ fr: dob: Date de naissance first_name: Prénom id_number: Numéro d’identification + issuing_state: État émetteur last_name: Nom de famille password: Mot de passe ssn: Numéro de sécurité sociale @@ -231,6 +255,7 @@ fr: session: phone: Entrez votre numéro de téléphone review: Entrez à nouveau votre mot de passe %{app_name} pour crypter vos données + unavailable: Nous travaillons à la résolution d’une erreur troubleshooting: headings: missing_required_items: Est-ce qu’il vous manque un de ces éléments? @@ -249,6 +274,19 @@ fr: learn_more_verify_in_person: En savoir plus sur la vérification en personne supported_documents: Voir la liste des pièces d’identité acceptées et délivrées par l’État verify_by_mail: Vérifiez plutôt votre adresse par courrier + unavailable: + exit_button: 'Quitter %{app_name}' + idv_explanation: + with_sp_html: '%{sp} doit s’assurer que c’est bien vous — et + non quelqu’un qui se fait passer pour vous.' + without_sp: 'L’agence à laquelle vous essayez d’accéder doit s’assurer qu’il + s’agit bien de vous, et non de quelqu’un qui se fait passer pour + vous.' + next_steps_html: '%{status_page_link} ou quittez le site %{app_name} et + réessayez plus tard.' + status_page_link: 'Obtenez des mises à jour sur notre page de statut' + technical_difficulties: Malheureusement, nous rencontrons des difficultés + techniques et ne pouvons pas vérifier votre identité pour le moment. welcome: no_js_header: Vous devez activer JavaScript pour vérifier votre identité. no_js_intro: '%{sp_name} a besoin de vous pour vérifier votre identité. Vous diff --git a/config/locales/in_person_proofing/en.yml b/config/locales/in_person_proofing/en.yml index 47a25a10932..ba75289e7e1 100644 --- a/config/locales/in_person_proofing/en.yml +++ b/config/locales/in_person_proofing/en.yml @@ -91,8 +91,8 @@ en: same_address_choice_yes: This address is on my state-issued ID state_prompt: '- Select -' state_id: - address1: Address - address2: Address line 2 (optional) + address1: Address line 1 + address2: Address line 2 city: City date_hint: day: 'Example: 28' @@ -111,20 +111,24 @@ en: missing_month_day_year: Enter a date of birth range_min_age: You must be over 13 years of age to use %{app_name} range_overflow: Enter a date that is in the past - same_address_as_id: Is your current residential address listed on your state-issued ID? - same_address_as_id_no: No, my current residential address is not listed on my state-issued ID - same_address_as_id_yes: Yes, my current residential address is listed on my state-issued ID - state_id_jurisdiction: State - state_id_jurisdiction_hint: Select the state shown on your ID + same_address_as_id: Do you currently live at the address listed on your state-issued ID? + same_address_as_id_no: No, I live at a different address + same_address_as_id_yes: Yes, I live at the address on my state-issued ID + state_id_jurisdiction: Issuing state + state_id_jurisdiction_hint: This is the state that issued your ID state_id_jurisdiction_prompt: '- Select -' state_id_number: ID number state_id_number_hint: May include letters and numbers + state_id_state: State + state_id_state_hint: Select the state shown on your ID + state_id_state_prompt: '- Select -' zipcode: ZIP Code headings: address: Enter your current residential address barcode: You’re ready to verify your identity in person with %{app_name} cta: Having trouble verifying your ID online? cta_variant: Try verifying your ID in person + id_address: Address on your ID po_search: location: Find a participating Post Office prepare: Verify your identity in person diff --git a/config/locales/in_person_proofing/es.yml b/config/locales/in_person_proofing/es.yml index 33696aa2d5e..9fdf23439d6 100644 --- a/config/locales/in_person_proofing/es.yml +++ b/config/locales/in_person_proofing/es.yml @@ -104,8 +104,8 @@ es: same_address_choice_yes: Esta dirección aparece en mi cédula de identidad emitida por el estado state_prompt: '- Seleccione -' state_id: - address1: Dirección - address2: Línea de dirección 2 (opcional) + address1: Línea de dirección 1 + address2: Línea de dirección 2 city: Ciudad date_hint: day: 'Ejemplo: 28' @@ -125,23 +125,25 @@ es: missing_month_day_year: Introduce una fecha de nacimiento range_min_age: Debe tener más de 13 años para usar %{app_name} range_overflow: Ingrese una fecha que esté en el pasado - same_address_as_id: ¿Tu domicilio actual aparece en tu identificación emitida - por el estado? - same_address_as_id_no: No, mi domicilio actual no aparece en mi identificación - emitida por el estado. - same_address_as_id_yes: Sí, mi domicilio actual aparece en mi identificación - emitida por el estado + same_address_as_id: ¿Vive actualmente en la dirección que figura en su documento + estatal de identidad? + same_address_as_id_no: No, vivo en otra dirección + same_address_as_id_yes: Sí, vivo en la misma dirección state_id_jurisdiction: Estado state_id_jurisdiction_hint: Seleccione el estado que aparece en su cédula state_id_jurisdiction_prompt: '- Seleccione -' state_id_number: Número de cédula state_id_number_hint: Puede incluir letras y números + state_id_state: Estado emisor + state_id_state_hint: Este es el estado que emitió su identificación + state_id_state_prompt: '- Seleccione -' zipcode: Código postal headings: address: Ingresa tu domicilio actual barcode: Está listo para verificar su identidad en persona con %{app_name} cta: ¿Tiene problemas para verificar su documento de identidad en línea? cta_variant: Intente verificar su ID en persona + id_address: Domicilio que consta en su identificación po_search: location: Encuentre una oficina de correos participante prepare: Verifique su identidad en persona diff --git a/config/locales/in_person_proofing/fr.yml b/config/locales/in_person_proofing/fr.yml index a17055815c4..02cc062646b 100644 --- a/config/locales/in_person_proofing/fr.yml +++ b/config/locales/in_person_proofing/fr.yml @@ -104,8 +104,8 @@ fr: same_address_choice_yes: Cette adresse figure sur mon document d’identité nationale state_prompt: '- Sélectionnez -' state_id: - address1: Adresse - address2: Adresse Ligne 2 (optional) + address1: Adresse ligne 1 + address2: Adresse ligne 2 city: Ville date_hint: day: 'Exemple: 28' @@ -125,23 +125,26 @@ fr: missing_month_day_year: Entrez une date de naissance range_min_age: Vous devez avoir plus de 13 ans pour utiliser %{app_name} range_overflow: Entrez une date qui est dans le passé - same_address_as_id: L’adresse de votre domicile actuel figure-t-elle sur votre - carte d’identité délivrée par l’État? - same_address_as_id_no: Non, l’adresse de mon domicile actuel ne figure pas sur - ma carte d’identité délivrée par l’État - same_address_as_id_yes: Oui, l’adresse de mon domicile actuel figure sur ma - carte d’identité délivrée par l’État + same_address_as_id: Vivez-vous actuellement à l’adresse indiquée sur votre pièce + d’identité émise par l’État? + same_address_as_id_no: Non, j’habite à une adresse différente + same_address_as_id_yes: Oui, j’habite à l’adresse indiquée sur ma pièce + d’identité émise par l’État state_id_jurisdiction: État state_id_jurisdiction_hint: Sélectionnez l’État figurant sur votre document d’identité state_id_jurisdiction_prompt: '- Sélectionnez -' state_id_number: Numéro d’identification state_id_number_hint: Peut comprendre des lettres et des chiffres + state_id_state: État émetteur + state_id_state_hint: Il s’agit de l’État qui a émis votre pièce d’identité + state_id_state_prompt: '- Sélectionnez -' zipcode: Code postal headings: address: Indiquez votre adresse résidentielle actuelle barcode: Vous êtes prêt à vérifier votre identité en personne avec %{app_name} cta: Vous avez des difficultés à vérifier votre identité en ligne? cta_variant: Essayez de vérifier votre identité en personne + id_address: Adresse sur votre pièce d’identité po_search: location: Trouver un bureau de poste participant prepare: Vérifiez votre identité en personne diff --git a/config/locales/vendor_outage/en.yml b/config/locales/vendor_outage/en.yml index a7d9e25cdfb..25a279c3b04 100644 --- a/config/locales/vendor_outage/en.yml +++ b/config/locales/vendor_outage/en.yml @@ -36,18 +36,8 @@ en: idv: generic: We are having technical difficulties on our end and cannot verify your identity at this time. Please try again later. - with_sp: '%{service_provider} needs to make sure you are you — not someone - pretending to be you. Unfortunately, we are having technical - difficulties and cannot verify your identity at this time. Please try - again later.' - without_sp: The agency that you are trying to access needs to make sure you are - you — not someone pretending to be you. Unfortunately, we are having - technical difficulties and cannot verify your identity at this time. - Please try again later. phone: default: We cannot verify phones at this time. Please try again later. - idv: We cannot verify phones at this time. Please try again later or verify your - address by mail instead. get_updates: Get updates get_updates_on_status_page: Get updates on our status page working: We are working to resolve an error diff --git a/config/locales/vendor_outage/es.yml b/config/locales/vendor_outage/es.yml index 5533007f109..78d833924d9 100644 --- a/config/locales/vendor_outage/es.yml +++ b/config/locales/vendor_outage/es.yml @@ -42,22 +42,9 @@ es: generic: Debido a problemas técnicos por nuestra parte, no podemos verificar su identidad en estos momentos. Por favor, inténtelo nuevamente más tarde. - with_sp: '%{service_provider} necesita asegurarse de que es usted realmente y no - alguien que se hace pasar por usted. Lamentablemente, debido a - problemas técnicos por nuestra parte, tal vez no podamos verificar su - identidad en estos momentos. Por favor, inténtelo nuevamente más - tarde.' - without_sp: La agencia a la que está intentando acceder debe asegurarse de que - usted sea quien dice ser, y no alguien que se hace pasar por usted. - Lamentablemente, debido a problemas técnicos por nuestra parte, tal - vez no podamos verificar su identidad en estos momentos. Por favor, - inténtelo nuevamente más tarde. phone: default: No podemos verificar teléfonos en estos momentos. Por favor, inténtelo nuevamente más tarde. - idv: No podemos verificar teléfonos en estos momentos. Por favor, inténtelo - nuevamente más tarde o, en lugar de ello, verifique su dirección por - correo. get_updates: Obtenga actualizaciones get_updates_on_status_page: Reciba actualizaciones en nuestra página de estado working: Estamos trabajando para corregir un error diff --git a/config/locales/vendor_outage/fr.yml b/config/locales/vendor_outage/fr.yml index 7c820ef82fd..de657734133 100644 --- a/config/locales/vendor_outage/fr.yml +++ b/config/locales/vendor_outage/fr.yml @@ -40,20 +40,9 @@ fr: idv: generic: Nous rencontrons des difficultés techniques et ne pouvons pas vérifier votre identité pour le moment. Veuillez réessayer plus tard. - with_sp: '%{service_provider} doit s’assurer que c’est bien vous — et non - quelqu’un qui se fait passer pour vous. Malheureusement, nous - rencontrons des difficultés techniques et ne pouvons pas vérifier - votre identité pour le moment. Veuillez réessayer plus tard.' - without_sp: L’agence à laquelle vous essayez d’accéder doit s’assurer qu’il - s’agit bien de vous, et non de quelqu’un qui se fait passer pour vous. - Malheureusement, nous rencontrons des difficultés techniques et ne - pouvons pas vérifier votre identité pour le moment. Veuillez réessayer - plus tard. phone: default: Nous ne pouvons pas vérifier les téléphones pour le moment. Veuillez réessayer plus tard. - idv: Nous ne pouvons pas vérifier les téléphones pour le moment. Veuillez - réessayer plus tard ou vérifier votre adresse par la poste. get_updates: Obtenir des mises à jour get_updates_on_status_page: Obtenez des mises à jour sur notre page de statut working: Nous travaillons à la résolution d’une erreur diff --git a/config/newrelic.yml b/config/newrelic.yml index 901f693003e..08269ea96e0 100644 --- a/config/newrelic.yml +++ b/config/newrelic.yml @@ -25,6 +25,7 @@ production: ActionController::BadRequest ActionController::ParameterMissing ActionController::RoutingError + ActionController::UnknownHttpMethod ActionDispatch::Http::MimeNegotiation::InvalidType ActionDispatch::Http::Parameters::ParseError GoodJob::ActiveJobExtensions::Concurrency::ConcurrencyExceededError diff --git a/config/routes.rb b/config/routes.rb index f50486b1f35..332c7a0d92b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -305,11 +305,18 @@ get '/restricted' => 'banned_user#show', as: :banned_user + get '/errors/idv_unavailable' => 'idv/unavailable#show', as: :idv_unavailable + scope '/verify', as: 'idv' do get '/' => 'idv#index' get '/activated' => 'idv#activated' end scope '/verify', module: 'idv', as: 'idv' do + if !FeatureManagement.idv_available? + # IdV has been disabled. + match '/*path' => 'unavailable#show', via: %i[get post] + end + get '/mail_only_warning' => 'gpo_only_warning#show' get '/come_back_later' => 'come_back_later#show' get '/personal_key' => 'personal_key#show' diff --git a/db/primary_migrate/20230403201505_add_fraud_review_pending_at_to_profiles.rb b/db/primary_migrate/20230403201505_add_fraud_review_pending_at_to_profiles.rb new file mode 100644 index 00000000000..efd28ec2948 --- /dev/null +++ b/db/primary_migrate/20230403201505_add_fraud_review_pending_at_to_profiles.rb @@ -0,0 +1,8 @@ +class AddFraudReviewPendingAtToProfiles < ActiveRecord::Migration[7.0] + disable_ddl_transaction! + + def change + add_column :profiles, :fraud_review_pending_at, :datetime + add_index :profiles, :fraud_review_pending_at, algorithm: :concurrently + end +end diff --git a/db/primary_migrate/20230403201954_add_fraud_rejection_at_to_profiles.rb b/db/primary_migrate/20230403201954_add_fraud_rejection_at_to_profiles.rb new file mode 100644 index 00000000000..b2c6c89b8e1 --- /dev/null +++ b/db/primary_migrate/20230403201954_add_fraud_rejection_at_to_profiles.rb @@ -0,0 +1,8 @@ +class AddFraudRejectionAtToProfiles < ActiveRecord::Migration[7.0] + disable_ddl_transaction! + + def change + add_column :profiles, :fraud_rejection_at, :datetime + add_index :profiles, :fraud_rejection_at, algorithm: :concurrently + end +end diff --git a/db/primary_migrate/20230403232935_add_status_check_completed_at_to_in_person_enrollments.rb b/db/primary_migrate/20230403232935_add_status_check_completed_at_to_in_person_enrollments.rb new file mode 100644 index 00000000000..eec0281108e --- /dev/null +++ b/db/primary_migrate/20230403232935_add_status_check_completed_at_to_in_person_enrollments.rb @@ -0,0 +1,6 @@ +class AddStatusCheckCompletedAtToInPersonEnrollments < ActiveRecord::Migration[7.0] + def change + add_column :in_person_enrollments, :status_check_completed_at, :datetime, + comment: 'The last time a status check was successfully completed' + end +end diff --git a/db/schema.rb b/db/schema.rb index 5dce1006baa..7767e896d09 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_03_22_000756) do +ActiveRecord::Schema[7.0].define(version: 2023_04_03_232935) do # These are extensions that must be enabled in order to support this database enable_extension "pg_stat_statements" enable_extension "pgcrypto" @@ -310,6 +310,7 @@ t.boolean "deadline_passed_sent", default: false, comment: "deadline passed email sent for expired enrollment" t.datetime "proofed_at", precision: nil, comment: "timestamp when user attempted to proof at a Post Office" t.boolean "capture_secondary_id_enabled", default: false, comment: "record and proof state ID and residential addresses separately" + t.datetime "status_check_completed_at", comment: "The last time a status check was successfully completed" t.index ["profile_id"], name: "index_in_person_enrollments_on_profile_id" t.index ["status_check_attempted_at"], name: "index_in_person_enrollments_on_status_check_attempted_at", where: "(status = 1)" t.index ["unique_id"], name: "index_in_person_enrollments_on_unique_id", unique: true @@ -445,7 +446,11 @@ t.string "initiating_service_provider_issuer" t.boolean "fraud_review_pending", default: false t.boolean "fraud_rejection", default: false + t.datetime "fraud_review_pending_at" + t.datetime "fraud_rejection_at" + t.index ["fraud_rejection_at"], name: "index_profiles_on_fraud_rejection_at" t.index ["fraud_review_pending"], name: "index_profiles_on_fraud_review_pending" + t.index ["fraud_review_pending_at"], name: "index_profiles_on_fraud_review_pending_at" t.index ["name_zip_birth_year_signature"], name: "index_profiles_on_name_zip_birth_year_signature" t.index ["reproof_at"], name: "index_profiles_on_reproof_at" t.index ["ssn_signature"], name: "index_profiles_on_ssn_signature" diff --git a/knapsack_rspec_report.json b/knapsack_rspec_report.json index 1b4936dec3c..265cc93ec04 100644 --- a/knapsack_rspec_report.json +++ b/knapsack_rspec_report.json @@ -1,879 +1,881 @@ { - "spec/components/accordion_component_spec.rb": 0.049147011000000004, - "spec/components/alert_component_spec.rb": 0.108772105, - "spec/components/alert_icon_component_spec.rb": 0.039647655000000004, - "spec/components/barcode_component_spec.rb": 0.097015522, - "spec/components/base_component_spec.rb": 0.047929254, - "spec/components/block_link_component_spec.rb": 0.041102304, - "spec/components/button_component_spec.rb": 0.103327307, - "spec/components/click_observer_component_spec.rb": 0.017100947, - "spec/components/clipboard_button_component_spec.rb": 0.027529106999999997, - "spec/components/countdown_alert_component_spec.rb": 0.071084852, - "spec/components/countdown_component_spec.rb": 0.058935751, - "spec/components/download_button_component_spec.rb": 0.029449876, - "spec/components/flash_component_spec.rb": 0.035777779999999995, - "spec/components/form_link_component_spec.rb": 0.032759548, - "spec/components/icon_component_spec.rb": 0.046635709, - "spec/components/javascript_required_component_spec.rb": 0.083911971, - "spec/components/language_picker_component_spec.rb": 0.044003236, - "spec/components/memorable_date_component_spec.rb": 0.242044868, - "spec/components/modal_component_spec.rb": 0.063299125, - "spec/components/one_time_code_input_component_spec.rb": 0.14030613, - "spec/components/page_footer_component_spec.rb": 0.026011144, - "spec/components/page_heading_component_spec.rb": 0.035640573, - "spec/components/password_toggle_component_spec.rb": 0.097155429, - "spec/components/phone_input_component_spec.rb": 0.619180884, - "spec/components/print_button_component_spec.rb": 0.017636541, - "spec/components/process_list_component_spec.rb": 0.064359267, - "spec/components/spinner_button_component_spec.rb": 0.036441973, - "spec/components/status_page_component_spec.rb": 0.081372785, - "spec/components/step_indicator_component_spec.rb": 0.095723733, - "spec/components/step_indicator_step_component_spec.rb": 0.066855469, - "spec/components/submit_button_component_spec.rb": 0.036746543, - "spec/components/time_component_spec.rb": 0.03417052, - "spec/components/troubleshooting_options_component_spec.rb": 0.046549351, - "spec/components/validated_field_component_spec.rb": 0.109877303, - "spec/components/vendor_outage_alert_component_spec.rb": 0.057830144, - "spec/config/initializers/ab_tests_spec.rb": 0.008335407, - "spec/config/initializers/ahoy_spec.rb": 0.039570654, - "spec/config/initializers/async_exception_spec.rb": 0.020922435, - "spec/config/initializers/ext_digest_spec.rb": 0.006719152, - "spec/config/initializers/job_configurations_spec.rb": 0.079674567, - "spec/config/initializers/phonelib_spec.rb": 0.009395226, - "spec/config/initializers/secure_headers_spec.rb": 0.008657477, - "spec/controllers/account_reset/cancel_controller_spec.rb": 0.793307154, - "spec/controllers/account_reset/confirm_delete_account_controller_spec.rb": 0.028050355, - "spec/controllers/account_reset/confirm_request_controller_spec.rb": 0.079574126, - "spec/controllers/account_reset/delete_account_controller_spec.rb": 1.212332396, - "spec/controllers/account_reset/pending_controller_spec.rb": 0.327602232, - "spec/controllers/account_reset/recovery_options_controller_spec.rb": 0.155542707, - "spec/controllers/account_reset/request_controller_spec.rb": 1.569977809, - "spec/controllers/accounts/personal_keys_controller_spec.rb": 0.62853492, - "spec/controllers/accounts_controller_spec.rb": 0.272364962, - "spec/controllers/analytics_events_controller_spec.rb": 0.02353102, - "spec/controllers/api/irs_attempts_api_controller_spec.rb": 0.271741524, - "spec/controllers/api/verify/base_controller_spec.rb": 0.068762677, - "spec/controllers/api/verify/document_capture_controller_spec.rb": 0.237568261, - "spec/controllers/api/verify/document_capture_errors_controller_spec.rb": 0.210054909, - "spec/controllers/application_controller_spec.rb": 2.117976024, - "spec/controllers/concerns/effective_user_spec.rb": 0.073727609, - "spec/controllers/concerns/idv/document_capture_concern_spec.rb": 0.099133214, - "spec/controllers/concerns/idv/phone_otp_rate_limitable_spec.rb": 0.022041273, - "spec/controllers/concerns/idv/step_indicator_concern_spec.rb": 0.28566715, - "spec/controllers/concerns/idv/threat_metrix_concern_spec.rb": 0.21251878200000002, - "spec/controllers/concerns/idv_step_concern_spec.rb": 0.13809474800000002, - "spec/controllers/concerns/inherited_proofing_concern_spec.rb": 0.088302702, - "spec/controllers/concerns/render_condition_concern_spec.rb": 0.37033526, - "spec/controllers/concerns/verify_sp_attributes_concern_spec.rb": 0.398529965, - "spec/controllers/country_support_controller_spec.rb": 0.053931489, - "spec/controllers/event_disavowal_controller_spec.rb": 0.351596013, - "spec/controllers/fake_s3_controller_spec.rb": 2.511295649, - "spec/controllers/forgot_password_controller_spec.rb": 0.027224797000000002, - "spec/controllers/frontend_log_controller_spec.rb": 0.342427905, - "spec/controllers/health/database_controller_spec.rb": 0.048420299, - "spec/controllers/health/health_controller_spec.rb": 0.045889608, - "spec/controllers/health/outbound_controller_spec.rb": 0.070818091, - "spec/controllers/idv/cancellations_controller_spec.rb": 0.652963132, - "spec/controllers/idv/capture_doc_controller_spec.rb": 0.327192588, - "spec/controllers/idv/capture_doc_status_controller_spec.rb": 0.555131835, - "spec/controllers/idv/come_back_later_controller_spec.rb": 0.084183646, - "spec/controllers/idv/doc_auth_controller_spec.rb": 0.831820165, - "spec/controllers/idv/forgot_password_controller_spec.rb": 0.45275612600000004, - "spec/controllers/idv/gpo_controller_spec.rb": 0.890774696, - "spec/controllers/idv/gpo_verify_controller_spec.rb": 1.789293908, - "spec/controllers/idv/image_uploads_controller_spec.rb": 1.36737438, - "spec/controllers/idv/in_person/address_search_controller_spec.rb": 0.108375784, - "spec/controllers/idv/in_person/ready_to_verify_controller_spec.rb": 0.216674961, - "spec/controllers/idv/in_person/usps_locations_controller_spec.rb": 2.831394503, - "spec/controllers/idv/in_person_controller_spec.rb": 0.209785071, - "spec/controllers/idv/inherited_proofing_cancellations_controller_spec.rb": 0.412491946, - "spec/controllers/idv/inherited_proofing_controller_spec.rb": 0.230617606, - "spec/controllers/idv/otp_delivery_method_controller_spec.rb": 0.46765666699999997, - "spec/controllers/idv/otp_verification_controller_spec.rb": 0.23485983, - "spec/controllers/idv/personal_key_controller_spec.rb": 1.698414453, - "spec/controllers/idv/phone_controller_spec.rb": 1.475145405, - "spec/controllers/idv/phone_errors_controller_spec.rb": 0.532586852, - "spec/controllers/idv/resend_otp_controller_spec.rb": 0.159267863, - "spec/controllers/idv/review_controller_spec.rb": 5.8206442890000005, - "spec/controllers/idv/session_errors_controller_spec.rb": 3.4046109600000003, - "spec/controllers/idv/sessions_controller_spec.rb": 0.328329708, - "spec/controllers/idv/setup_errors_controller_spec.rb": 0.043395489, - "spec/controllers/idv/verify_info_controller_spec.rb": 0.124265517, - "spec/controllers/idv_controller_spec.rb": 0.340371501, - "spec/controllers/mfa_confirmation_controller_spec.rb": 0.28578834399999997, - "spec/controllers/no_js_controller_spec.rb": 0.027093832999999998, - "spec/controllers/openid_connect/authorization_controller_spec.rb": 1.166386948, - "spec/controllers/openid_connect/certs_controller_spec.rb": 0.024938413, - "spec/controllers/openid_connect/configuration_controller_spec.rb": 0.029358142, - "spec/controllers/openid_connect/logout_controller_spec.rb": 1.617582479, - "spec/controllers/openid_connect/token_controller_spec.rb": 0.254868956, - "spec/controllers/openid_connect/user_info_controller_spec.rb": 0.198672963, - "spec/controllers/pages_controller_spec.rb": 0.058824031, - "spec/controllers/password_capture_controller_spec.rb": 0.124963287, - "spec/controllers/reactivate_account_controller_spec.rb": 0.223552417, - "spec/controllers/reauthn_required_controller_spec.rb": 0.11579423999999999, - "spec/controllers/redirect/contact_controller_spec.rb": 0.017144125, - "spec/controllers/redirect/help_center_controller_spec.rb": 0.059476430999999996, - "spec/controllers/redirect/return_to_sp_controller_spec.rb": 0.097941473, - "spec/controllers/risc/configuration_controller_spec.rb": 0.014132906, - "spec/controllers/risc/security_events_controller_spec.rb": 0.990391504, - "spec/controllers/saml_completion_controller_spec.rb": 0.039140058, - "spec/controllers/saml_idp_controller_spec.rb": 11.093810166, - "spec/controllers/saml_post_controller_spec.rb": 0.033944142999999996, - "spec/controllers/saml_signed_message_spec.rb": 0.439664603, - "spec/controllers/service_provider_controller_spec.rb": 0.087910502, - "spec/controllers/sign_out_controller_spec.rb": 0.065300148, - "spec/controllers/sign_up/cancellations_controller_spec.rb": 0.40229099, - "spec/controllers/sign_up/completions_controller_spec.rb": 0.547326205, - "spec/controllers/sign_up/email_confirmations_controller_spec.rb": 0.224425584, - "spec/controllers/sign_up/emails_controller_spec.rb": 0.033428642, - "spec/controllers/sign_up/passwords_controller_spec.rb": 0.178644169, - "spec/controllers/sign_up/registrations_controller_spec.rb": 1.39882121, - "spec/controllers/test/device_profiling_controller_spec.rb": 0.025794102, - "spec/controllers/test/piv_cac_authentication_test_subject_controller_spec.rb": 0.064482308, - "spec/controllers/test/push_notification_controller_spec.rb": 0.037449352, - "spec/controllers/test/telephony_controller_spec.rb": 0.042967176999999995, - "spec/controllers/two_factor_authentication/backup_code_verification_controller_spec.rb": 0.715876689, - "spec/controllers/two_factor_authentication/options_controller_spec.rb": 0.410579153, - "spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb": 3.136869566, - "spec/controllers/two_factor_authentication/personal_key_verification_controller_spec.rb": 0.99690613, - "spec/controllers/two_factor_authentication/piv_cac_verification_controller_spec.rb": 0.915621478, - "spec/controllers/two_factor_authentication/sms_opt_in_controller_spec.rb": 0.635024222, - "spec/controllers/two_factor_authentication/totp_verification_controller_spec.rb": 0.733835657, - "spec/controllers/two_factor_authentication/webauthn_verification_controller_spec.rb": 0.355507404, - "spec/controllers/users/additional_mfa_required_controller_spec.rb": 0.18356746899999998, - "spec/controllers/users/authorization_confirmation_controller_spec.rb": 0.147308682, - "spec/controllers/users/backup_code_setup_controller_spec.rb": 1.6961684620000002, - "spec/controllers/users/delete_controller_spec.rb": 0.475854728, - "spec/controllers/users/edit_phone_controller_spec.rb": 0.147183221, - "spec/controllers/users/email_confirmations_controller_spec.rb": 1.448550375, - "spec/controllers/users/email_language_controller_spec.rb": 0.239465163, - "spec/controllers/users/emails_controller_spec.rb": 0.542180274, - "spec/controllers/users/forget_all_browsers_controller_spec.rb": 0.239115638, - "spec/controllers/users/mfa_selection_controller_spec.rb": 0.380249971, - "spec/controllers/users/passwords_controller_spec.rb": 1.479995975, - "spec/controllers/users/personal_keys_controller_spec.rb": 0.331246202, - "spec/controllers/users/phone_setup_controller_spec.rb": 0.266579666, - "spec/controllers/users/phones_controller_spec.rb": 0.20955723899999998, - "spec/controllers/users/piv_cac_authentication_setup_controller_spec.rb": 0.999457506, - "spec/controllers/users/reset_passwords_controller_spec.rb": 2.175335544, - "spec/controllers/users/rules_of_use_controller_spec.rb": 0.468152071, - "spec/controllers/users/service_provider_revoke_controller_spec.rb": 0.432359624, - "spec/controllers/users/sessions_controller_spec.rb": 1.790181608, - "spec/controllers/users/totp_setup_controller_spec.rb": 4.111021269, - "spec/controllers/users/two_factor_authentication_controller_spec.rb": 2.157944642, - "spec/controllers/users/two_factor_authentication_setup_controller_spec.rb": 0.428352789, - "spec/controllers/users/verify_password_controller_spec.rb": 0.367195705, - "spec/controllers/users/verify_personal_key_controller_spec.rb": 0.875904318, - "spec/controllers/users/webauthn_setup_controller_spec.rb": 0.70466533, - "spec/controllers/vendor_outage_controller_spec.rb": 0.043053054, - "spec/decorators/device_decorator_spec.rb": 0.044806382, - "spec/decorators/email_context_spec.rb": 0.065239854, - "spec/decorators/event_decorator_spec.rb": 0.098268357, - "spec/decorators/mfa_context_spec.rb": 1.371234219, - "spec/decorators/service_provider_session_decorator_spec.rb": 0.321755287, - "spec/decorators/session_decorator_spec.rb": 0.062076096, - "spec/decorators/user_decorator_spec.rb": 1.016717048, - "spec/features/accessibility/idv_pages_spec.rb": 102.978934337, - "spec/features/accessibility/static_pages_spec.rb": 56.09555461, - "spec/features/accessibility/user_pages_spec.rb": 138.871200876, - "spec/features/accessibility/visitor_pages_spec.rb": 23.394869103, - "spec/features/account/backup_codes_spec.rb": 23.388061234, - "spec/features/account/device_spec.rb": 4.238363682, - "spec/features/account/unphishable_badge_spec.rb": 8.318415434999999, - "spec/features/account_connected_apps_spec.rb": 9.033295784, - "spec/features/account_creation/multiple_browsers_spec.rb": 20.211398447, - "spec/features/account_creation/sp_return_log_spec.rb": 5.493974012, - "spec/features/account_email_language_spec.rb": 13.354988754, - "spec/features/account_history_spec.rb": 4.342116669, - "spec/features/account_reset/cancel_request_spec.rb": 5.843557439, - "spec/features/account_reset/delete_account_spec.rb": 16.449192662, - "spec/features/account_reset/pending_request_spec.rb": 6.071581068, - "spec/features/device_tracking_spec.rb": 8.518126325, - "spec/features/event_disavowal_spec.rb": 53.574837167, - "spec/features/ialmax/saml_sign_in_spec.rb": 35.21371572, - "spec/features/idv/account_creation_spec.rb": 56.144554471, - "spec/features/idv/actions/cancel_link_sent_action_spec.rb": 4.882536451, - "spec/features/idv/actions/cancel_send_link_action_spec.rb": 4.757549789, - "spec/features/idv/actions/redo_document_capture_action_spec.rb": 23.409524570000002, - "spec/features/idv/analytics_spec.rb": 27.271190020000002, - "spec/features/idv/cancel_spec.rb": 30.504384713999997, - "spec/features/idv/clearing_and_restarting_spec.rb": 83.24677081600001, - "spec/features/idv/doc_auth/address_step_spec.rb": 27.730397611, - "spec/features/idv/doc_auth/agreement_step_spec.rb": 33.608453043, - "spec/features/idv/doc_auth/document_capture_step_spec.rb": 44.028447855, - "spec/features/idv/doc_auth/email_sent_step_spec.rb": 4.833393796, - "spec/features/idv/doc_auth/link_sent_step_spec.rb": 47.621717086, - "spec/features/idv/doc_auth/send_link_step_spec.rb": 40.572430571, - "spec/features/idv/doc_auth/ssn_step_spec.rb": 18.395156692, - "spec/features/idv/doc_auth/test_credentials_spec.rb": 15.221689832, - "spec/features/idv/doc_auth/upload_step_spec.rb": 18.631862249, - "spec/features/idv/doc_auth/verify_info_step_spec.rb": 26.987061057000002, - "spec/features/idv/doc_auth/verify_step_spec.rb": 116.05652094999999, - "spec/features/idv/doc_auth/welcome_step_spec.rb": 22.040493143, - "spec/features/idv/doc_capture/capture_complete_step_spec.rb": 6.307759956, - "spec/features/idv/doc_capture/document_capture_step_spec.rb": 86.823149064, - "spec/features/idv/gpo_disabled_spec.rb": 9.182235644, - "spec/features/idv/hybrid_flow_spec.rb": 28.979461954, - "spec/features/idv/in_person_spec.rb": 112.48211235400001, - "spec/features/idv/inherited_proofing/agreement_step_spec.rb": 27.898213038, - "spec/features/idv/inherited_proofing/analytics_spec.rb": 5.406147415, - "spec/features/idv/inherited_proofing/get_started_step_spec.rb": 8.919112244, - "spec/features/idv/inherited_proofing/inherited_proofing_cancel_spec.rb": 97.869064893, - "spec/features/idv/inherited_proofing/verify_info_step_spec.rb": 27.370937477, - "spec/features/idv/inherited_proofing/verify_wait_step_spec.rb": 32.942364572, - "spec/features/idv/phone_input_spec.rb": 14.514575307, - "spec/features/idv/phone_otp_rate_limiting_spec.rb": 29.446112104999997, - "spec/features/idv/proofing_components_spec.rb": 42.512160836999996, - "spec/features/idv/sp_handoff_spec.rb": 137.671309011, - "spec/features/idv/sp_requested_attributes_spec.rb": 74.8063194, - "spec/features/idv/steps/confirmation_step_spec.rb": 42.633386223, - "spec/features/idv/steps/forgot_password_step_spec.rb": 24.742056025000004, - "spec/features/idv/steps/gpo_otp_verification_step_spec.rb": 106.017550162, - "spec/features/idv/steps/gpo_step_spec.rb": 57.125811075, - "spec/features/idv/steps/in_person/verify_step_spec.rb": 11.197358651, - "spec/features/idv/steps/phone_otp_verification_step_spec.rb": 33.458809718000005, - "spec/features/idv/steps/phone_step_spec.rb": 196.557153647, - "spec/features/idv/steps/review_step_spec.rb": 46.152502773, - "spec/features/idv/threatmetrix_pending_spec.rb": 16.949332325, - "spec/features/idv/uak_password_spec.rb": 9.639697261, - "spec/features/idv/vendor_outage_spec.rb": 47.880928744, - "spec/features/irs_attempts_api/event_tracking_spec.rb": 23.299167091, - "spec/features/legacy_passwords_spec.rb": 18.011714479, - "spec/features/load_testing/email_sign_up_spec.rb": 4.478636518, - "spec/features/multi_factor_authentication/mfa_cta_spec.rb": 15.661944315, - "spec/features/multiple_emails/add_email_spec.rb": 74.432278243, - "spec/features/multiple_emails/email_management_spec.rb": 32.047586089999996, - "spec/features/multiple_emails/reset_password_spec.rb": 9.537514888, - "spec/features/multiple_emails/sign_in_spec.rb": 14.959968993, - "spec/features/multiple_emails/sp_sign_in_spec.rb": 21.934338037, - "spec/features/new_device_tracking_spec.rb": 13.500902486000001, - "spec/features/openid_connect/authorization_confirmation_spec.rb": 24.572898996, - "spec/features/openid_connect/openid_connect_spec.rb": 205.46179577, - "spec/features/openid_connect/phishing_resistant_required_spec.rb": 44.989927725, - "spec/features/openid_connect/redirect_uri_validation_spec.rb": 43.46192137, - "spec/features/phone/add_phone_spec.rb": 40.597530241, - "spec/features/phone/confirmation_spec.rb": 146.396855398, - "spec/features/phone/default_phone_selection_spec.rb": 23.700579428, - "spec/features/phone/edit_phone_spec.rb": 12.660619418, - "spec/features/phone/rate_limitting_spec.rb": 70.687632474, - "spec/features/phone/remove_phone_spec.rb": 8.708044022, - "spec/features/remember_device/cookie_expiration_spec.rb": 9.56998625, - "spec/features/remember_device/phone_spec.rb": 51.059496764, - "spec/features/remember_device/revocation_spec.rb": 56.235288777, - "spec/features/remember_device/session_expiration_spec.rb": 5.149553426, - "spec/features/remember_device/sp_expiration_spec.rb": 268.472075532, - "spec/features/remember_device/totp_spec.rb": 65.987402859, - "spec/features/remember_device/user_opted_preference_spec.rb": 35.608870363, - "spec/features/remember_device/webauthn_spec.rb": 124.748069825, - "spec/features/reports/authorization_count_spec.rb": 91.459592413, - "spec/features/reports/monthly_gpo_letter_requests_report_spec.rb": 16.182485294, - "spec/features/reports/sp_active_users_report_spec.rb": 9.465962556000001, - "spec/features/saml/authorization_confirmation_spec.rb": 31.964992879, - "spec/features/saml/ial1/account_creation_spec.rb": 13.865674372, - "spec/features/saml/ial1_sso_spec.rb": 67.435076633, - "spec/features/saml/ial2_sso_spec.rb": 38.057789857, - "spec/features/saml/multiple_endpoints_spec.rb": 33.496769253000004, - "spec/features/saml/phishing_resistant_required_spec.rb": 30.763752886, - "spec/features/saml/redirect_uri_validation_spec.rb": 4.95748826, - "spec/features/saml/saml_logout_spec.rb": 30.792872715999998, - "spec/features/saml/saml_relay_state_spec.rb": 19.590728821, - "spec/features/saml/saml_spec.rb": 119.776592439, - "spec/features/services/idv/inherited_proofing/va/mocks/service_spec.rb": 4.038326983, - "spec/features/session/decryption_spec.rb": 4.256088043, - "spec/features/session/timeout_spec.rb": 12.524386905, - "spec/features/sign_in/banned_users_spec.rb": 15.752049699, - "spec/features/sign_in/remember_device_default_spec.rb": 13.080639506, - "spec/features/sign_in/sp_return_log_spec.rb": 4.824498238, - "spec/features/sign_in/two_factor_options_spec.rb": 62.129132518, - "spec/features/sp_cost_tracking_spec.rb": 55.082879594000005, - "spec/features/two_factor_authentication/backup_code_sign_up_spec.rb": 30.868415282, - "spec/features/two_factor_authentication/change_factor_spec.rb": 20.45261191, - "spec/features/two_factor_authentication/multiple_mfa_sign_up_spec.rb": 34.73611352, - "spec/features/two_factor_authentication/multiple_tabs_spec.rb": 13.295791412, - "spec/features/two_factor_authentication/sign_in_spec.rb": 149.34513190799998, - "spec/features/two_factor_authentication/sign_in_via_personal_key_spec.rb": 9.318756492999999, - "spec/features/users/non_restricted_required_sign_in_spec.rb": 22.969656438, - "spec/features/users/password_recovery_via_recovery_code_spec.rb": 57.222423066000005, - "spec/features/users/password_reset_with_pending_profile_spec.rb": 9.117393059000001, - "spec/features/users/piv_cac_management_spec.rb": 40.478984125, - "spec/features/users/regenerate_personal_key_spec.rb": 11.362544527, - "spec/features/users/sign_in_irs_spec.rb": 42.079423733, - "spec/features/users/sign_in_spec.rb": 540.879714153, - "spec/features/users/sign_out_spec.rb": 4.259124252, - "spec/features/users/sign_up_spec.rb": 164.288494001, - "spec/features/users/totp_management_spec.rb": 24.442206140000003, - "spec/features/users/user_edit_spec.rb": 4.468454409, - "spec/features/users/user_profile_spec.rb": 49.651148085, - "spec/features/users/verify_profile_spec.rb": 18.665291157, - "spec/features/visitors/bad_password_spec.rb": 4.814326332, - "spec/features/visitors/email_confirmation_spec.rb": 29.018051282000002, - "spec/features/visitors/i18n_spec.rb": 51.849335752, - "spec/features/visitors/js_disabled_spec.rb": 8.39112344, - "spec/features/visitors/navigation_spec.rb": 4.094604047, - "spec/features/visitors/password_recovery_spec.rb": 86.025270207, - "spec/features/visitors/resend_email_confirmation_spec.rb": 22.605908782, - "spec/features/visitors/set_password_spec.rb": 34.726599573, - "spec/features/visitors/sign_up_with_email_spec.rb": 37.329449042, - "spec/features/webauthn/hidden_spec.rb": 28.581912582, - "spec/features/webauthn/management_spec.rb": 70.053166159, - "spec/features/webauthn/sign_in_spec.rb": 14.182489745000002, - "spec/features/webauthn/sign_up_spec.rb": 19.039691697000002, - "spec/forms/add_user_email_form_spec.rb": 0.479784722, - "spec/forms/api/verify/document_capture_errors_delete_form_spec.rb": 0.029721246, - "spec/forms/delete_user_email_form_spec.rb": 0.310914606, - "spec/forms/edit_phone_form_spec.rb": 0.258150779, - "spec/forms/event_disavowal/password_reset_from_disavowal_form_spec.rb": 3.682894634, - "spec/forms/gpo_verify_form_spec.rb": 1.142967115, - "spec/forms/idv/api_document_verification_form_spec.rb": 0.45293001800000005, - "spec/forms/idv/api_document_verification_status_form_spec.rb": 0.140759624, - "spec/forms/idv/api_image_upload_form_spec.rb": 1.253924595, - "spec/forms/idv/doc_pii_form_spec.rb": 0.064349871, - "spec/forms/idv/inherited_proofing/base_form_spec.rb": 0.086049866, - "spec/forms/idv/inherited_proofing/va/form_spec.rb": 0.197490471, - "spec/forms/idv/phone_confirmation_otp_verification_form_spec.rb": 0.208945709, - "spec/forms/idv/phone_form_spec.rb": 1.081262927, - "spec/forms/idv/ssn_form_spec.rb": 0.171843121, - "spec/forms/idv/ssn_format_form_spec.rb": 0.08519818900000001, - "spec/forms/new_phone_form_spec.rb": 1.161641731, - "spec/forms/openid_connect_authorize_form_spec.rb": 0.518811745, - "spec/forms/openid_connect_logout_form_spec.rb": 0.706959874, - "spec/forms/openid_connect_token_form_spec.rb": 1.9757069170000001, - "spec/forms/otp_delivery_selection_form_spec.rb": 0.119669807, - "spec/forms/otp_verification_form_spec.rb": 0.218209233, - "spec/forms/password_form_spec.rb": 0.97725235, - "spec/forms/password_reset_email_form_spec.rb": 0.080207263, - "spec/forms/personal_key_form_spec.rb": 0.065018962, - "spec/forms/register_user_email_form_spec.rb": 2.78392862, - "spec/forms/reset_password_form_spec.rb": 1.1610412989999999, - "spec/forms/security_event_form_spec.rb": 2.911133848, - "spec/forms/totp_setup_form_spec.rb": 0.18822861400000002, - "spec/forms/totp_verification_form_spec.rb": 0.069494468, - "spec/forms/two_factor_authentication/phone_deletion_form_spec.rb": 0.535660895, - "spec/forms/two_factor_login_options_form_spec.rb": 0.037470828, - "spec/forms/two_factor_options_form_spec.rb": 0.325853875, - "spec/forms/update_email_language_form_spec.rb": 0.08954489, - "spec/forms/update_user_password_form_spec.rb": 1.092777003, - "spec/forms/user_piv_cac_login_form_spec.rb": 0.067772621, - "spec/forms/user_piv_cac_setup_form_spec.rb": 0.201820367, - "spec/forms/user_piv_cac_verification_form_spec.rb": 0.144574521, - "spec/forms/verify_password_form_spec.rb": 0.134231806, - "spec/forms/verify_personal_key_form_spec.rb": 0.284375214, - "spec/forms/webauthn_setup_form_spec.rb": 0.338584243, - "spec/forms/webauthn_verification_form_spec.rb": 0.100489014, - "spec/forms/webauthn_visit_form_spec.rb": 0.175756424, - "spec/helpers/application_helper_spec.rb": 0.026707177, - "spec/helpers/asset_helper_spec.rb": 0.017005984000000002, - "spec/helpers/aws_s3_helper_spec.rb": 0.073577482, - "spec/helpers/go_back_helper_spec.rb": 0.060757685, - "spec/helpers/link_helper_spec.rb": 0.101946363, - "spec/helpers/locale_helper_spec.rb": 0.088891574, - "spec/helpers/script_helper_spec.rb": 0.099531843, - "spec/helpers/session_timeout_warning_helper_spec.rb": 0.069595488, - "spec/i18n_spec.rb": 37.720227783, - "spec/jobs/address_proofing_job_spec.rb": 0.17462343, - "spec/jobs/application_job_spec.rb": 0.009142006, - "spec/jobs/document_proofing_job_spec.rb": 0.50437029, - "spec/jobs/get_usps_proofing_results_job_spec.rb": 6.619208557, - "spec/jobs/gpo_daily_job_spec.rb": 0.099331143, - "spec/jobs/heartbeat_job_spec.rb": 0.052770776, - "spec/jobs/in_person/email_reminder_job_spec.rb": 0.887409784, - "spec/jobs/inherited_proofing_job_spec.rb": 0.015349274, - "spec/jobs/irs_attempts_events_batch_job_spec.rb": 0.330945908, - "spec/jobs/job_helpers/encryption_helper_spec.rb": 0.008010765, - "spec/jobs/job_helpers/s3_helper_spec.rb": 0.110703917, - "spec/jobs/job_helpers/stale_job_helper_spec.rb": 0.030398194, - "spec/jobs/job_helpers/timer_spec.rb": 0.022952948, - "spec/jobs/phone_number_opt_out_sync_job_spec.rb": 0.066530903, - "spec/jobs/psql_stats_job_spec.rb": 0.039264083, - "spec/jobs/reports/agreement_summary_report_spec.rb": 0.108298018, - "spec/jobs/reports/base_report_spec.rb": 0.008733073, - "spec/jobs/reports/combined_invoice_supplement_report_spec.rb": 0.36172781, - "spec/jobs/reports/daily_auths_report_spec.rb": 0.093644721, - "spec/jobs/reports/daily_dropoffs_report_spec.rb": 0.13644600899999998, - "spec/jobs/reports/deleted_user_accounts_report_spec.rb": 0.105382982, - "spec/jobs/reports/irs_weekly_summary_report_spec.rb": 0.296948832, - "spec/jobs/reports/month_helper_spec.rb": 0.019340088999999998, - "spec/jobs/reports/query_helpers_spec.rb": 0.020601285, - "spec/jobs/reports/sp_active_users_report_spec.rb": 0.08714355900000001, - "spec/jobs/reports/sp_user_counts_report_spec.rb": 0.05578129, - "spec/jobs/reports/total_ial2_costs_report_spec.rb": 0.034388406, - "spec/jobs/reports/total_monthly_auths_report_spec.rb": 0.045500935, - "spec/jobs/reports/verification_failures_report_spec.rb": 0.455579546, - "spec/jobs/resolution_proofing_job_spec.rb": 0.758022259, - "spec/jobs/risc_delivery_job_spec.rb": 0.209109026, - "spec/jobs/threat_metrix_js_verification_job_spec.rb": 1.030960332, - "spec/lib/ab_test_bucket_spec.rb": 0.06390188399999999, - "spec/lib/analytics_events_documenter_spec.rb": 0.248858927, - "spec/lib/app_artifacts_spec.rb": 0.048771506, - "spec/lib/asset_sources_spec.rb": 0.1362476, - "spec/lib/aws/ses_spec.rb": 0.038266803, - "spec/lib/base16_spec.rb": 0.032634536, - "spec/lib/data_requests/create_email_addresses_report_spec.rb": 0.026106901, - "spec/lib/data_requests/create_mfa_configurations_report_spec.rb": 0.15112360600000002, - "spec/lib/data_requests/create_user_events_report_spec.rb": 0.050788221, - "spec/lib/data_requests/create_user_report_spec.rb": 0.10290339700000001, - "spec/lib/data_requests/fetch_cloudwatch_logs_spec.rb": 0.024198622, - "spec/lib/data_requests/lookup_shared_device_users_spec.rb": 0.068085213, - "spec/lib/data_requests/lookup_user_by_uuid_spec.rb": 0.063915739, - "spec/lib/data_requests/write_cloudwatch_logs_spec.rb": 0.027318553, - "spec/lib/data_requests/write_user_events_spec.rb": 0.011272968, - "spec/lib/data_requests/write_user_info_spec.rb": 0.01058327, - "spec/lib/deploy/activate_spec.rb": 0.090855127, - "spec/lib/feature_management_spec.rb": 0.273514838, - "spec/lib/fingerprinter_spec.rb": 0.018583016, - "spec/lib/headers_filter_spec.rb": 0.006812243, - "spec/lib/identity_config_spec.rb": 0.026371801, - "spec/lib/identity_job_log_subscriber_spec.rb": 0.206703883, - "spec/lib/linters/errors_add_linter_spec.rb": 0.047610634, - "spec/lib/linters/image_size_linter_spec.rb": 0.094331455, - "spec/lib/linters/localized_validation_message_linter_spec.rb": 0.08268767, - "spec/lib/linters/mail_later_linter_spec.rb": 0.091152605, - "spec/lib/linters/redirect_back_linter_spec.rb": 0.077695647, - "spec/lib/linters/url_options_linter_spec.rb": 0.12496467800000001, - "spec/lib/makefile_help_parser_spec.rb": 0.089192572, - "spec/lib/otp_code_generator_spec.rb": 0.040730353, - "spec/lib/pinpoint_supported_countries_spec.rb": 0.127769791, - "spec/lib/query_tracker_spec.rb": 0.044862226, - "spec/lib/session_encryptor_spec.rb": 0.098413281, - "spec/lib/tasks/dev_rake_spec.rb": 12.162226285000001, - "spec/lib/tasks/partners_rake_spec.rb": 0.886899062, - "spec/lib/tasks/review_profile_spec.rb": 0.411175656, - "spec/lib/tasks/rotate_rake_spec.rb": 0.10711069200000001, - "spec/lib/telephony/alert_sender_spec.rb": 0.07433495600000001, - "spec/lib/telephony/otp_sender_spec.rb": 0.22194904000000001, - "spec/lib/telephony/pinpoint/aws_credential_builder_spec.rb": 0.029442157, - "spec/lib/telephony/pinpoint/opt_out_manager_spec.rb": 0.082387123, - "spec/lib/telephony/pinpoint/sms_sender_spec.rb": 0.249128754, - "spec/lib/telephony/pinpoint/voice_sender_spec.rb": 0.109370858, - "spec/lib/telephony/response_spec.rb": 0.047005193, - "spec/lib/telephony/telephony_spec.rb": 0.084029964, - "spec/lib/telephony/test/call_spec.rb": 0.048464306, - "spec/lib/telephony/test/message_spec.rb": 0.044993153, - "spec/lib/telephony/test/sms_sender_spec.rb": 0.05212054, - "spec/lib/telephony/test/voice_sender_spec.rb": 0.01956261, - "spec/lib/telephony/util_spec.rb": 0.00737186, - "spec/lib/utf8_sanitizer_spec.rb": 0.061775448, - "spec/mailers/previews/user_mailer_preview_spec.rb": 0.279313044, - "spec/mailers/report_mailer_spec.rb": 0.09894568299999999, - "spec/mailers/user_mailer_spec.rb": 3.351854277, - "spec/models/account_reset_request_spec.rb": 0.063627305, - "spec/models/agency_identity_spec.rb": 0.034431008, - "spec/models/agency_spec.rb": 0.046146805, - "spec/models/agreements/iaa_gtc_spec.rb": 0.296810918, - "spec/models/agreements/iaa_order_spec.rb": 0.504770998, - "spec/models/agreements/iaa_spec.rb": 0.312157665, - "spec/models/agreements/integration_spec.rb": 0.369569055, - "spec/models/agreements/integration_status_spec.rb": 0.079110488, - "spec/models/agreements/integration_usage_spec.rb": 0.267389804, - "spec/models/agreements/partner_account_spec.rb": 0.211296024, - "spec/models/agreements/partner_account_status_spec.rb": 0.089256006, - "spec/models/anonymous_user_spec.rb": 0.038836213, - "spec/models/backup_code_configuration_spec.rb": 1.3155075330000001, - "spec/models/concerns/user_otp_methods_spec.rb": 0.010580832, - "spec/models/deleted_user_spec.rb": 0.0996753, - "spec/models/device_spec.rb": 0.09487378, - "spec/models/document_capture_session_spec.rb": 0.12486395, - "spec/models/email_address_spec.rb": 0.254197475, - "spec/models/event_spec.rb": 0.049106344999999996, - "spec/models/gpo_confirmation_code_spec.rb": 0.163433899, - "spec/models/in_person_enrollment_spec.rb": 1.080877239, - "spec/models/null_identity_spec.rb": 0.013323827, - "spec/models/otp_requests_tracker_spec.rb": 0.066435966, - "spec/models/phone_configuration_spec.rb": 0.136422243, - "spec/models/phone_number_opt_out_spec.rb": 0.139528466, - "spec/models/profile_spec.rb": 1.144879759, - "spec/models/service_provider_identity_spec.rb": 0.526990577, - "spec/models/service_provider_spec.rb": 0.092240207, - "spec/models/sp_return_log_spec.rb": 0.008982879, - "spec/models/user_spec.rb": 2.169601104, - "spec/models/webauthn_configuration_spec.rb": 0.179146562, - "spec/policies/backup_code_policy_spec.rb": 0.041491402, - "spec/policies/service_provider_mfa_policy_spec.rb": 1.167226007, - "spec/policies/two_factor_authentication/piv_cac_policy_spec.rb": 0.097554552, - "spec/policies/user_mfa_policy_spec.rb": 0.413726253, - "spec/policies/webauthn_login_option_policy_spec.rb": 0.078762105, - "spec/presenters/account_reset/pending_presenter_spec.rb": 0.131198146, - "spec/presenters/account_show_presenter_spec.rb": 0.239898794, - "spec/presenters/additional_mfa_required_presenter_spec.rb": 0.209258848, - "spec/presenters/cancellation_presenter_spec.rb": 0.041558194, - "spec/presenters/completions_presenter_spec.rb": 0.702209128, - "spec/presenters/confirm_delete_email_presenter_spec.rb": 0.027691823, - "spec/presenters/eastern_time_presenter_spec.rb": 0.007232577, - "spec/presenters/fully_signed_in_modal_presenter_spec.rb": 0.0341076, - "spec/presenters/idv/cancellations_presenter_spec.rb": 0.047369415, - "spec/presenters/idv/gpo_presenter_spec.rb": 0.23047700299999999, - "spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb": 0.480756231, - "spec/presenters/idv/in_person/verification_results_email_presenter_spec.rb": 0.508174151, - "spec/presenters/image_upload_response_presenter_spec.rb": 0.100540624, - "spec/presenters/max_attempts_reached_presenter_spec.rb": 0.029343903, - "spec/presenters/mfa_confirmation_presenter_spec.rb": 0.077649707, - "spec/presenters/navigation_presenter_spec.rb": 0.121035086, - "spec/presenters/openid_connect_certs_presenter_spec.rb": 0.007293362, - "spec/presenters/openid_connect_configuration_presenter_spec.rb": 0.008804586, - "spec/presenters/openid_connect_user_info_presenter_spec.rb": 0.57471445, - "spec/presenters/partially_signed_in_modal_presenter_spec.rb": 0.036481249, - "spec/presenters/piv_cac_authentication_setup_presenter_spec.rb": 0.061132946, - "spec/presenters/piv_cac_error_presenter_spec.rb": 0.032818318, - "spec/presenters/risc_configuration_presenter_spec.rb": 0.010231914, - "spec/presenters/saml_request_presenter_spec.rb": 0.04651439, - "spec/presenters/setup_presenter_spec.rb": 0.08096505300000001, - "spec/presenters/two_factor_auth_code/authenticator_delivery_presenter_spec.rb": 0.028366371, - "spec/presenters/two_factor_auth_code/backup_code_presenter_spec.rb": 0.029430937, - "spec/presenters/two_factor_auth_code/generic_delivery_presenter_spec.rb": 0.007684023, - "spec/presenters/two_factor_auth_code/personal_key_presenter_spec.rb": 0.016164293, - "spec/presenters/two_factor_auth_code/phone_delivery_presenter_spec.rb": 0.062373953, - "spec/presenters/two_factor_auth_code/piv_cac_authentication_presenter_spec.rb": 0.117779067, - "spec/presenters/two_factor_auth_code/webauthn_authentication_presenter_spec.rb": 0.197790952, - "spec/presenters/two_factor_authentication/auth_app_selection_presenter_spec.rb": 0.073220755, - "spec/presenters/two_factor_authentication/personal_key_selection_presenter_spec.rb": 0.007711227, - "spec/presenters/two_factor_authentication/phone_selection_presenter_spec.rb": 0.197122635, - "spec/presenters/two_factor_authentication/piv_cac_selection_presenter_spec.rb": 0.077580676, - "spec/presenters/two_factor_authentication/selection_presenter_spec.rb": 0.033361800999999996, - "spec/presenters/two_factor_authentication/sms_selection_presenter_spec.rb": 0.105708586, - "spec/presenters/two_factor_authentication/voice_selection_presenter_spec.rb": 0.104977153, - "spec/presenters/two_factor_authentication/webauthn_platform_selection_presenter_spec.rb": 0.094294125, - "spec/presenters/two_factor_authentication/webauthn_selection_presenter_spec.rb": 0.085759265, - "spec/presenters/two_factor_login_options_presenter_spec.rb": 0.126158202, - "spec/presenters/two_factor_options_presenter_spec.rb": 0.059798137, - "spec/presenters/utc_time_presenter_spec.rb": 0.007996935, - "spec/presenters/webauthn_setup_presenter_spec.rb": 0.224987129, - "spec/requests/acuant_sdk_spec.rb": 0.10719693899999999, - "spec/requests/api_cors_spec.rb": 0.648163585, - "spec/requests/csp_spec.rb": 0.1317261, - "spec/requests/headers_spec.rb": 0.289887932, - "spec/requests/i18n_spec.rb": 0.127211317, - "spec/requests/invalid_encoding_spec.rb": 0.316951142, - "spec/requests/invalid_sign_in_params_spec.rb": 0.100030549, - "spec/requests/not_acceptable_spec.rb": 0.091949009, - "spec/requests/openid_connect_authorize_spec.rb": 0.682524608, - "spec/requests/openid_connect_cors_spec.rb": 0.775186246, - "spec/requests/page_not_found_spec.rb": 0.321029426, - "spec/requests/params_is_string_instead_of_hash_spec.rb": 0.036043056, - "spec/requests/rack_attack_spec.rb": 7.035250818, - "spec/requests/redirects_spec.rb": 0.112060716, - "spec/requests/redis_down_spec.rb": 0.042421866, - "spec/requests/saml_requests_spec.rb": 0.126058405, - "spec/requests/secure_cookies_spec.rb": 0.317706497, - "spec/routing/gpo_verification_routing_spec.rb": 0.271897607, - "spec/scripts/changelog_check_spec.rb": 0.087690587, - "spec/services/access_token_verifier_spec.rb": 0.070778914, - "spec/services/account_reset/cancel_request_for_user_spec.rb": 0.522738329, - "spec/services/account_reset/cancel_spec.rb": 1.313280391, - "spec/services/account_reset/create_request_spec.rb": 0.5140622619999999, - "spec/services/account_reset/delete_account_spec.rb": 0.470135255, - "spec/services/account_reset/find_prending_request_for_user_spec.rb": 0.116338195, - "spec/services/account_reset/grant_request_spec.rb": 0.033515597, - "spec/services/account_reset/grant_requests_and_send_emails_spec.rb": 1.088987596, - "spec/services/account_reset/notify_user_of_request_cancellation_spec.rb": 0.609316665, - "spec/services/active_profile_encryptor_spec.rb": 0.045989857, - "spec/services/agency_identity_linker_spec.rb": 0.444096779, - "spec/services/agency_seeder_spec.rb": 0.06666127399999999, - "spec/services/agreements/iaa_gtc_seeder_spec.rb": 0.047563289, - "spec/services/agreements/iaa_order_seeder_spec.rb": 0.073733356, - "spec/services/agreements/integration_seeder_spec.rb": 0.077652525, - "spec/services/agreements/integration_status_seeder_spec.rb": 0.040083455000000004, - "spec/services/agreements/partner_account_seeder_spec.rb": 0.050986908, - "spec/services/agreements/partner_account_status_seeder_spec.rb": 0.057081632, - "spec/services/analytics_spec.rb": 0.196870647, - "spec/services/arcgis_api/geocoder_spec.rb": 0.254591012, - "spec/services/attribute_asserter_spec.rb": 1.417471838, - "spec/services/backup_code_generator_spec.rb": 1.608796853, - "spec/services/banned_user_resolver_spec.rb": 0.169445944, - "spec/services/barcode_outputter_spec.rb": 0.021030761, - "spec/services/browser_cache_spec.rb": 0.023664325, - "spec/services/calendar_service_spec.rb": 0.151204539, - "spec/services/cloud_front_header_parser_spec.rb": 0.021399525, - "spec/services/completions_decider_spec.rb": 0.067696835, - "spec/services/database_health_checker_spec.rb": 0.021787039, - "spec/services/date_parser_spec.rb": 0.037518695, - "spec/services/db/add_document_verification_and_selfie_costs_spec.rb": 0.042545368, - "spec/services/db/identity/sp_active_user_counts_spec.rb": 0.076766587, - "spec/services/db/identity/sp_user_counts_spec.rb": 0.035604365, - "spec/services/db/monthly_auth_count/total_monthly_auth_counts_spec.rb": 0.057617347, - "spec/services/db/monthly_sp_auth_count/total_monthly_auth_counts_within_iaa_window_spec.rb": 0.118074815, - "spec/services/db/monthly_sp_auth_count/unique_monthly_auth_counts_by_iaa_spec.rb": 0.17832504100000002, - "spec/services/db/sp_return_log_spec.rb": 0.017495576, - "spec/services/deleted_accounts_report_spec.rb": 0.168865146, - "spec/services/displayable_pii_formatter_spec.rb": 0.877241402, - "spec/services/doc_auth/acuant/acuant_client_spec.rb": 0.595169502, - "spec/services/doc_auth/acuant/pii_from_doc_spec.rb": 0.039825227, - "spec/services/doc_auth/acuant/request_spec.rb": 0.5969638580000001, - "spec/services/doc_auth/acuant/requests/create_document_request_spec.rb": 0.052855897, - "spec/services/doc_auth/acuant/requests/get_results_request_spec.rb": 0.057867368, - "spec/services/doc_auth/acuant/requests/upload_image_request_spec.rb": 0.04673682, - "spec/services/doc_auth/acuant/responses/create_document_response_spec.rb": 0.008015186, - "spec/services/doc_auth/acuant/responses/get_results_response_spec.rb": 0.11955101, - "spec/services/doc_auth/acuant/result_codes_spec.rb": 0.015067951, - "spec/services/doc_auth/error_generator_spec.rb": 0.173362816, - "spec/services/doc_auth/lexis_nexis/lexis_nexis_client_spec.rb": 0.339152287, - "spec/services/doc_auth/lexis_nexis/request_spec.rb": 0.513154343, - "spec/services/doc_auth/lexis_nexis/requests/true_id_request_spec.rb": 0.08492709600000001, - "spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb": 0.526238586, - "spec/services/doc_auth/mock/dock_auth_mock_client_spec.rb": 0.089377347, - "spec/services/doc_auth/mock/result_response_spec.rb": 0.130995995, - "spec/services/doc_auth/processed_alert_to_log_alert_formatter_spec.rb": 0.048100604, - "spec/services/doc_auth/response_spec.rb": 0.110714172, - "spec/services/doc_auth_router_spec.rb": 0.104369947, - "spec/services/document_capture_session_async_result_spec.rb": 0.04468306, - "spec/services/document_capture_session_result_spec.rb": 0.013961617, - "spec/services/duration_parser_spec.rb": 0.07542789899999999, - "spec/services/email_confirmation_token_validator_spec.rb": 0.171470942, - "spec/services/encrypted_attribute_spec.rb": 0.045735786, - "spec/services/encrypted_document_storage/document_writer_spec.rb": 0.056115484, - "spec/services/encrypted_document_storage/local_storage_spec.rb": 0.006655648, - "spec/services/encrypted_document_storage/s3_storage_spec.rb": 0.011837611, - "spec/services/encrypted_redis_struct_storage_spec.rb": 0.095256547, - "spec/services/encryption/aes_cipher_spec.rb": 0.029692198, - "spec/services/encryption/contextless_kms_client_spec.rb": 0.158337668, - "spec/services/encryption/encryptors/aes_encryptor_spec.rb": 0.021458273, - "spec/services/encryption/encryptors/attribute_encryptor_spec.rb": 0.056215738, - "spec/services/encryption/encryptors/background_proofing_arg_encryptor_spec.rb": 0.032815329, - "spec/services/encryption/encryptors/pii_encryptor_spec.rb": 0.087434982, - "spec/services/encryption/encryptors/session_encryptor_spec.rb": 0.022074273, - "spec/services/encryption/kms_client_spec.rb": 0.124088057, - "spec/services/encryption/kms_logger_spec.rb": 0.027827677000000002, - "spec/services/encryption/multi_region_kms_client_spec.rb": 0.083713106, - "spec/services/encryption/password_verifier_spec.rb": 0.121817937, - "spec/services/encryption/uak_password_verifier_spec.rb": 0.290313061, - "spec/services/encryption/user_access_key_spec.rb": 0.082614757, - "spec/services/event_disavowal/disavow_event_spec.rb": 0.029016975, - "spec/services/event_disavowal/find_disavowed_event_spec.rb": 0.078908649, - "spec/services/event_disavowal/validate_disavowed_event_spec.rb": 0.101543407, - "spec/services/forget_all_browsers_spec.rb": 0.020601921, - "spec/services/form_response_spec.rb": 0.229848636, - "spec/services/frontend_logger_spec.rb": 0.03759352, - "spec/services/funnel/registration/add_mfa_spec.rb": 0.030655013, - "spec/services/funnel/registration/total_registered_count_spec.rb": 2.41516231, - "spec/services/gpo_confirmation_exporter_spec.rb": 0.014903229, - "spec/services/gpo_confirmation_maker_spec.rb": 0.201290419, - "spec/services/gpo_confirmation_spec.rb": 0.023151908, - "spec/services/gpo_confirmation_uploader_spec.rb": 0.085924338, - "spec/services/gpo_daily_test_sender_spec.rb": 0.069554278, - "spec/services/health_check_summary_spec.rb": 0.01377171, - "spec/services/iaa_reporting_helper_spec.rb": 0.197426729, - "spec/services/ial_context_spec.rb": 0.564007904, - "spec/services/id_token_builder_spec.rb": 0.44178926, - "spec/services/identity_linker_spec.rb": 0.34482297, - "spec/services/idv/actions/verify_document_status_action_spec.rb": 0.310872931, - "spec/services/idv/agent_spec.rb": 0.431849365, - "spec/services/idv/analytics_events_enhancer_spec.rb": 0.11322181099999999, - "spec/services/idv/cancel_verification_attempt_spec.rb": 0.250370914, - "spec/services/idv/data_url_image_spec.rb": 0.02930365, - "spec/services/idv/doc_auth_form_response_spec.rb": 0.047722898, - "spec/services/idv/duplicate_ssn_finder_spec.rb": 0.396549523, - "spec/services/idv/gpo_mail_spec.rb": 0.140903219, - "spec/services/idv/in_person/completion_survey_sender_spec.rb": 0.701078816, - "spec/services/idv/in_person/enrollment_code_formatter_spec.rb": 0.007275535, - "spec/services/idv/in_person_config_spec.rb": 0.09524637500000001, - "spec/services/idv/inherited_proofing/service_provider_forms_spec.rb": 0.017866026, - "spec/services/idv/inherited_proofing/service_provider_services_spec.rb": 0.046329605999999995, - "spec/services/idv/inherited_proofing/va/mocks/service_spec.rb": 0.022656277, - "spec/services/idv/inherited_proofing/va/service_spec.rb": 0.212388074, - "spec/services/idv/phone_confirmation_session_spec.rb": 0.072848268, - "spec/services/idv/phone_step_spec.rb": 0.892131694, - "spec/services/idv/profile_maker_spec.rb": 0.216338542, - "spec/services/idv/proofing_components_logging_spec.rb": 0.00808737, - "spec/services/idv/send_phone_confirmation_otp_spec.rb": 0.165591839, - "spec/services/idv/session_spec.rb": 1.022631924, - "spec/services/idv/steps/document_capture_step_spec.rb": 0.11231677100000001, - "spec/services/idv/steps/in_person/address_step_spec.rb": 0.034563412, - "spec/services/idv/steps/in_person/ssn_step_spec.rb": 0.10425285200000001, - "spec/services/idv/steps/in_person/state_id_step_spec.rb": 0.124847793, - "spec/services/idv/steps/in_person/verify_step_spec.rb": 0.423742355, - "spec/services/idv/steps/in_person/verify_wait_step_show_spec.rb": 0.23411788, - "spec/services/idv/steps/send_link_step_spec.rb": 0.03121841, - "spec/services/idv/steps/ssn_step_spec.rb": 0.147318598, - "spec/services/idv/steps/verify_step_spec.rb": 0.221633626, - "spec/services/idv/steps/verify_wait_step_show_spec.rb": 0.24069390899999998, - "spec/services/idv/steps/welcome_step_spec.rb": 0.096048725, - "spec/services/image_upload_presigned_url_generator_spec.rb": 0.021236647, - "spec/services/irs_attempts_api/attempt_event_spec.rb": 1.029090904, - "spec/services/irs_attempts_api/envelope_encryptor_spec.rb": 1.867925429, - "spec/services/irs_attempts_api/redis_client_spec.rb": 0.02766815, - "spec/services/irs_attempts_api/tracker_spec.rb": 0.426418519, - "spec/services/key_rotator/attribute_encryption_spec.rb": 0.047732795999999994, - "spec/services/key_rotator/hmac_fingerprinter_spec.rb": 0.144293607, - "spec/services/maintenance_window_spec.rb": 0.055038656000000005, - "spec/services/marketing_site_spec.rb": 0.146001812, - "spec/services/multi_health_checker_spec.rb": 0.019880269, - "spec/services/openid_connect_attribute_scoper_spec.rb": 0.119872429, - "spec/services/otp_preference_updater_spec.rb": 0.062165502, - "spec/services/otp_rate_limiter_spec.rb": 0.152157655, - "spec/services/out_of_band_session_accessor_spec.rb": 0.062152927, - "spec/services/outbound_health_checker_spec.rb": 0.184794702, - "spec/services/parse_controller_from_referer_spec.rb": 0.016213323, - "spec/services/personal_key_generator_spec.rb": 0.39597725500000003, - "spec/services/phone_formatter_spec.rb": 0.044494338, - "spec/services/phone_number_capabilities_spec.rb": 0.311111883, - "spec/services/pii/attributes_spec.rb": 0.048974035, - "spec/services/pii/cacher_spec.rb": 0.5165822369999999, - "spec/services/pii/fingerprinter_spec.rb": 0.088296894, - "spec/services/pii/re_encryptor_spec.rb": 0.13912480900000002, - "spec/services/piv_cac/check_config_spec.rb": 0.023588783, - "spec/services/piv_cac_service_spec.rb": 0.151519679, - "spec/services/profanity_detector_spec.rb": 0.055579421, - "spec/services/proofing/aamva/applicant_spec.rb": 0.022719184, - "spec/services/proofing/aamva/authentication_client_spec.rb": 0.226609978, - "spec/services/proofing/aamva/hmac_secret_spec.rb": 0.036037677, - "spec/services/proofing/aamva/proofing_spec.rb": 0.222116563, - "spec/services/proofing/aamva/request/authentication_token_request_spec.rb": 0.331372834, - "spec/services/proofing/aamva/request/security_token_request_spec.rb": 1.695364844, - "spec/services/proofing/aamva/request/verification_request_spec.rb": 0.5182939329999999, - "spec/services/proofing/aamva/response/authentication_token_response_spec.rb": 0.056526948, - "spec/services/proofing/aamva/response/security_token_response_spec.rb": 0.089254431, - "spec/services/proofing/aamva/response/verification_response_spec.rb": 0.295524163, - "spec/services/proofing/aamva/soap_error_handler_spec.rb": 0.062254464, - "spec/services/proofing/aamva/verification_client_spec.rb": 0.521299008, - "spec/services/proofing/lexis_nexis/date_formatter_spec.rb": 0.024901723, - "spec/services/proofing/lexis_nexis/ddp/proofing_spec.rb": 0.07044550599999999, - "spec/services/proofing/lexis_nexis/ddp/response_redacter_spec.rb": 0.029369222, - "spec/services/proofing/lexis_nexis/ddp/verification_request_spec.rb": 0.154966442, - "spec/services/proofing/lexis_nexis/instant_verify/check_to_attribute_mapper_spec.rb": 0.054316685, - "spec/services/proofing/lexis_nexis/instant_verify/proofing_spec.rb": 0.140340471, - "spec/services/proofing/lexis_nexis/instant_verify/verification_request_spec.rb": 0.118398591, - "spec/services/proofing/lexis_nexis/phone_finder/proofing_spec.rb": 0.162158531, - "spec/services/proofing/lexis_nexis/phone_finder/verification_request_spec.rb": 0.103770414, - "spec/services/proofing/lexis_nexis/response_spec.rb": 0.114928848, - "spec/services/proofing/lexis_nexis/verification_error_parser_spec.rb": 0.032426917, - "spec/services/proofing/mock/address_mock_client_spec.rb": 0.033923987, - "spec/services/proofing/mock/ddp_mock_client_spec.rb": 0.047904126, - "spec/services/proofing/mock/device_profiling_backend_spec.rb": 0.015433675, - "spec/services/proofing/mock/resolution_mock_client_spec.rb": 0.068481, - "spec/services/proofing/mock/state_id_mock_client_spec.rb": 0.036386154, - "spec/services/proofing/resolution_result_adjudicator_spec.rb": 0.041358236, - "spec/services/proofing/result_spec.rb": 0.170110073, - "spec/services/proofing_session_async_result_spec.rb": 0.008156238, - "spec/services/push_notification/account_purged_event_spec.rb": 0.033696301, - "spec/services/push_notification/email_changed_event_spec.rb": 0.030610602, - "spec/services/push_notification/http_push_spec.rb": 0.658764272, - "spec/services/push_notification/identifier_recycled_event_spec.rb": 0.033834444000000005, - "spec/services/push_notification/mfa_limit_account_locked_event_spec.rb": 0.071419766, - "spec/services/push_notification/password_reset_event_spec.rb": 0.027089673, - "spec/services/push_notification/recovery_activated_event_spec.rb": 0.034678147, - "spec/services/push_notification/reproof_completed_event_spec.rb": 0.031385264999999996, - "spec/services/pwned_passwords/lookup_password_spec.rb": 0.017572236, - "spec/services/random_phrase_spec.rb": 0.054952944999999996, - "spec/services/reactivate_account_session_spec.rb": 0.145035185, - "spec/services/redis_rate_limiter_spec.rb": 0.06365961, - "spec/services/remember_device_cookie_spec.rb": 0.16358788600000002, - "spec/services/request_password_reset_spec.rb": 3.84982235, - "spec/services/reset_user_password_spec.rb": 1.656120346, - "spec/services/revoke_service_provider_consent_spec.rb": 0.037012274, - "spec/services/saml_endpoint_spec.rb": 0.077398775, - "spec/services/saml_request_validator_spec.rb": 0.129392116, - "spec/services/secure_headers_allow_list_spec.rb": 0.045560798, - "spec/services/send_sign_up_email_confirmation_spec.rb": 0.9002513870000001, - "spec/services/service_provider_request_proxy_spec.rb": 0.067697158, - "spec/services/service_provider_seeder_spec.rb": 1.489102754, - "spec/services/service_provider_updater_spec.rb": 0.371044052, - "spec/services/session_encryptor_spec.rb": 0.026784901, - "spec/services/sp_return_url_resolver_spec.rb": 0.087292078, - "spec/services/ssn_formatter_spec.rb": 0.071836666, - "spec/services/store_sp_metadata_in_session_spec.rb": 0.037607598, - "spec/services/throttle_spec.rb": 0.16150151399999998, - "spec/services/time_service_spec.rb": 0.007492697, - "spec/services/update_user_spec.rb": 0.315131791, - "spec/services/uri_service_spec.rb": 0.049602692000000004, - "spec/services/user_alerts/alert_user_about_account_verified_spec.rb": 0.644675534, - "spec/services/user_alerts/alert_user_about_new_device_spec.rb": 0.43763708, - "spec/services/user_alerts/alert_user_about_password_change_spec.rb": 0.45879819, - "spec/services/user_alerts/alert_user_about_personal_key_sign_in_spec.rb": 0.434650409, - "spec/services/user_event_creator_spec.rb": 0.25354719400000003, - "spec/services/user_seeder_spec.rb": 2.879392347, - "spec/services/user_session_context_spec.rb": 0.056569425, - "spec/services/usps_in_person_proofing/enrollment_helper_spec.rb": 1.713073552, - "spec/services/usps_in_person_proofing/proofer_spec.rb": 0.195618458, - "spec/services/uuid_reporter_spec.rb": 0.259169016, - "spec/services/vendor_status_spec.rb": 0.196496469, - "spec/services/x509/attribute_spec.rb": 0.007711406, - "spec/services/x509/attributes_spec.rb": 0.055760618, - "spec/svg_spec.rb": 0.997822538, - "spec/views/account_reset/cancel/show.html.erb_spec.rb": 0.02643611, - "spec/views/account_reset/confirm_delete_account/show.html.erb_spec.rb": 0.037357889000000005, - "spec/views/account_reset/confirm_request/show.html.erb_spec.rb": 0.020924519, - "spec/views/account_reset/delete_account/show.html.erb_spec.rb": 0.027562486, - "spec/views/account_reset/recovery_options/show.html.erb_spec.rb": 0.035277194, - "spec/views/account_reset/request/show.html.erb_spec.rb": 0.08116884499999999, - "spec/views/account_reset/user_mailer/email_confirmation_instructions.html.erb_spec.rb": 0.195369038, - "spec/views/account_reset/user_mailer/unconfirmed_email_instructions.html.erb_spec.rb": 0.14238541400000002, - "spec/views/accounts/_nav_auth.html.erb_spec.rb": 0.099497997, - "spec/views/accounts/connected_accounts/show.html.erb_spec.rb": 0.088269719, - "spec/views/accounts/history/show.html.erb_spec.rb": 0.04057107, - "spec/views/accounts/show.html.erb_spec.rb": 0.792754118, - "spec/views/accounts/two_factor_authentication/show.html.erb_spec.rb": 0.28162121, - "spec/views/devise/passwords/edit.html.erb_spec.rb": 0.177408905, - "spec/views/devise/passwords/new.html.erb_spec.rb": 0.121723631, - "spec/views/devise/sessions/new.html.erb_spec.rb": 0.420667595, - "spec/views/devise/shared/_password_strength.html.erb_spec.rb": 0.077075795, - "spec/views/forgot_password/show.html.erb_spec.rb": 0.07941247900000001, - "spec/views/idv/activated.html.erb_spec.rb": 0.02576063, - "spec/views/idv/cancellations/destroy.html.erb_spec.rb": 0.043809009999999995, - "spec/views/idv/cancellations/new.html.erb_spec.rb": 0.096707272, - "spec/views/idv/come_back_later/show.html.erb_spec.rb": 0.066434787, - "spec/views/idv/doc_auth/_cancel.html.erb_spec.rb": 0.028245101999999998, - "spec/views/idv/doc_auth/upload.html.erb_spec.rb": 0.016437345, - "spec/views/idv/doc_auth/welcome.html.erb_spec.rb": 0.172654326, - "spec/views/idv/gpo/index.html.erb_spec.rb": 0.190390253, - "spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb": 0.422239303, - "spec/views/idv/inherited_proofing/agreement.html.erb_spec.rb": 0.054860779, - "spec/views/idv/inherited_proofing/get_started.html.erb_spec.rb": 0.073224101, - "spec/views/idv/inherited_proofing/retrieval.html.erb_spec.rb": 0.063003193, - "spec/views/idv/otp_delivery_method/new.html.erb_spec.rb": 2.346517686, - "spec/views/idv/phone/new.html.erb_spec.rb": 0.117593909, - "spec/views/idv/phone_errors/_warning.html.erb_spec.rb": 0.148965295, - "spec/views/idv/phone_errors/failure.html.erb_spec.rb": 0.035213686, - "spec/views/idv/phone_errors/jobfail.html.erb_spec.rb": 0.071391794, - "spec/views/idv/phone_errors/timeout.html.erb_spec.rb": 0.091650747, - "spec/views/idv/phone_errors/warning.html.erb_spec.rb": 2.491938882, - "spec/views/idv/review/new.html.erb_spec.rb": 0.228347029, - "spec/views/idv/session_errors/exception.html.erb_spec.rb": 0.036973738, - "spec/views/idv/session_errors/failure.html.erb_spec.rb": 0.032551618000000004, - "spec/views/idv/session_errors/throttled.html.erb_spec.rb": 0.066645808, - "spec/views/idv/session_errors/warning.html.erb_spec.rb": 0.078130013, - "spec/views/idv/setup_errors/show.html.erb_spec.rb": 0.027011202999999998, - "spec/views/idv/shared/_back.html.erb_spec.rb": 0.140458106, - "spec/views/idv/shared/_document_capture.html.erb_spec.rb": 0.163371821, - "spec/views/idv/shared/_error.html.erb_spec.rb": 0.417349375, - "spec/views/idv/shared/_ssn.html.erb_spec.rb": 0.20486670199999998, - "spec/views/layouts/application.html.erb_spec.rb": 0.514892659, - "spec/views/layouts/user_mailer.html.erb_spec.rb": 0.363813026, - "spec/views/mfa_confirmation/show.html.erb_spec.rb": 0.142166368, - "spec/views/partials/multi_factor_authentication/_mfa_selection.html.erb_spec.rb": 0.183879445, - "spec/views/phone_setup/index.html.erb_spec.rb": 0.30427586100000004, - "spec/views/reactivate_account/index.html.erb_spec.rb": 0.022433174, - "spec/views/shared/_address.html.erb_spec.rb": 0.042828727999999996, - "spec/views/shared/_banner.html.erb_spec.rb": 0.037668518, - "spec/views/shared/_email_languages.html.erb_spec.rb": 0.1201203, - "spec/views/shared/_footer_lite.html.erb_spec.rb": 0.126087999, - "spec/views/shared/_maintenance_window_alert.html.erb_spec.rb": 0.055376061000000004, - "spec/views/shared/_masked_text.html.erb_spec.rb": 0.09122343699999999, - "spec/views/shared/_nav_branded.html.erb_spec.rb": 0.08085326, - "spec/views/shared/_nav_lite.html.erb_spec.rb": 0.02417347, - "spec/views/shared/_personal_key.html.erb_spec.rb": 0.026055194, - "spec/views/shared/_troubleshooting_options.html.erb_spec.rb": 0.17557002300000002, - "spec/views/shared/personal_key/_key.html.erb_spec.rb": 0.023120367, - "spec/views/sign_up/completions/show.html.erb_spec.rb": 0.221683159, - "spec/views/sign_up/email_resend/new.html.erb_spec.rb": 0.035517566, - "spec/views/sign_up/emails/show.html.erb_spec.rb": 0.04764852, - "spec/views/sign_up/passwords/new.html.erb_spec.rb": 0.105079434, - "spec/views/sign_up/registrations/new.html.erb_spec.rb": 0.164365077, - "spec/views/two_factor_authentication/options/index.html.erb_spec.rb": 0.159048591, - "spec/views/two_factor_authentication/otp_verification/show.html.erb_spec.rb": 0.39991023600000003, - "spec/views/two_factor_authentication/personal_key_verification/show.html.erb_spec.rb": 0.154182877, - "spec/views/two_factor_authentication/sms_opt_in/error.html.erb_spec.rb": 0.116736438, - "spec/views/two_factor_authentication/sms_opt_in/new.html.erb_spec.rb": 0.090751205, - "spec/views/two_factor_authentication/totp_verification/show.html.erb_spec.rb": 0.273594457, - "spec/views/users/backup_code_setup/create.html.erb_spec.rb": 0.284494432, - "spec/views/users/backup_code_setup/reminder.html.erb_spec.rb": 0.055875805, - "spec/views/users/delete/show.html.erb_spec.rb": 0.25852063200000003, - "spec/views/users/edit_phone/remove_phone.html.erb_spec.rb": 0.11129446900000001, - "spec/views/users/passwords/edit.html.erb_spec.rb": 0.12145905800000001, - "spec/views/users/phones/add.html.erb_spec.rb": 0.070481236, - "spec/views/users/piv_cac_authentication_setup/new.html.erb_spec.rb": 0.06872613699999999, - "spec/views/users/shared/_otp_delivery_preference_selection.html.erb_spec.rb": 0.146298796, - "spec/views/users/totp_setup/new.html.erb_spec.rb": 0.204829306, - "spec/views/users/two_factor_authentication_setup/index.html.erb_spec.rb": 0.16885018000000002, - "spec/views/users/webauthn_setup/new.html.erb_spec.rb": 0.032509383, - "spec/views/vendor_outage/show.html.erb_spec.rb": 2.786345259 -} \ No newline at end of file + "spec/bin/query-cloudwatch_spec.rb": 0.185691175, + "spec/browsers_json_spec.rb": 0.01345417, + "spec/components/accordion_component_spec.rb": 0.047253322, + "spec/components/alert_component_spec.rb": 0.101356174, + "spec/components/alert_icon_component_spec.rb": 0.050707798, + "spec/components/barcode_component_spec.rb": 0.102853523, + "spec/components/base_component_spec.rb": 0.065462929, + "spec/components/block_link_component_spec.rb": 0.033560085, + "spec/components/button_component_spec.rb": 0.081012837, + "spec/components/captcha_submit_button_component_spec.rb": 0.115090254, + "spec/components/click_observer_component_spec.rb": 0.019846901, + "spec/components/clipboard_button_component_spec.rb": 0.026499913, + "spec/components/countdown_alert_component_spec.rb": 0.066877983, + "spec/components/countdown_component_spec.rb": 0.039926967, + "spec/components/download_button_component_spec.rb": 0.028188849000000002, + "spec/components/flash_component_spec.rb": 0.029677084, + "spec/components/form_link_component_spec.rb": 0.018150979, + "spec/components/icon_component_spec.rb": 0.037456068, + "spec/components/javascript_required_component_spec.rb": 0.068863599, + "spec/components/language_picker_component_spec.rb": 0.043185727, + "spec/components/memorable_date_component_spec.rb": 0.189257412, + "spec/components/modal_component_spec.rb": 0.057037631, + "spec/components/one_time_code_input_component_spec.rb": 0.115337998, + "spec/components/page_footer_component_spec.rb": 0.023401319, + "spec/components/page_heading_component_spec.rb": 0.030338535, + "spec/components/password_toggle_component_spec.rb": 0.059668459, + "spec/components/phone_input_component_spec.rb": 0.627761231, + "spec/components/print_button_component_spec.rb": 0.018293783, + "spec/components/process_list_component_spec.rb": 0.058629781, + "spec/components/spinner_button_component_spec.rb": 0.052304052, + "spec/components/status_page_component_spec.rb": 0.073577429, + "spec/components/step_indicator_component_spec.rb": 0.102082847, + "spec/components/step_indicator_step_component_spec.rb": 0.06419309299999999, + "spec/components/submit_button_component_spec.rb": 0.032022745, + "spec/components/time_component_spec.rb": 0.037802394, + "spec/components/troubleshooting_options_component_spec.rb": 0.0640858, + "spec/components/validated_field_component_spec.rb": 0.093702209, + "spec/components/vendor_outage_alert_component_spec.rb": 0.050706314, + "spec/config/initializers/ab_tests_spec.rb": 0.010122217, + "spec/config/initializers/ahoy_spec.rb": 0.045401162, + "spec/config/initializers/async_exception_spec.rb": 0.014906909, + "spec/config/initializers/ext_digest_spec.rb": 0.011389408, + "spec/config/initializers/job_configurations_spec.rb": 0.064500894, + "spec/config/initializers/phonelib_spec.rb": 0.008330456, + "spec/config/initializers/secure_headers_spec.rb": 0.007119445, + "spec/controllers/account_reset/cancel_controller_spec.rb": 0.719626954, + "spec/controllers/account_reset/confirm_delete_account_controller_spec.rb": 0.029051145, + "spec/controllers/account_reset/confirm_request_controller_spec.rb": 0.028675140000000002, + "spec/controllers/account_reset/delete_account_controller_spec.rb": 0.660295251, + "spec/controllers/account_reset/pending_controller_spec.rb": 0.29364802100000004, + "spec/controllers/account_reset/recovery_options_controller_spec.rb": 0.127795112, + "spec/controllers/account_reset/request_controller_spec.rb": 1.588041571, + "spec/controllers/accounts/personal_keys_controller_spec.rb": 0.571222531, + "spec/controllers/accounts_controller_spec.rb": 0.24805039999999998, + "spec/controllers/analytics_events_controller_spec.rb": 0.02453217, + "spec/controllers/api/internal/sessions_controller_spec.rb": 0.27534024, + "spec/controllers/api/irs_attempts_api_controller_spec.rb": 0.619138087, + "spec/controllers/api/verify/base_controller_spec.rb": 0.12245304000000001, + "spec/controllers/api/verify/document_capture_controller_spec.rb": 0.241268252, + "spec/controllers/api/verify/document_capture_errors_controller_spec.rb": 0.17630573, + "spec/controllers/application_controller_spec.rb": 1.687593063, + "spec/controllers/concerns/api/csrf_token_concern_spec.rb": 0.01633232, + "spec/controllers/concerns/effective_user_spec.rb": 0.0690955, + "spec/controllers/concerns/idv/document_capture_concern_spec.rb": 0.032767786, + "spec/controllers/concerns/idv/phone_otp_rate_limitable_spec.rb": 0.028521787, + "spec/controllers/concerns/idv/step_indicator_concern_spec.rb": 0.282383953, + "spec/controllers/concerns/idv/threat_metrix_concern_spec.rb": 0.062069293, + "spec/controllers/concerns/idv_step_concern_spec.rb": 0.259207908, + "spec/controllers/concerns/reauthentication_required_concern_spec.rb": 0.214750925, + "spec/controllers/concerns/recaptcha_concern_spec.rb": 0.06723346499999999, + "spec/controllers/concerns/render_condition_concern_spec.rb": 0.099476305, + "spec/controllers/concerns/verify_sp_attributes_concern_spec.rb": 0.529739826, + "spec/controllers/country_support_controller_spec.rb": 0.048648460000000004, + "spec/controllers/event_disavowal_controller_spec.rb": 0.313231184, + "spec/controllers/fake_s3_controller_spec.rb": 0.033832763, + "spec/controllers/forgot_password_controller_spec.rb": 0.023822617, + "spec/controllers/frontend_log_controller_spec.rb": 0.31407554, + "spec/controllers/health/database_controller_spec.rb": 0.044527772, + "spec/controllers/health/health_controller_spec.rb": 0.037807157, + "spec/controllers/health/outbound_controller_spec.rb": 0.076502189, + "spec/controllers/idv/cancellations_controller_spec.rb": 0.698957932, + "spec/controllers/idv/capture_doc_controller_spec.rb": 0.22255448, + "spec/controllers/idv/capture_doc_status_controller_spec.rb": 0.404447052, + "spec/controllers/idv/come_back_later_controller_spec.rb": 0.061399015, + "spec/controllers/idv/doc_auth_controller_spec.rb": 0.7707043379999999, + "spec/controllers/idv/document_capture_controller_spec.rb": 0.32428111, + "spec/controllers/idv/forgot_password_controller_spec.rb": 0.28287656099999997, + "spec/controllers/idv/gpo_controller_spec.rb": 1.037941323, + "spec/controllers/idv/gpo_verify_controller_spec.rb": 1.390012413, + "spec/controllers/idv/image_uploads_controller_spec.rb": 1.319783393, + "spec/controllers/idv/in_person/address_search_controller_spec.rb": 0.22545855199999998, + "spec/controllers/idv/in_person/ready_to_verify_controller_spec.rb": 0.180886167, + "spec/controllers/idv/in_person/usps_locations_controller_spec.rb": 0.450196962, + "spec/controllers/idv/in_person/verify_info_controller_spec.rb": 0.477626004, + "spec/controllers/idv/in_person_controller_spec.rb": 0.402102335, + "spec/controllers/idv/not_verified_controller_spec.rb": 0.036425387, + "spec/controllers/idv/otp_verification_controller_spec.rb": 0.244264492, + "spec/controllers/idv/personal_key_controller_spec.rb": 1.8358741619999999, + "spec/controllers/idv/phone_controller_spec.rb": 1.566826773, + "spec/controllers/idv/phone_errors_controller_spec.rb": 0.953970671, + "spec/controllers/idv/please_call_controller_spec.rb": 0.084055039, + "spec/controllers/idv/resend_otp_controller_spec.rb": 0.115737306, + "spec/controllers/idv/review_controller_spec.rb": 5.810555222, + "spec/controllers/idv/session_errors_controller_spec.rb": 1.489943436, + "spec/controllers/idv/sessions_controller_spec.rb": 0.316428684, + "spec/controllers/idv/ssn_controller_spec.rb": 0.501697239, + "spec/controllers/idv/unavailable_controller_spec.rb": 0.106648676, + "spec/controllers/idv/verify_info_controller_spec.rb": 0.896669286, + "spec/controllers/idv_controller_spec.rb": 0.432986416, + "spec/controllers/mfa_confirmation_controller_spec.rb": 0.295023469, + "spec/controllers/no_js_controller_spec.rb": 0.032611193, + "spec/controllers/openid_connect/authorization_controller_spec.rb": 1.303357646, + "spec/controllers/openid_connect/certs_controller_spec.rb": 0.024612279, + "spec/controllers/openid_connect/configuration_controller_spec.rb": 0.022582953000000003, + "spec/controllers/openid_connect/logout_controller_spec.rb": 1.126554493, + "spec/controllers/openid_connect/token_controller_spec.rb": 0.196184474, + "spec/controllers/openid_connect/user_info_controller_spec.rb": 0.176545058, + "spec/controllers/pages_controller_spec.rb": 0.07820936, + "spec/controllers/password_capture_controller_spec.rb": 0.10005012299999999, + "spec/controllers/reactivate_account_controller_spec.rb": 0.153951747, + "spec/controllers/redirect/contact_controller_spec.rb": 0.028664921, + "spec/controllers/redirect/help_center_controller_spec.rb": 0.08361238, + "spec/controllers/redirect/policy_controller_spec.rb": 0.015941174, + "spec/controllers/redirect/return_to_sp_controller_spec.rb": 0.100976527, + "spec/controllers/risc/configuration_controller_spec.rb": 0.014231443, + "spec/controllers/risc/security_events_controller_spec.rb": 0.598680498, + "spec/controllers/saml_completion_controller_spec.rb": 0.04809786, + "spec/controllers/saml_idp_controller_spec.rb": 10.502273236, + "spec/controllers/saml_post_controller_spec.rb": 0.026114579, + "spec/controllers/saml_signed_message_spec.rb": 0.440552398, + "spec/controllers/service_provider_controller_spec.rb": 0.091931371, + "spec/controllers/sign_out_controller_spec.rb": 0.059610685000000004, + "spec/controllers/sign_up/cancellations_controller_spec.rb": 0.340604805, + "spec/controllers/sign_up/completions_controller_spec.rb": 0.716640834, + "spec/controllers/sign_up/email_confirmations_controller_spec.rb": 0.199802754, + "spec/controllers/sign_up/emails_controller_spec.rb": 0.020562414, + "spec/controllers/sign_up/passwords_controller_spec.rb": 0.153737338, + "spec/controllers/sign_up/registrations_controller_spec.rb": 1.003662417, + "spec/controllers/test/device_profiling_controller_spec.rb": 0.029727224, + "spec/controllers/test/piv_cac_authentication_test_subject_controller_spec.rb": 0.066411684, + "spec/controllers/test/push_notification_controller_spec.rb": 0.037275222, + "spec/controllers/test/telephony_controller_spec.rb": 0.034129193, + "spec/controllers/two_factor_authentication/backup_code_verification_controller_spec.rb": 0.617542073, + "spec/controllers/two_factor_authentication/options_controller_spec.rb": 0.386797851, + "spec/controllers/two_factor_authentication/otp_expired_controller_spec.rb": 0.27893086500000003, + "spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb": 2.893660196, + "spec/controllers/two_factor_authentication/personal_key_verification_controller_spec.rb": 0.824157819, + "spec/controllers/two_factor_authentication/piv_cac_verification_controller_spec.rb": 0.839421281, + "spec/controllers/two_factor_authentication/sms_opt_in_controller_spec.rb": 0.626459143, + "spec/controllers/two_factor_authentication/totp_verification_controller_spec.rb": 0.614282958, + "spec/controllers/two_factor_authentication/webauthn_verification_controller_spec.rb": 0.356852901, + "spec/controllers/users/authorization_confirmation_controller_spec.rb": 0.145457812, + "spec/controllers/users/backup_code_setup_controller_spec.rb": 2.125878679, + "spec/controllers/users/delete_controller_spec.rb": 0.600356157, + "spec/controllers/users/edit_phone_controller_spec.rb": 0.192218183, + "spec/controllers/users/email_confirmations_controller_spec.rb": 1.460684717, + "spec/controllers/users/email_language_controller_spec.rb": 0.212705772, + "spec/controllers/users/emails_controller_spec.rb": 0.586191456, + "spec/controllers/users/forget_all_browsers_controller_spec.rb": 0.184442002, + "spec/controllers/users/mfa_selection_controller_spec.rb": 0.332298961, + "spec/controllers/users/passwords_controller_spec.rb": 1.314142275, + "spec/controllers/users/personal_keys_controller_spec.rb": 0.306624967, + "spec/controllers/users/phone_setup_controller_spec.rb": 0.270372402, + "spec/controllers/users/phones_controller_spec.rb": 0.326525417, + "spec/controllers/users/piv_cac_authentication_setup_controller_spec.rb": 0.770934656, + "spec/controllers/users/reset_passwords_controller_spec.rb": 2.195733769, + "spec/controllers/users/rules_of_use_controller_spec.rb": 0.42946418, + "spec/controllers/users/service_provider_revoke_controller_spec.rb": 0.402157388, + "spec/controllers/users/sessions_controller_spec.rb": 1.653365633, + "spec/controllers/users/totp_setup_controller_spec.rb": 3.959273352, + "spec/controllers/users/two_factor_authentication_controller_spec.rb": 1.941067333, + "spec/controllers/users/two_factor_authentication_setup_controller_spec.rb": 0.311643449, + "spec/controllers/users/verify_password_controller_spec.rb": 0.471758447, + "spec/controllers/users/verify_personal_key_controller_spec.rb": 0.774642238, + "spec/controllers/users/webauthn_setup_controller_spec.rb": 0.678193085, + "spec/controllers/vendor_outage_controller_spec.rb": 0.041163561, + "spec/decorators/device_decorator_spec.rb": 0.038917785999999996, + "spec/decorators/email_context_spec.rb": 0.050924115, + "spec/decorators/event_decorator_spec.rb": 0.110334059, + "spec/decorators/mfa_context_spec.rb": 0.909110676, + "spec/decorators/service_provider_session_decorator_spec.rb": 0.34307433, + "spec/decorators/session_decorator_spec.rb": 0.044499213, + "spec/decorators/user_decorator_spec.rb": 1.102677904, + "spec/features/accessibility/idv_pages_spec.rb": 165.375981848, + "spec/features/accessibility/static_pages_spec.rb": 110.254003334, + "spec/features/accessibility/user_pages_spec.rb": 285.58769503999997, + "spec/features/accessibility/visitor_pages_spec.rb": 63.034958193, + "spec/features/account/backup_codes_spec.rb": 17.914824163, + "spec/features/account/device_spec.rb": 3.196686714, + "spec/features/account/unphishable_badge_spec.rb": 6.3247692, + "spec/features/account_connected_apps_spec.rb": 6.903688739, + "spec/features/account_creation/multiple_browsers_spec.rb": 16.855496967, + "spec/features/account_creation/sp_return_log_spec.rb": 4.56924897, + "spec/features/account_email_language_spec.rb": 10.139567911, + "spec/features/account_history_spec.rb": 3.330966708, + "spec/features/account_reset/cancel_request_spec.rb": 4.739523311, + "spec/features/account_reset/delete_account_spec.rb": 17.839138194, + "spec/features/account_reset/pending_request_spec.rb": 5.006512109, + "spec/features/device_tracking_spec.rb": 6.473703227, + "spec/features/event_disavowal_spec.rb": 42.21487633, + "spec/features/ialmax/saml_sign_in_spec.rb": 27.437746482999998, + "spec/features/idv/account_creation_spec.rb": 51.378506317, + "spec/features/idv/actions/cancel_link_sent_action_spec.rb": 4.458647413, + "spec/features/idv/actions/redo_document_capture_action_spec.rb": 20.62188384, + "spec/features/idv/analytics_spec.rb": 27.190867567, + "spec/features/idv/cancel_spec.rb": 24.771272547, + "spec/features/idv/clearing_and_restarting_spec.rb": 69.552144226, + "spec/features/idv/doc_auth/address_step_spec.rb": 38.005462285, + "spec/features/idv/doc_auth/agreement_step_spec.rb": 26.433021312, + "spec/features/idv/doc_auth/document_capture_spec.rb": 51.291508331, + "spec/features/idv/doc_auth/document_capture_step_spec.rb": 50.414096529, + "spec/features/idv/doc_auth/email_sent_step_spec.rb": 3.80092589, + "spec/features/idv/doc_auth/link_sent_step_spec.rb": 4.283712103, + "spec/features/idv/doc_auth/ssn_step_spec.rb": 10.641385753, + "spec/features/idv/doc_auth/test_credentials_spec.rb": 9.99784889, + "spec/features/idv/doc_auth/upload_step_spec.rb": 51.863814609, + "spec/features/idv/doc_auth/verify_info_step_spec.rb": 123.835049723, + "spec/features/idv/doc_auth/welcome_step_spec.rb": 16.895202564999998, + "spec/features/idv/doc_capture/capture_complete_step_spec.rb": 5.132482017, + "spec/features/idv/doc_capture/document_capture_step_spec.rb": 68.258863793, + "spec/features/idv/gpo_disabled_spec.rb": 10.503912021, + "spec/features/idv/hybrid_flow_spec.rb": 23.181832478, + "spec/features/idv/in_person_spec.rb": 131.519424948, + "spec/features/idv/outage_spec.rb": 107.678846404, + "spec/features/idv/phone_input_spec.rb": 12.194582901, + "spec/features/idv/phone_otp_rate_limiting_spec.rb": 25.290264875, + "spec/features/idv/proofing_components_spec.rb": 44.572364813, + "spec/features/idv/sp_handoff_spec.rb": 127.326103007, + "spec/features/idv/sp_requested_attributes_spec.rb": 64.246955222, + "spec/features/idv/steps/confirmation_step_spec.rb": 34.876604572, + "spec/features/idv/steps/forgot_password_step_spec.rb": 21.736264375, + "spec/features/idv/steps/gpo_otp_verification_step_spec.rb": 89.080326171, + "spec/features/idv/steps/gpo_step_spec.rb": 51.650038832999996, + "spec/features/idv/steps/in_person/verify_info_spec.rb": 9.877270575, + "spec/features/idv/steps/in_person/verify_step_spec.rb": 24.78400964, + "spec/features/idv/steps/phone_otp_verification_step_spec.rb": 27.199549958, + "spec/features/idv/steps/phone_step_spec.rb": 195.75975706, + "spec/features/idv/steps/review_step_spec.rb": 44.360843345, + "spec/features/idv/threatmetrix_pending_spec.rb": 49.221405527, + "spec/features/idv/uak_password_spec.rb": 7.902013181, + "spec/features/irs_attempts_api/event_tracking_spec.rb": 25.354044524, + "spec/features/legacy_passwords_spec.rb": 13.563822508, + "spec/features/load_testing/email_sign_up_spec.rb": 3.467094116, + "spec/features/multi_factor_authentication/mfa_cta_spec.rb": 12.35607854, + "spec/features/multiple_emails/add_email_spec.rb": 58.379324834, + "spec/features/multiple_emails/email_management_spec.rb": 24.978637444, + "spec/features/multiple_emails/reset_password_spec.rb": 7.430474027, + "spec/features/multiple_emails/sign_in_spec.rb": 11.370547192, + "spec/features/multiple_emails/sp_sign_in_spec.rb": 17.396392849999998, + "spec/features/new_device_tracking_spec.rb": 10.381174502, + "spec/features/openid_connect/authorization_confirmation_spec.rb": 20.179389722, + "spec/features/openid_connect/openid_connect_spec.rb": 167.138706858, + "spec/features/openid_connect/phishing_resistant_required_spec.rb": 34.001085309, + "spec/features/openid_connect/redirect_uri_validation_spec.rb": 33.120771518, + "spec/features/phone/add_phone_spec.rb": 37.490217186, + "spec/features/phone/confirmation_spec.rb": 112.67856858100001, + "spec/features/phone/default_phone_selection_spec.rb": 18.725192631, + "spec/features/phone/edit_phone_spec.rb": 9.537593768, + "spec/features/phone/rate_limitting_spec.rb": 54.655647711, + "spec/features/phone/remove_phone_spec.rb": 6.6254866240000005, + "spec/features/remember_device/cookie_expiration_spec.rb": 7.325559522, + "spec/features/remember_device/phone_spec.rb": 40.628021829, + "spec/features/remember_device/revocation_spec.rb": 10.485624767000001, + "spec/features/remember_device/session_expiration_spec.rb": 3.982436988, + "spec/features/remember_device/sp_expiration_spec.rb": 211.766204891, + "spec/features/remember_device/totp_spec.rb": 51.047722848, + "spec/features/remember_device/user_opted_preference_spec.rb": 27.768803937999998, + "spec/features/remember_device/webauthn_spec.rb": 98.560121063, + "spec/features/reports/authorization_count_spec.rb": 71.401482268, + "spec/features/reports/monthly_gpo_letter_requests_report_spec.rb": 12.183763893, + "spec/features/reports/sp_active_users_report_spec.rb": 7.286086294, + "spec/features/saml/authorization_confirmation_spec.rb": 26.150682793, + "spec/features/saml/ial1/account_creation_spec.rb": 10.580017755, + "spec/features/saml/ial1_sso_spec.rb": 51.6018368, + "spec/features/saml/ial2_sso_spec.rb": 27.535485615, + "spec/features/saml/multiple_endpoints_spec.rb": 25.400298174, + "spec/features/saml/phishing_resistant_required_spec.rb": 23.513348885, + "spec/features/saml/redirect_uri_validation_spec.rb": 3.942279306, + "spec/features/saml/saml_logout_spec.rb": 24.157208545, + "spec/features/saml/saml_relay_state_spec.rb": 15.093978083, + "spec/features/saml/saml_spec.rb": 110.60438054, + "spec/features/session/decryption_spec.rb": 3.256941234, + "spec/features/session/timeout_spec.rb": 9.471305588, + "spec/features/sign_in/banned_users_spec.rb": 12.129006181, + "spec/features/sign_in/remember_device_default_spec.rb": 10.069318299, + "spec/features/sign_in/sp_return_log_spec.rb": 3.733718778, + "spec/features/sign_in/two_factor_options_spec.rb": 47.745540653, + "spec/features/sp_cost_tracking_spec.rb": 50.783324199, + "spec/features/two_factor_authentication/backup_code_sign_up_spec.rb": 24.584182124, + "spec/features/two_factor_authentication/change_factor_spec.rb": 17.24585893, + "spec/features/two_factor_authentication/multiple_mfa_sign_up_spec.rb": 16.010188449, + "spec/features/two_factor_authentication/multiple_tabs_spec.rb": 11.373113592, + "spec/features/two_factor_authentication/sign_in_spec.rb": 121.83629427, + "spec/features/two_factor_authentication/sign_in_via_personal_key_spec.rb": 7.321116241, + "spec/features/users/password_recovery_via_recovery_code_spec.rb": 46.964656765, + "spec/features/users/password_reset_with_pending_profile_spec.rb": 7.237078065, + "spec/features/users/piv_cac_management_spec.rb": 30.668030266, + "spec/features/users/regenerate_personal_key_spec.rb": 8.987526887000001, + "spec/features/users/sign_in_irs_spec.rb": 30.884822841, + "spec/features/users/sign_in_spec.rb": 422.649588344, + "spec/features/users/sign_out_spec.rb": 3.43708553, + "spec/features/users/sign_up_spec.rb": 128.386760477, + "spec/features/users/totp_management_spec.rb": 19.133432851000002, + "spec/features/users/user_edit_spec.rb": 3.314308614, + "spec/features/users/user_profile_spec.rb": 41.618690916, + "spec/features/users/verify_profile_spec.rb": 14.688483096, + "spec/features/visitors/bad_password_spec.rb": 3.622186752, + "spec/features/visitors/email_confirmation_spec.rb": 22.196911488, + "spec/features/visitors/i18n_spec.rb": 38.847907676, + "spec/features/visitors/js_disabled_spec.rb": 6.339618132, + "spec/features/visitors/navigation_spec.rb": 4.181874004, + "spec/features/visitors/password_recovery_spec.rb": 66.583101644, + "spec/features/visitors/resend_email_confirmation_spec.rb": 17.253549811, + "spec/features/visitors/set_password_spec.rb": 30.015697064, + "spec/features/visitors/sign_up_with_email_spec.rb": 31.534222514, + "spec/features/webauthn/hidden_spec.rb": 24.227415872999998, + "spec/features/webauthn/management_spec.rb": 53.624379184, + "spec/features/webauthn/sign_in_spec.rb": 10.879400402, + "spec/features/webauthn/sign_up_spec.rb": 14.691343386, + "spec/forms/add_user_email_form_spec.rb": 0.5456360140000001, + "spec/forms/api/verify/document_capture_errors_delete_form_spec.rb": 0.031662077999999996, + "spec/forms/delete_user_email_form_spec.rb": 0.302865236, + "spec/forms/edit_phone_form_spec.rb": 0.227426358, + "spec/forms/event_disavowal/password_reset_from_disavowal_form_spec.rb": 0.817841122, + "spec/forms/gpo_verify_form_spec.rb": 1.131057832, + "spec/forms/idv/api_document_verification_form_spec.rb": 0.178082758, + "spec/forms/idv/api_document_verification_status_form_spec.rb": 0.142448794, + "spec/forms/idv/api_image_upload_form_spec.rb": 1.139435361, + "spec/forms/idv/doc_pii_form_spec.rb": 0.059271565, + "spec/forms/idv/phone_confirmation_otp_verification_form_spec.rb": 0.183517877, + "spec/forms/idv/phone_form_spec.rb": 0.95947762, + "spec/forms/idv/ssn_form_spec.rb": 0.154520826, + "spec/forms/idv/ssn_format_form_spec.rb": 0.072979816, + "spec/forms/new_phone_form_spec.rb": 2.031037458, + "spec/forms/openid_connect_authorize_form_spec.rb": 0.596742651, + "spec/forms/openid_connect_logout_form_spec.rb": 0.714093112, + "spec/forms/openid_connect_token_form_spec.rb": 1.913807907, + "spec/forms/otp_delivery_selection_form_spec.rb": 0.127123852, + "spec/forms/otp_verification_form_spec.rb": 0.199160617, + "spec/forms/password_form_spec.rb": 1.188525368, + "spec/forms/password_reset_email_form_spec.rb": 0.076759054, + "spec/forms/personal_key_form_spec.rb": 0.06633077400000001, + "spec/forms/register_user_email_form_spec.rb": 3.041947124, + "spec/forms/reset_password_form_spec.rb": 1.054730842, + "spec/forms/security_event_form_spec.rb": 2.542158474, + "spec/forms/totp_setup_form_spec.rb": 0.156456089, + "spec/forms/totp_verification_form_spec.rb": 0.058561933999999996, + "spec/forms/two_factor_authentication/phone_deletion_form_spec.rb": 0.449122586, + "spec/forms/two_factor_login_options_form_spec.rb": 0.09582588, + "spec/forms/two_factor_options_form_spec.rb": 0.243800354, + "spec/forms/update_email_language_form_spec.rb": 0.083828612, + "spec/forms/update_user_password_form_spec.rb": 0.926201858, + "spec/forms/user_piv_cac_login_form_spec.rb": 0.047058057, + "spec/forms/user_piv_cac_setup_form_spec.rb": 0.185118188, + "spec/forms/user_piv_cac_verification_form_spec.rb": 0.135310388, + "spec/forms/verify_password_form_spec.rb": 0.12722292500000001, + "spec/forms/verify_personal_key_form_spec.rb": 0.239359002, + "spec/forms/webauthn_setup_form_spec.rb": 0.138091492, + "spec/forms/webauthn_verification_form_spec.rb": 0.226542362, + "spec/forms/webauthn_visit_form_spec.rb": 0.141763644, + "spec/helpers/application_helper_spec.rb": 0.021086988, + "spec/helpers/asset_helper_spec.rb": 0.01549042, + "spec/helpers/aws_s3_helper_spec.rb": 0.091065602, + "spec/helpers/go_back_helper_spec.rb": 0.055581522, + "spec/helpers/link_helper_spec.rb": 0.089029812, + "spec/helpers/locale_helper_spec.rb": 0.087239343, + "spec/helpers/script_helper_spec.rb": 0.085423074, + "spec/helpers/session_timeout_warning_helper_spec.rb": 0.060790384, + "spec/i18n_spec.rb": 50.702802539, + "spec/jobs/address_proofing_job_spec.rb": 0.192242415, + "spec/jobs/application_job_spec.rb": 0.007564081, + "spec/jobs/document_proofing_job_spec.rb": 0.559700526, + "spec/jobs/fraud_rejection_daily_job_spec.rb": 0.079938747, + "spec/jobs/get_usps_proofing_results_job_spec.rb": 7.843321775, + "spec/jobs/gpo_daily_job_spec.rb": 0.104095852, + "spec/jobs/heartbeat_job_spec.rb": 0.014237247, + "spec/jobs/in_person/email_reminder_job_spec.rb": 0.877686566, + "spec/jobs/irs_attempts_events_batch_job_spec.rb": 3.639189138, + "spec/jobs/job_helpers/encryption_helper_spec.rb": 0.01002906, + "spec/jobs/job_helpers/s3_helper_spec.rb": 0.167022335, + "spec/jobs/job_helpers/stale_job_helper_spec.rb": 0.02858227, + "spec/jobs/job_helpers/timer_spec.rb": 0.0214543, + "spec/jobs/phone_number_opt_out_sync_job_spec.rb": 0.047666838, + "spec/jobs/reports/agreement_summary_report_spec.rb": 0.123715904, + "spec/jobs/reports/base_report_spec.rb": 0.037328095, + "spec/jobs/reports/combined_invoice_supplement_report_spec.rb": 0.324706043, + "spec/jobs/reports/daily_auths_report_spec.rb": 0.166715463, + "spec/jobs/reports/daily_dropoffs_report_spec.rb": 0.097023199, + "spec/jobs/reports/daily_registration_report_spec.rb": 0.138372927, + "spec/jobs/reports/deleted_user_accounts_report_spec.rb": 0.090197228, + "spec/jobs/reports/duplicate_ssn_report_spec.rb": 0.10172186400000001, + "spec/jobs/reports/irs_weekly_summary_report_spec.rb": 0.285212858, + "spec/jobs/reports/month_helper_spec.rb": 0.014984619000000001, + "spec/jobs/reports/query_helpers_spec.rb": 0.019143998, + "spec/jobs/reports/sp_active_users_report_spec.rb": 0.071096301, + "spec/jobs/reports/sp_user_counts_report_spec.rb": 0.053266291, + "spec/jobs/reports/total_ial2_costs_report_spec.rb": 0.034394596, + "spec/jobs/reports/total_monthly_auths_report_spec.rb": 0.042859366999999995, + "spec/jobs/reports/verification_failures_report_spec.rb": 0.477205394, + "spec/jobs/resolution_proofing_job_spec.rb": 0.588646698, + "spec/jobs/risc_delivery_job_spec.rb": 0.169518108, + "spec/jobs/threat_metrix_js_verification_job_spec.rb": 0.981613087, + "spec/lib/ab_test_bucket_spec.rb": 0.061471894, + "spec/lib/analytics_events_documenter_spec.rb": 0.190323129, + "spec/lib/app_artifacts_spec.rb": 0.048736892, + "spec/lib/asset_sources_spec.rb": 0.112079159, + "spec/lib/aws/ses_spec.rb": 0.037517965, + "spec/lib/base16_spec.rb": 0.026916704, + "spec/lib/data_requests/deployed/create_email_addresses_report_spec.rb": 0.02253286, + "spec/lib/data_requests/deployed/create_mfa_configurations_report_spec.rb": 0.117324761, + "spec/lib/data_requests/deployed/create_user_events_report_spec.rb": 0.048524675, + "spec/lib/data_requests/deployed/create_user_report_spec.rb": 0.09963783600000001, + "spec/lib/data_requests/deployed/lookup_shared_device_users_spec.rb": 0.050149732, + "spec/lib/data_requests/deployed/lookup_user_by_uuid_spec.rb": 0.057556582, + "spec/lib/data_requests/local/fetch_cloudwatch_logs_spec.rb": 0.037973312, + "spec/lib/data_requests/local/write_cloudwatch_logs_spec.rb": 0.028919119, + "spec/lib/data_requests/local/write_user_events_spec.rb": 0.009915095, + "spec/lib/data_requests/local/write_user_info_spec.rb": 0.009470691, + "spec/lib/deploy/activate_spec.rb": 0.13826028099999998, + "spec/lib/feature_management_spec.rb": 0.397662774, + "spec/lib/fingerprinter_spec.rb": 0.015419853, + "spec/lib/good_job_connection_pool_size_spec.rb": 0.036179908999999996, + "spec/lib/headers_filter_spec.rb": 0.008766337, + "spec/lib/identity_config_spec.rb": 0.025962357, + "spec/lib/identity_cors_spec.rb": 0.024493265, + "spec/lib/identity_job_log_subscriber_spec.rb": 0.164736772, + "spec/lib/linters/errors_add_linter_spec.rb": 0.04352469, + "spec/lib/linters/image_size_linter_spec.rb": 0.085625468, + "spec/lib/linters/localized_validation_message_linter_spec.rb": 0.092063957, + "spec/lib/linters/mail_later_linter_spec.rb": 0.077226566, + "spec/lib/linters/redirect_back_linter_spec.rb": 0.076755621, + "spec/lib/linters/url_options_linter_spec.rb": 0.095077736, + "spec/lib/makefile_help_parser_spec.rb": 0.080842259, + "spec/lib/otp_code_generator_spec.rb": 0.03034179, + "spec/lib/pinpoint_supported_countries_spec.rb": 0.119058425, + "spec/lib/query_tracker_spec.rb": 0.035661485, + "spec/lib/reporting/authentication_report_spec.rb": 0.010312284, + "spec/lib/reporting/cloudwatch_client_spec.rb": 1.020889211, + "spec/lib/reporting/cloudwatch_query_quoting_spec.rb": 0.016911478, + "spec/lib/reporting/command_line_options_spec.rb": 0.051185253, + "spec/lib/reporting/identity_verification_report_spec.rb": 0.014863927999999998, + "spec/lib/session_encryptor_spec.rb": 0.090182567, + "spec/lib/tasks/dev_rake_spec.rb": 12.508507087, + "spec/lib/tasks/partners_rake_spec.rb": 0.902318065, + "spec/lib/tasks/review_profile_spec.rb": 1.1079302340000001, + "spec/lib/tasks/rotate_rake_spec.rb": 0.30446941899999996, + "spec/lib/telephony/alert_sender_spec.rb": 0.067202754, + "spec/lib/telephony/otp_sender_spec.rb": 0.209770442, + "spec/lib/telephony/pinpoint/aws_credential_builder_spec.rb": 0.028222088, + "spec/lib/telephony/pinpoint/opt_out_manager_spec.rb": 0.10640153299999999, + "spec/lib/telephony/pinpoint/sms_sender_spec.rb": 0.211558586, + "spec/lib/telephony/pinpoint/voice_sender_spec.rb": 0.097395808, + "spec/lib/telephony/response_spec.rb": 0.042006122, + "spec/lib/telephony/telephony_spec.rb": 0.078356267, + "spec/lib/telephony/test/call_spec.rb": 0.068570091, + "spec/lib/telephony/test/message_spec.rb": 0.043978130000000004, + "spec/lib/telephony/test/sms_sender_spec.rb": 0.045974666, + "spec/lib/telephony/test/voice_sender_spec.rb": 0.022395638000000002, + "spec/lib/telephony/util_spec.rb": 0.007113312, + "spec/lib/utf8_sanitizer_spec.rb": 0.059890347000000003, + "spec/mailers/previews/user_mailer_preview_spec.rb": 0.292095632, + "spec/mailers/report_mailer_spec.rb": 0.10244007399999999, + "spec/mailers/user_mailer_spec.rb": 3.676390663, + "spec/models/account_reset_request_spec.rb": 0.057218896, + "spec/models/agency_identity_spec.rb": 0.030335927999999998, + "spec/models/agency_spec.rb": 0.046644419, + "spec/models/agreements/iaa_gtc_spec.rb": 0.306059918, + "spec/models/agreements/iaa_order_spec.rb": 0.470808725, + "spec/models/agreements/iaa_spec.rb": 0.245824153, + "spec/models/agreements/integration_spec.rb": 0.34108569, + "spec/models/agreements/integration_status_spec.rb": 0.06724306000000001, + "spec/models/agreements/integration_usage_spec.rb": 0.26668758, + "spec/models/agreements/partner_account_spec.rb": 0.170270273, + "spec/models/agreements/partner_account_status_spec.rb": 0.083461415, + "spec/models/anonymous_user_spec.rb": 0.039631976, + "spec/models/backup_code_configuration_spec.rb": 1.294288719, + "spec/models/concerns/user_otp_methods_spec.rb": 0.00950226, + "spec/models/deleted_user_spec.rb": 0.079463014, + "spec/models/device_spec.rb": 0.086995835, + "spec/models/document_capture_session_spec.rb": 0.072794356, + "spec/models/email_address_spec.rb": 0.207938978, + "spec/models/event_spec.rb": 0.041311343, + "spec/models/gpo_confirmation_code_spec.rb": 0.127433969, + "spec/models/in_person_enrollment_spec.rb": 1.028460284, + "spec/models/null_identity_spec.rb": 0.007449214, + "spec/models/phone_configuration_spec.rb": 0.134042061, + "spec/models/phone_number_opt_out_spec.rb": 0.132228465, + "spec/models/profile_spec.rb": 1.922392905, + "spec/models/service_provider_identity_spec.rb": 0.443261182, + "spec/models/service_provider_spec.rb": 0.097290375, + "spec/models/sp_return_log_spec.rb": 0.009612778, + "spec/models/user_spec.rb": 2.071524169, + "spec/models/webauthn_configuration_spec.rb": 0.160580897, + "spec/policies/backup_code_policy_spec.rb": 0.047170202, + "spec/policies/service_provider_mfa_policy_spec.rb": 1.056282868, + "spec/policies/two_factor_authentication/piv_cac_policy_spec.rb": 0.070412291, + "spec/policies/user_mfa_policy_spec.rb": 0.199092249, + "spec/policies/webauthn_login_option_policy_spec.rb": 0.07133541, + "spec/presenters/account_reset/pending_presenter_spec.rb": 0.143367138, + "spec/presenters/account_show_presenter_spec.rb": 0.177017309, + "spec/presenters/cancellation_presenter_spec.rb": 0.030601714, + "spec/presenters/completions_presenter_spec.rb": 0.563997295, + "spec/presenters/confirm_delete_email_presenter_spec.rb": 0.021897057, + "spec/presenters/eastern_time_presenter_spec.rb": 0.007312063, + "spec/presenters/idv/cancellations_presenter_spec.rb": 0.042703547, + "spec/presenters/idv/gpo_presenter_spec.rb": 0.27275645, + "spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb": 0.378023641, + "spec/presenters/idv/in_person/verification_results_email_presenter_spec.rb": 0.491749575, + "spec/presenters/image_upload_response_presenter_spec.rb": 0.111157361, + "spec/presenters/max_attempts_reached_presenter_spec.rb": 0.02859288, + "spec/presenters/mfa_confirmation_presenter_spec.rb": 0.055629244, + "spec/presenters/navigation_presenter_spec.rb": 0.128845831, + "spec/presenters/openid_connect_certs_presenter_spec.rb": 0.00879459, + "spec/presenters/openid_connect_configuration_presenter_spec.rb": 0.00937257, + "spec/presenters/openid_connect_user_info_presenter_spec.rb": 0.50639289, + "spec/presenters/piv_cac_authentication_setup_presenter_spec.rb": 0.052806555, + "spec/presenters/piv_cac_error_presenter_spec.rb": 0.029971705, + "spec/presenters/risc_configuration_presenter_spec.rb": 0.007505527, + "spec/presenters/saml_request_presenter_spec.rb": 0.038690222, + "spec/presenters/session_timeout_modal_presenter_spec.rb": 0.014778803, + "spec/presenters/setup_presenter_spec.rb": 0.079369594, + "spec/presenters/two_factor_auth_code/authenticator_delivery_presenter_spec.rb": 0.028849325, + "spec/presenters/two_factor_auth_code/backup_code_presenter_spec.rb": 0.032277671, + "spec/presenters/two_factor_auth_code/generic_delivery_presenter_spec.rb": 0.007990885, + "spec/presenters/two_factor_auth_code/personal_key_presenter_spec.rb": 0.014080891, + "spec/presenters/two_factor_auth_code/phone_delivery_presenter_spec.rb": 0.070801363, + "spec/presenters/two_factor_auth_code/piv_cac_authentication_presenter_spec.rb": 0.122388517, + "spec/presenters/two_factor_auth_code/webauthn_authentication_presenter_spec.rb": 0.149058269, + "spec/presenters/two_factor_authentication/auth_app_selection_presenter_spec.rb": 0.057092587, + "spec/presenters/two_factor_authentication/personal_key_selection_presenter_spec.rb": 0.006362566, + "spec/presenters/two_factor_authentication/phone_selection_presenter_spec.rb": 0.147669572, + "spec/presenters/two_factor_authentication/piv_cac_selection_presenter_spec.rb": 0.066833743, + "spec/presenters/two_factor_authentication/selection_presenter_spec.rb": 0.035486058, + "spec/presenters/two_factor_authentication/sms_selection_presenter_spec.rb": 0.078822224, + "spec/presenters/two_factor_authentication/voice_selection_presenter_spec.rb": 0.105602242, + "spec/presenters/two_factor_authentication/webauthn_platform_selection_presenter_spec.rb": 0.104484259, + "spec/presenters/two_factor_authentication/webauthn_selection_presenter_spec.rb": 0.078740212, + "spec/presenters/two_factor_login_options_presenter_spec.rb": 0.175141757, + "spec/presenters/two_factor_options_presenter_spec.rb": 0.051090845999999995, + "spec/presenters/utc_time_presenter_spec.rb": 0.007486452, + "spec/presenters/webauthn_setup_presenter_spec.rb": 0.222969207, + "spec/requests/acuant_sdk_spec.rb": 0.09939785899999999, + "spec/requests/api_cors_spec.rb": 0.513065068, + "spec/requests/csp_spec.rb": 0.14527948499999999, + "spec/requests/headers_spec.rb": 0.246363634, + "spec/requests/i18n_spec.rb": 0.120136023, + "spec/requests/invalid_encoding_spec.rb": 0.295391124, + "spec/requests/invalid_sign_in_params_spec.rb": 0.09459721900000001, + "spec/requests/not_acceptable_spec.rb": 0.094575783, + "spec/requests/openid_connect_authorize_spec.rb": 0.751280258, + "spec/requests/openid_connect_cors_spec.rb": 0.538410748, + "spec/requests/page_not_found_spec.rb": 0.130961063, + "spec/requests/rack_attack_spec.rb": 6.875212267999999, + "spec/requests/redirects_spec.rb": 0.17369221699999998, + "spec/requests/redis_down_spec.rb": 0.037052368, + "spec/requests/saml_requests_spec.rb": 0.088256373, + "spec/requests/secure_cookies_spec.rb": 0.10017601500000001, + "spec/routing/gpo_verification_routing_spec.rb": 0.279416249, + "spec/scripts/changelog_check_spec.rb": 0.091737529, + "spec/services/access_token_verifier_spec.rb": 0.07655946500000001, + "spec/services/account_reset/cancel_request_for_user_spec.rb": 0.463988287, + "spec/services/account_reset/cancel_spec.rb": 1.169718978, + "spec/services/account_reset/create_request_spec.rb": 0.684636089, + "spec/services/account_reset/delete_account_spec.rb": 0.606466707, + "spec/services/account_reset/find_prending_request_for_user_spec.rb": 0.115164372, + "spec/services/account_reset/grant_request_spec.rb": 0.031229465, + "spec/services/account_reset/grant_requests_and_send_emails_spec.rb": 1.328006576, + "spec/services/account_reset/notify_user_of_request_cancellation_spec.rb": 0.62713688, + "spec/services/account_reset/validate_granted_token_spec.rb": 0.040424776, + "spec/services/active_profile_encryptor_spec.rb": 0.05254814, + "spec/services/agency_identity_linker_spec.rb": 0.40137527, + "spec/services/agency_seeder_spec.rb": 0.062155219, + "spec/services/agreements/iaa_gtc_seeder_spec.rb": 0.045117687000000004, + "spec/services/agreements/iaa_order_seeder_spec.rb": 0.077702734, + "spec/services/agreements/integration_seeder_spec.rb": 0.066703186, + "spec/services/agreements/integration_status_seeder_spec.rb": 0.035570467, + "spec/services/agreements/partner_account_seeder_spec.rb": 0.043904704, + "spec/services/agreements/partner_account_status_seeder_spec.rb": 0.051665759000000006, + "spec/services/analytics_spec.rb": 0.234241117, + "spec/services/arcgis_api/geocoder_spec.rb": 0.41724231700000003, + "spec/services/attribute_asserter_spec.rb": 1.546701598, + "spec/services/backup_code_generator_spec.rb": 1.479039338, + "spec/services/banned_user_resolver_spec.rb": 0.136806634, + "spec/services/barcode_outputter_spec.rb": 0.018576909, + "spec/services/browser_cache_spec.rb": 0.021734859, + "spec/services/browser_support_spec.rb": 0.093884178, + "spec/services/calendar_service_spec.rb": 0.122989104, + "spec/services/cloud_front_header_parser_spec.rb": 0.0319161, + "spec/services/completions_decider_spec.rb": 0.051105304000000004, + "spec/services/database_health_checker_spec.rb": 0.021446327, + "spec/services/date_parser_spec.rb": 0.037658146, + "spec/services/db/add_document_verification_and_selfie_costs_spec.rb": 0.042534051, + "spec/services/db/identity/sp_active_user_counts_spec.rb": 0.07088024, + "spec/services/db/identity/sp_user_counts_spec.rb": 0.029031567, + "spec/services/db/monthly_auth_count/total_monthly_auth_counts_spec.rb": 0.045848539, + "spec/services/db/monthly_sp_auth_count/total_monthly_auth_counts_within_iaa_window_spec.rb": 0.11222610699999999, + "spec/services/db/monthly_sp_auth_count/unique_monthly_auth_counts_by_iaa_spec.rb": 0.160131191, + "spec/services/db/sp_return_log_spec.rb": 0.013286332, + "spec/services/deleted_accounts_report_spec.rb": 0.157554418, + "spec/services/displayable_pii_formatter_spec.rb": 0.879316827, + "spec/services/doc_auth/acuant/acuant_client_spec.rb": 0.301843504, + "spec/services/doc_auth/acuant/pii_from_doc_spec.rb": 0.030922839, + "spec/services/doc_auth/acuant/request_spec.rb": 0.558747325, + "spec/services/doc_auth/acuant/requests/create_document_request_spec.rb": 0.074538876, + "spec/services/doc_auth/acuant/requests/get_results_request_spec.rb": 0.07982211, + "spec/services/doc_auth/acuant/requests/upload_image_request_spec.rb": 0.072700706, + "spec/services/doc_auth/acuant/responses/create_document_response_spec.rb": 0.009226863, + "spec/services/doc_auth/acuant/responses/get_results_response_spec.rb": 0.126992819, + "spec/services/doc_auth/acuant/result_codes_spec.rb": 0.015058334, + "spec/services/doc_auth/error_generator_spec.rb": 0.169202135, + "spec/services/doc_auth/lexis_nexis/lexis_nexis_client_spec.rb": 0.330498073, + "spec/services/doc_auth/lexis_nexis/request_spec.rb": 0.547362534, + "spec/services/doc_auth/lexis_nexis/requests/true_id_request_spec.rb": 0.105806142, + "spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb": 0.503873076, + "spec/services/doc_auth/mock/dock_auth_mock_client_spec.rb": 0.091080398, + "spec/services/doc_auth/mock/result_response_spec.rb": 0.117753533, + "spec/services/doc_auth/processed_alert_to_log_alert_formatter_spec.rb": 0.018258746, + "spec/services/doc_auth/response_spec.rb": 0.128130091, + "spec/services/doc_auth_router_spec.rb": 0.095799855, + "spec/services/document_capture_session_async_result_spec.rb": 0.049821769, + "spec/services/document_capture_session_result_spec.rb": 0.008328064, + "spec/services/duration_parser_spec.rb": 0.072267957, + "spec/services/email_confirmation_token_validator_spec.rb": 0.161345248, + "spec/services/encrypted_attribute_spec.rb": 0.039945239, + "spec/services/encrypted_document_storage/document_writer_spec.rb": 0.05515934, + "spec/services/encrypted_document_storage/local_storage_spec.rb": 0.006122147, + "spec/services/encrypted_document_storage/s3_storage_spec.rb": 0.011976658, + "spec/services/encrypted_redis_struct_storage_spec.rb": 0.112913095, + "spec/services/encryption/aes_cipher_spec.rb": 0.030430366, + "spec/services/encryption/aes_cipher_v2_spec.rb": 0.023787243, + "spec/services/encryption/contextless_kms_client_spec.rb": 0.148588384, + "spec/services/encryption/encryptors/aes_encryptor_spec.rb": 0.024738347, + "spec/services/encryption/encryptors/aes_encryptor_v2_spec.rb": 0.023045868, + "spec/services/encryption/encryptors/attribute_encryptor_spec.rb": 0.047064122, + "spec/services/encryption/encryptors/background_proofing_arg_encryptor_spec.rb": 0.025864836999999998, + "spec/services/encryption/encryptors/pii_encryptor_spec.rb": 0.092263229, + "spec/services/encryption/encryptors/session_encryptor_spec.rb": 0.023114612, + "spec/services/encryption/kms_client_spec.rb": 0.1873834, + "spec/services/encryption/kms_logger_spec.rb": 0.022014373, + "spec/services/encryption/multi_region_kms_client_spec.rb": 0.081048674, + "spec/services/encryption/password_verifier_spec.rb": 0.10723056, + "spec/services/encryption/uak_password_verifier_spec.rb": 0.250484399, + "spec/services/encryption/user_access_key_spec.rb": 0.084086562, + "spec/services/event_disavowal/disavow_event_spec.rb": 0.025417099, + "spec/services/event_disavowal/find_disavowed_event_spec.rb": 0.062397093, + "spec/services/event_disavowal/validate_disavowed_event_spec.rb": 0.08787130900000001, + "spec/services/forget_all_browsers_spec.rb": 0.020908084, + "spec/services/form_response_spec.rb": 0.194205025, + "spec/services/frontend_logger_spec.rb": 0.018131561, + "spec/services/funnel/registration/add_mfa_spec.rb": 0.038040219, + "spec/services/funnel/registration/total_registered_count_spec.rb": 0.110147248, + "spec/services/gpo_confirmation_exporter_spec.rb": 0.023577765, + "spec/services/gpo_confirmation_maker_spec.rb": 0.180253283, + "spec/services/gpo_confirmation_spec.rb": 0.023930607, + "spec/services/gpo_confirmation_uploader_spec.rb": 0.069140379, + "spec/services/gpo_daily_test_sender_spec.rb": 0.056535775999999996, + "spec/services/health_check_summary_spec.rb": 0.0151433, + "spec/services/iaa_reporting_helper_spec.rb": 0.183439879, + "spec/services/ial_context_spec.rb": 0.464090626, + "spec/services/id_token_builder_spec.rb": 0.334396084, + "spec/services/identity_linker_spec.rb": 0.288367367, + "spec/services/idv/actions/verify_document_status_action_spec.rb": 0.272389584, + "spec/services/idv/agent_spec.rb": 0.419524769, + "spec/services/idv/analytics_events_enhancer_spec.rb": 0.053621465, + "spec/services/idv/cancel_verification_attempt_spec.rb": 0.219316008, + "spec/services/idv/data_url_image_spec.rb": 0.02997306, + "spec/services/idv/doc_auth_form_response_spec.rb": 0.053093869, + "spec/services/idv/duplicate_ssn_finder_spec.rb": 0.222775772, + "spec/services/idv/gpo_mail_spec.rb": 0.124873332, + "spec/services/idv/in_person/completion_survey_sender_spec.rb": 0.674142688, + "spec/services/idv/in_person/enrollment_code_formatter_spec.rb": 0.008019318, + "spec/services/idv/in_person_config_spec.rb": 0.107334034, + "spec/services/idv/phone_confirmation_session_spec.rb": 0.06028332, + "spec/services/idv/phone_step_spec.rb": 0.830866348, + "spec/services/idv/profile_maker_spec.rb": 0.22977045200000001, + "spec/services/idv/proofing_components_logging_spec.rb": 0.021217593, + "spec/services/idv/send_phone_confirmation_otp_spec.rb": 0.191641493, + "spec/services/idv/session_spec.rb": 0.915339425, + "spec/services/idv/steps/document_capture_step_spec.rb": 0.182655802, + "spec/services/idv/steps/in_person/address_step_spec.rb": 0.217891119, + "spec/services/idv/steps/in_person/ssn_step_spec.rb": 0.081506788, + "spec/services/idv/steps/in_person/state_id_step_spec.rb": 0.189685245, + "spec/services/idv/steps/in_person/verify_step_spec.rb": 0.27147140399999997, + "spec/services/idv/steps/in_person/verify_wait_step_show_spec.rb": 0.280391025, + "spec/services/idv/steps/upload_step_spec.rb": 0.052712836, + "spec/services/idv/steps/welcome_step_spec.rb": 0.06748736899999999, + "spec/services/image_upload_presigned_url_generator_spec.rb": 0.024556504, + "spec/services/irs_attempts_api/attempt_event_spec.rb": 1.251784171, + "spec/services/irs_attempts_api/envelope_encryptor_spec.rb": 3.348876783, + "spec/services/irs_attempts_api/redis_client_spec.rb": 0.030896200999999998, + "spec/services/irs_attempts_api/tracker_spec.rb": 0.442496033, + "spec/services/key_rotator/attribute_encryption_spec.rb": 0.076784434, + "spec/services/key_rotator/hmac_fingerprinter_spec.rb": 0.144765468, + "spec/services/maintenance_window_spec.rb": 0.045502836, + "spec/services/marketing_site_spec.rb": 0.242773315, + "spec/services/multi_health_checker_spec.rb": 0.020096313, + "spec/services/openid_connect_attribute_scoper_spec.rb": 0.093507757, + "spec/services/otp_preference_updater_spec.rb": 0.05561098, + "spec/services/otp_rate_limiter_spec.rb": 0.146888721, + "spec/services/out_of_band_session_accessor_spec.rb": 0.035128526, + "spec/services/outage_status_spec.rb": 0.212980414, + "spec/services/outbound_health_checker_spec.rb": 0.1255733, + "spec/services/parse_controller_from_referer_spec.rb": 0.016238258999999998, + "spec/services/personal_key_generator_spec.rb": 0.358131293, + "spec/services/phone_formatter_spec.rb": 0.072818469, + "spec/services/phone_number_capabilities_spec.rb": 0.236355699, + "spec/services/phone_recaptcha_validator_spec.rb": 0.11327219100000001, + "spec/services/pii/attributes_spec.rb": 0.052501571, + "spec/services/pii/cacher_spec.rb": 0.47407567899999997, + "spec/services/pii/fingerprinter_spec.rb": 0.074099072, + "spec/services/pii/re_encryptor_spec.rb": 0.120902764, + "spec/services/piv_cac/check_config_spec.rb": 0.019717316999999998, + "spec/services/piv_cac_service_spec.rb": 0.15460014, + "spec/services/profanity_detector_spec.rb": 0.052402745, + "spec/services/proofing/aamva/applicant_spec.rb": 0.02306904, + "spec/services/proofing/aamva/authentication_client_spec.rb": 0.20816283100000002, + "spec/services/proofing/aamva/hmac_secret_spec.rb": 0.008360152, + "spec/services/proofing/aamva/proofing_spec.rb": 0.24020803100000002, + "spec/services/proofing/aamva/request/authentication_token_request_spec.rb": 0.248799952, + "spec/services/proofing/aamva/request/security_token_request_spec.rb": 1.794116499, + "spec/services/proofing/aamva/request/verification_request_spec.rb": 0.279082606, + "spec/services/proofing/aamva/response/authentication_token_response_spec.rb": 0.057684673, + "spec/services/proofing/aamva/response/security_token_response_spec.rb": 0.095749796, + "spec/services/proofing/aamva/response/verification_response_spec.rb": 0.32805449200000003, + "spec/services/proofing/aamva/soap_error_handler_spec.rb": 0.082296091, + "spec/services/proofing/aamva/verification_client_spec.rb": 0.489217931, + "spec/services/proofing/ddp_result_spec.rb": 0.126256307, + "spec/services/proofing/lexis_nexis/date_formatter_spec.rb": 0.023691009, + "spec/services/proofing/lexis_nexis/ddp/proofing_spec.rb": 0.066945244, + "spec/services/proofing/lexis_nexis/ddp/response_redacter_spec.rb": 0.025849511999999998, + "spec/services/proofing/lexis_nexis/ddp/verification_request_spec.rb": 0.025268374, + "spec/services/proofing/lexis_nexis/instant_verify/check_to_attribute_mapper_spec.rb": 0.052876516, + "spec/services/proofing/lexis_nexis/instant_verify/proofing_spec.rb": 0.195741817, + "spec/services/proofing/lexis_nexis/instant_verify/verification_request_spec.rb": 0.068235424, + "spec/services/proofing/lexis_nexis/phone_finder/proofing_spec.rb": 0.122634362, + "spec/services/proofing/lexis_nexis/phone_finder/verification_request_spec.rb": 0.077633495, + "spec/services/proofing/lexis_nexis/response_spec.rb": 0.063842998, + "spec/services/proofing/lexis_nexis/verification_error_parser_spec.rb": 0.035667648999999996, + "spec/services/proofing/mock/address_mock_client_spec.rb": 0.025629891000000002, + "spec/services/proofing/mock/ddp_mock_client_spec.rb": 0.044225425, + "spec/services/proofing/mock/device_profiling_backend_spec.rb": 0.016206738000000002, + "spec/services/proofing/mock/resolution_mock_client_spec.rb": 0.055217221, + "spec/services/proofing/mock/state_id_mock_client_spec.rb": 0.037586472, + "spec/services/proofing/resolution_result_adjudicator_spec.rb": 0.033485077, + "spec/services/proofing_session_async_result_spec.rb": 0.014494836, + "spec/services/push_notification/account_purged_event_spec.rb": 0.029994371, + "spec/services/push_notification/email_changed_event_spec.rb": 0.02787753, + "spec/services/push_notification/http_push_spec.rb": 0.621945155, + "spec/services/push_notification/identifier_recycled_event_spec.rb": 0.026411327999999998, + "spec/services/push_notification/mfa_limit_account_locked_event_spec.rb": 0.031767904, + "spec/services/push_notification/password_reset_event_spec.rb": 0.027084327, + "spec/services/push_notification/recovery_activated_event_spec.rb": 0.030530783, + "spec/services/push_notification/reproof_completed_event_spec.rb": 0.03078486, + "spec/services/pwned_passwords/lookup_password_spec.rb": 0.01506096, + "spec/services/random_phrase_spec.rb": 0.037123024, + "spec/services/reactivate_account_session_spec.rb": 0.140854031, + "spec/services/recaptcha_mock_validator_spec.rb": 0.038526107, + "spec/services/recaptcha_validator_spec.rb": 0.286191666, + "spec/services/redis_rate_limiter_spec.rb": 0.059155562, + "spec/services/remember_device_cookie_spec.rb": 0.176597241, + "spec/services/request_password_reset_spec.rb": 3.199050218, + "spec/services/reset_user_password_spec.rb": 1.785525947, + "spec/services/revoke_service_provider_consent_spec.rb": 0.03152246, + "spec/services/saml_endpoint_spec.rb": 0.064391223, + "spec/services/saml_request_validator_spec.rb": 0.116813682, + "spec/services/secure_headers_allow_list_spec.rb": 0.035059107, + "spec/services/send_sign_up_email_confirmation_spec.rb": 1.095458277, + "spec/services/service_provider_request_proxy_spec.rb": 0.064112945, + "spec/services/service_provider_seeder_spec.rb": 1.496502392, + "spec/services/service_provider_updater_spec.rb": 0.45303152, + "spec/services/session_encryptor_spec.rb": 0.02276282, + "spec/services/sp_return_url_resolver_spec.rb": 0.089280987, + "spec/services/ssn_formatter_spec.rb": 0.064549527, + "spec/services/store_sp_metadata_in_session_spec.rb": 0.030212393, + "spec/services/string_redacter_spec.rb": 0.007479016, + "spec/services/throttle_spec.rb": 0.150838164, + "spec/services/time_service_spec.rb": 0.008286567, + "spec/services/update_user_spec.rb": 0.243611109, + "spec/services/uri_service_spec.rb": 0.048279977, + "spec/services/user_alerts/alert_user_about_account_verified_spec.rb": 0.580092159, + "spec/services/user_alerts/alert_user_about_new_device_spec.rb": 0.416537168, + "spec/services/user_alerts/alert_user_about_password_change_spec.rb": 0.40544898, + "spec/services/user_alerts/alert_user_about_personal_key_sign_in_spec.rb": 0.442179963, + "spec/services/user_event_creator_spec.rb": 0.24851092, + "spec/services/user_seeder_spec.rb": 2.757052879, + "spec/services/user_session_context_spec.rb": 0.054993397, + "spec/services/usps_in_person_proofing/enrollment_helper_spec.rb": 3.513400313, + "spec/services/usps_in_person_proofing/proofer_spec.rb": 0.441451188, + "spec/services/usps_in_person_proofing/transliterable_validator_spec.rb": 0.132614606, + "spec/services/usps_in_person_proofing/transliterator_spec.rb": 0.339624196, + "spec/services/uuid_reporter_spec.rb": 0.231941375, + "spec/services/x509/attribute_spec.rb": 0.007239249, + "spec/services/x509/attributes_spec.rb": 0.035395995, + "spec/svg_spec.rb": 1.037545143, + "spec/views/account_reset/cancel/show.html.erb_spec.rb": 0.027495574000000002, + "spec/views/account_reset/confirm_delete_account/show.html.erb_spec.rb": 0.038532393, + "spec/views/account_reset/confirm_request/show.html.erb_spec.rb": 0.010109552, + "spec/views/account_reset/delete_account/show.html.erb_spec.rb": 0.025564153, + "spec/views/account_reset/recovery_options/show.html.erb_spec.rb": 0.027236882, + "spec/views/account_reset/request/show.html.erb_spec.rb": 0.080220089, + "spec/views/account_reset/user_mailer/email_confirmation_instructions.html.erb_spec.rb": 0.117099683, + "spec/views/account_reset/user_mailer/unconfirmed_email_instructions.html.erb_spec.rb": 0.084849485, + "spec/views/accounts/_nav_auth.html.erb_spec.rb": 0.086775397, + "spec/views/accounts/connected_accounts/show.html.erb_spec.rb": 0.079172743, + "spec/views/accounts/history/show.html.erb_spec.rb": 0.074563569, + "spec/views/accounts/show.html.erb_spec.rb": 0.907920787, + "spec/views/accounts/two_factor_authentication/show.html.erb_spec.rb": 0.218638628, + "spec/views/devise/passwords/edit.html.erb_spec.rb": 0.145286793, + "spec/views/devise/passwords/new.html.erb_spec.rb": 0.122298059, + "spec/views/devise/sessions/new.html.erb_spec.rb": 0.311074075, + "spec/views/devise/shared/_password_strength.html.erb_spec.rb": 0.030884156, + "spec/views/forgot_password/show.html.erb_spec.rb": 0.08115992, + "spec/views/idv/activated.html.erb_spec.rb": 0.018504194, + "spec/views/idv/cancellations/destroy.html.erb_spec.rb": 0.022236137, + "spec/views/idv/cancellations/new.html.erb_spec.rb": 0.083915747, + "spec/views/idv/come_back_later/show.html.erb_spec.rb": 0.057678448, + "spec/views/idv/doc_auth/_cancel.html.erb_spec.rb": 0.029647781, + "spec/views/idv/doc_auth/welcome.html.erb_spec.rb": 0.131283137, + "spec/views/idv/gpo/index.html.erb_spec.rb": 0.167210509, + "spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb": 0.48577042800000003, + "spec/views/idv/phone/new.html.erb_spec.rb": 0.127702654, + "spec/views/idv/phone_errors/_warning.html.erb_spec.rb": 0.099779457, + "spec/views/idv/phone_errors/failure.html.erb_spec.rb": 0.188355827, + "spec/views/idv/phone_errors/jobfail.html.erb_spec.rb": 0.078352151, + "spec/views/idv/phone_errors/timeout.html.erb_spec.rb": 0.074833886, + "spec/views/idv/phone_errors/warning.html.erb_spec.rb": 0.235660953, + "spec/views/idv/please_call/show.html.erb_spec.rb": 0.026478493, + "spec/views/idv/review/new.html.erb_spec.rb": 0.257268326, + "spec/views/idv/session_errors/exception.html.erb_spec.rb": 0.043186901, + "spec/views/idv/session_errors/failure.html.erb_spec.rb": 0.030970952, + "spec/views/idv/session_errors/throttled.html.erb_spec.rb": 0.052929332, + "spec/views/idv/session_errors/warning.html.erb_spec.rb": 0.07114673, + "spec/views/idv/shared/_back.html.erb_spec.rb": 0.11076280799999999, + "spec/views/idv/shared/_document_capture.html.erb_spec.rb": 0.094721841, + "spec/views/idv/shared/_error.html.erb_spec.rb": 0.204260881, + "spec/views/idv/shared/_ssn.html.erb_spec.rb": 0.087453943, + "spec/views/idv/unavailable/show.html.erb_spec.rb": 0.076485933, + "spec/views/layouts/application.html.erb_spec.rb": 0.291218951, + "spec/views/layouts/user_mailer.html.erb_spec.rb": 0.214147414, + "spec/views/mfa_confirmation/show.html.erb_spec.rb": 0.11407014, + "spec/views/partials/multi_factor_authentication/_mfa_selection.html.erb_spec.rb": 0.096781725, + "spec/views/partials/personal_key/_key.html.erb_spec.rb": 0.052162107, + "spec/views/phone_setup/index.html.erb_spec.rb": 0.438273894, + "spec/views/phone_setup/spam_protection.html.erb_spec.rb": 0.10028938, + "spec/views/reactivate_account/index.html.erb_spec.rb": 0.045763681, + "spec/views/shared/_address.html.erb_spec.rb": 0.018385801, + "spec/views/shared/_banner.html.erb_spec.rb": 0.015734672, + "spec/views/shared/_email_languages.html.erb_spec.rb": 0.064889984, + "spec/views/shared/_footer_lite.html.erb_spec.rb": 0.053308845, + "spec/views/shared/_maintenance_window_alert.html.erb_spec.rb": 0.037222589, + "spec/views/shared/_masked_text.html.erb_spec.rb": 0.037445212, + "spec/views/shared/_nav_branded.html.erb_spec.rb": 0.038126881, + "spec/views/shared/_nav_lite.html.erb_spec.rb": 0.009702337, + "spec/views/shared/_personal_key.html.erb_spec.rb": 0.016604356, + "spec/views/shared/_troubleshooting_options.html.erb_spec.rb": 0.078339002, + "spec/views/sign_up/completions/show.html.erb_spec.rb": 0.262895097, + "spec/views/sign_up/email_resend/new.html.erb_spec.rb": 0.025757625, + "spec/views/sign_up/emails/show.html.erb_spec.rb": 0.042786726000000004, + "spec/views/sign_up/passwords/new.html.erb_spec.rb": 0.089472192, + "spec/views/sign_up/registrations/new.html.erb_spec.rb": 0.139687924, + "spec/views/two_factor_authentication/options/index.html.erb_spec.rb": 0.12746154, + "spec/views/two_factor_authentication/otp_expired/show.html.erb_spec.rb": 0.090631826, + "spec/views/two_factor_authentication/otp_verification/show.html.erb_spec.rb": 0.518435305, + "spec/views/two_factor_authentication/personal_key_verification/show.html.erb_spec.rb": 0.146216537, + "spec/views/two_factor_authentication/sms_opt_in/error.html.erb_spec.rb": 0.075920482, + "spec/views/two_factor_authentication/sms_opt_in/new.html.erb_spec.rb": 0.07783190200000001, + "spec/views/two_factor_authentication/totp_verification/show.html.erb_spec.rb": 0.263983231, + "spec/views/users/backup_code_setup/create.html.erb_spec.rb": 0.27626599, + "spec/views/users/backup_code_setup/reminder.html.erb_spec.rb": 0.059435181000000004, + "spec/views/users/delete/show.html.erb_spec.rb": 0.188219776, + "spec/views/users/edit_phone/remove_phone.html.erb_spec.rb": 0.08591955400000001, + "spec/views/users/passwords/edit.html.erb_spec.rb": 0.07117100700000001, + "spec/views/users/phones/add.html.erb_spec.rb": 0.046923689, + "spec/views/users/piv_cac_authentication_setup/new.html.erb_spec.rb": 0.064162238, + "spec/views/users/shared/_otp_delivery_preference_selection.html.erb_spec.rb": 0.07410494200000001, + "spec/views/users/totp_setup/new.html.erb_spec.rb": 0.181947164, + "spec/views/users/two_factor_authentication_setup/index.html.erb_spec.rb": 0.181100083, + "spec/views/users/webauthn_setup/new.html.erb_spec.rb": 0.033767042, + "spec/views/vendor_outage/show.html.erb_spec.rb": 0.028226784999999997 +} diff --git a/lib/feature_management.rb b/lib/feature_management.rb index 4ab08c5fe96..3aeb8c86296 100644 --- a/lib/feature_management.rb +++ b/lib/feature_management.rb @@ -15,6 +15,11 @@ def self.identity_pki_disabled? !IdentityConfig.store.piv_cac_verify_token_url end + def self.idv_available? + return false if !IdentityConfig.store.idv_available + !OutageStatus.new.any_idv_vendor_outage? + end + def self.development_and_identity_pki_disabled? # This controls if we try to hop over to identity-pki or just throw up # a screen asking for a Subject or one of a list of error conditions. diff --git a/lib/identity_config.rb b/lib/identity_config.rb index 0be4b47faef..c25562d9e9d 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -199,6 +199,7 @@ def self.build_store(config_map) config.add(:identity_pki_disabled, type: :boolean) config.add(:identity_pki_local_dev, type: :boolean) config.add(:idv_attempt_window_in_hours, type: :integer) + config.add(:idv_available, type: :boolean) config.add(:idv_contact_phone_number, type: :string) config.add(:idv_max_attempts, type: :integer) config.add(:idv_min_age_years, type: :integer) diff --git a/lib/identity_job_log_subscriber.rb b/lib/identity_job_log_subscriber.rb index 6948cc5feb4..2adc8c6d3ab 100644 --- a/lib/identity_job_log_subscriber.rb +++ b/lib/identity_job_log_subscriber.rb @@ -117,10 +117,6 @@ def logger end end - def self.reports_logger - @reports_logger ||= ActiveSupport::Logger.new(Rails.root.join('log', 'reports.log')) - end - def self.worker_logger @worker_logger ||= ActiveSupport::Logger.new(Rails.root.join('log', 'workers.log')) end diff --git a/lib/idp/constants.rb b/lib/idp/constants.rb index fcf730f4796..35ccd19e4ae 100644 --- a/lib/idp/constants.rb +++ b/lib/idp/constants.rb @@ -82,6 +82,7 @@ module Vendors AAL2 = 2 AAL3 = 3 + MOCK_IDV_APPLICANT_STATE_ID_JURISDICTION = 'ND' MOCK_IDV_APPLICANT = { first_name: 'FAKEY', middle_name: nil, @@ -93,7 +94,7 @@ module Vendors zipcode: '59010', dob: '1938-10-06', state_id_number: '1111111111111', - state_id_jurisdiction: 'ND', + state_id_jurisdiction: MOCK_IDV_APPLICANT_STATE_ID_JURISDICTION, state_id_type: 'drivers_license', state_id_expiration: '2099-12-31', state_id_issued: '2019-12-31', @@ -105,6 +106,7 @@ module Vendors state_id_address2: '2nd Address Line', state_id_city: 'Best City', state_id_zipcode: '12345', + state_id_state: 'VA', ).freeze MOCK_IDV_APPLICANT_WITH_SSN = MOCK_IDV_APPLICANT.merge(ssn: '900-66-1234').freeze @@ -113,5 +115,6 @@ module Vendors MOCK_IDV_APPLICANT_FULL_STATE_ID_JURISDICTION = 'North Dakota' MOCK_IDV_APPLICANT_FULL_STATE = 'Montana' + MOCK_IDV_APPLICANT_FULL_STATE_ID_STATE = 'Virginia' end end diff --git a/lib/session_encryptor.rb b/lib/session_encryptor.rb index a33bf8df85e..c2a924cb6d3 100644 --- a/lib/session_encryptor.rb +++ b/lib/session_encryptor.rb @@ -8,8 +8,9 @@ class SensitiveValueError < StandardError; end MINIMUM_COMPRESS_LIMIT = 300 SENSITIVE_KEYS = [ 'first_name', 'middle_name', 'last_name', 'address1', 'address2', 'city', 'state', 'zipcode', - 'zip_code', 'state_id_address1', 'state_id_address2', 'state_id_city', 'state_id_jurisdiction', - 'state_id_zipcode', 'same_address_as_id', 'dob', 'phone_number', 'phone', 'ssn', + 'zip_code', 'state_id_address1', 'state_id_address2', 'state_id_city', + 'state_id_zipcode', 'state_id_state', 'state_id_jurisdiction', + 'same_address_as_id', 'dob', 'phone_number', 'phone', 'ssn', 'prev_address1', 'prev_address2', 'prev_city', 'prev_state', 'prev_zipcode', 'pii', 'pii_from_doc', 'pii_from_user', 'password', 'personal_key', 'email', 'email_address', 'unconfirmed_phone' diff --git a/lib/tasks/review_profile.rake b/lib/tasks/review_profile.rake index 86c1c85a9e2..a448b0917b3 100644 --- a/lib/tasks/review_profile.rake +++ b/lib/tasks/review_profile.rake @@ -26,7 +26,7 @@ namespace :users do next end - if user.proofing_component.review_eligible? + if user.fraud_review_eligible? profile = user.fraud_review_pending_profile profile.activate_after_passing_review @@ -73,7 +73,7 @@ namespace :users do next end - if user.proofing_component.review_eligible? + if user.fraud_review_eligible? profile = user.fraud_review_pending_profile profile.reject_for_fraud(notify_user: true) diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 6ac9d6990cf..215f3da082f 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -402,7 +402,7 @@ def index end context 'with a SAML request' do - let(:sp_session_request_url) { '/api/saml/auth2022' } + let(:sp_session_request_url) { '/api/saml/auth2023' } it 'returns the saml completion url' do expect(url_with_updated_params).to eq complete_saml_url end @@ -440,9 +440,9 @@ def index context 'with saml_internal_post feature flag set to false' do before { allow(IdentityConfig.store).to receive(:saml_internal_post).and_return false } context 'with a SAML request' do - let(:sp_session_request_url) { '/api/saml/auth2022?SAMLRequest=blah' } + let(:sp_session_request_url) { '/api/saml/auth2023?SAMLRequest=blah' } it 'returns the original request url' do - expect(url_with_updated_params).to eq '/api/saml/auth2022?SAMLRequest=blah' + expect(url_with_updated_params).to eq '/api/saml/auth2023?SAMLRequest=blah' end end diff --git a/spec/controllers/idv/document_capture_controller_spec.rb b/spec/controllers/idv/document_capture_controller_spec.rb index b757586cfa1..8eb45995dc0 100644 --- a/spec/controllers/idv/document_capture_controller_spec.rb +++ b/spec/controllers/idv/document_capture_controller_spec.rb @@ -28,13 +28,6 @@ end describe 'before_actions' do - it 'checks that feature flag is enabled' do - expect(subject).to have_actions( - :before, - :render_404_if_document_capture_controller_disabled, - ) - end - it 'includes authentication before_action' do expect(subject).to have_actions( :before, @@ -154,17 +147,4 @@ end end end - - context 'when doc_auth_document_capture_controller_enabled is false' do - before do - allow(IdentityConfig.store).to receive(:doc_auth_document_capture_controller_enabled). - and_return(false) - end - - it 'returns 404' do - get :show - - expect(response.status).to eq(404) - end - end end diff --git a/spec/controllers/idv/in_person/usps_locations_controller_spec.rb b/spec/controllers/idv/in_person/usps_locations_controller_spec.rb index 1af6b68966a..c3b0c457bc1 100644 --- a/spec/controllers/idv/in_person/usps_locations_controller_spec.rb +++ b/spec/controllers/idv/in_person/usps_locations_controller_spec.rb @@ -257,6 +257,14 @@ expect(enrollment.service_provider).to be_nil end + it 'updates proofing component vendor' do + expect(user.proofing_component&.document_check).to be_nil + + response + + expect(user.proofing_component.document_check).to eq Idp::Constants::Vendors::USPS + end + context 'when unauthenticated' do let(:user) { nil } diff --git a/spec/controllers/idv/in_person/verify_info_controller_spec.rb b/spec/controllers/idv/in_person/verify_info_controller_spec.rb index 83ea59e23d9..a2dfa6ec3de 100644 --- a/spec/controllers/idv/in_person/verify_info_controller_spec.rb +++ b/spec/controllers/idv/in_person/verify_info_controller_spec.rb @@ -158,12 +158,6 @@ expect(response).to redirect_to(idv_session_errors_ssn_failure_url) end end - - it 'updates proofing component vendor' do - put :update - - expect(user.proofing_component.document_check).to eq Idp::Constants::Vendors::USPS - end end end end diff --git a/spec/controllers/idv/phone_errors_controller_spec.rb b/spec/controllers/idv/phone_errors_controller_spec.rb index 2191b8f32e2..e825c321435 100644 --- a/spec/controllers/idv/phone_errors_controller_spec.rb +++ b/spec/controllers/idv/phone_errors_controller_spec.rb @@ -62,6 +62,7 @@ end context 'the user is not authenticated and not recovering their account' do + let(:user) { nil } it 'redirects to sign in' do get action @@ -83,11 +84,17 @@ let(:idv_session) { double } let(:idv_session_user_phone_confirmation) { false } let(:user) { nil } + let(:phone) { '3602345678' } + let(:country_code) { 'US' } before do allow(idv_session).to receive(:user_phone_confirmation). and_return(idv_session_user_phone_confirmation) allow(idv_session).to receive(:current_user).and_return(user) + allow(idv_session).to receive(:previous_phone_step_params).and_return( + phone: phone, + international_code: country_code, + ) allow(subject).to receive(:remaining_attempts).and_return(5) allow(controller).to receive(:idv_session).and_return(idv_session) stub_sign_in(user) if user @@ -99,12 +106,21 @@ describe '#warning' do let(:action) { :warning } let(:template) { 'idv/phone_errors/warning' } + let(:user) { create(:user) } it_behaves_like 'an idv phone errors controller action' - context 'with throttle attempts' do - let(:user) { create(:user) } + it 'assigns phone' do + get action + expect(assigns(:phone)).to eql(phone) + end + it 'assigns country_code' do + get action + expect(assigns(:country_code)).to eql(country_code) + end + + context 'with throttle attempts' do before do Throttle.new(throttle_type: :proof_address, user: user).increment! end diff --git a/spec/controllers/idv/unavailable_controller_spec.rb b/spec/controllers/idv/unavailable_controller_spec.rb new file mode 100644 index 00000000000..5c868d577be --- /dev/null +++ b/spec/controllers/idv/unavailable_controller_spec.rb @@ -0,0 +1,82 @@ +require 'rails_helper' + +describe Idv::UnavailableController, type: :controller do + let(:idv_available) { false } + + before do + allow(IdentityConfig.store).to receive(:idv_available).and_return(idv_available) + end + + describe '#show' do + let(:params) { nil } + + before do + stub_analytics + get :show, params: params + end + + it 'returns 200 OK' do + # https://http.cat/200 + expect(response.status).to eql(200) + end + + it 'logs an analytics event with redirect_from nil' do + expect(@analytics).to have_logged_event( + 'Vendor Outage', + redirect_from: nil, + vendor_status: { + acuant: :operational, + lexisnexis_instant_verify: :operational, + lexisnexis_trueid: :operational, + sms: :operational, + voice: :operational, + }, + ) + end + + it 'renders the view' do + expect(response).to render_template('idv/unavailable/show') + end + + context 'coming from the create account page' do + let(:params) do + { from: SignUp::RegistrationsController::CREATE_ACCOUNT } + end + it 'logs an analytics event with redirect_from CREATE_ACCOUNT' do + expect(@analytics).to have_logged_event( + 'Vendor Outage', + redirect_from: SignUp::RegistrationsController::CREATE_ACCOUNT, + vendor_status: { + acuant: :operational, + lexisnexis_instant_verify: :operational, + lexisnexis_trueid: :operational, + sms: :operational, + voice: :operational, + }, + ) + end + it 'renders the view' do + expect(response).to render_template('idv/unavailable/show') + end + end + + context 'IdV is enabled' do + let(:idv_available) { true } + + it 'renders the view when from: is nil' do + expect(response).to render_template('idv/unavailable/show') + end + + it 'returns a 200' do + expect(response.status).to eql(200) + end + + context 'coming from the create account page' do + let(:params) { { from: SignUp::RegistrationsController::CREATE_ACCOUNT } } + it 'redirects back to create account' do + expect(response).to redirect_to(sign_up_email_path) + end + end + end + end +end diff --git a/spec/controllers/saml_completion_controller_spec.rb b/spec/controllers/saml_completion_controller_spec.rb index ec38e62af35..fd6cbb8105c 100644 --- a/spec/controllers/saml_completion_controller_spec.rb +++ b/spec/controllers/saml_completion_controller_spec.rb @@ -20,7 +20,7 @@ Signature: signature, } end - let(:sp_session_request_url) { 'http://example.gov/api/saml/auth2022' } + let(:sp_session_request_url) { 'http://example.gov/api/saml/auth2023' } before do expect(controller).to receive(:sp_session).at_least(:once).and_return( diff --git a/spec/controllers/saml_idp_controller_spec.rb b/spec/controllers/saml_idp_controller_spec.rb index 456d874848f..27f9df1d08a 100644 --- a/spec/controllers/saml_idp_controller_spec.rb +++ b/spec/controllers/saml_idp_controller_spec.rb @@ -562,7 +562,7 @@ def name_id_version(format_urn) authn_context_comparison: 'exact', requested_ial: authn_context, service_provider: sp1_issuer, - endpoint: '/api/saml/auth2022', + endpoint: '/api/saml/auth2023', idv: false, finish_profile: false, request_signed: true, @@ -703,7 +703,7 @@ def name_id_version(format_urn) authn_context_comparison: 'minimum', requested_ial: 'ialmax', service_provider: sp1_issuer, - endpoint: '/api/saml/auth2022', + endpoint: '/api/saml/auth2023', idv: false, finish_profile: false, request_signed: true, @@ -1241,7 +1241,7 @@ def name_id_version(format_urn) authn_context_comparison: 'exact', requested_ial: Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF, service_provider: 'http://localhost:3000', - endpoint: '/api/saml/auth2022', + endpoint: '/api/saml/auth2023', idv: false, finish_profile: false, request_signed: false, @@ -1282,7 +1282,7 @@ def name_id_version(format_urn) authn_context_comparison: 'exact', requested_ial: 'none', service_provider: 'http://localhost:3000', - endpoint: '/api/saml/auth2022', + endpoint: '/api/saml/auth2023', idv: false, finish_profile: false, request_signed: true, @@ -1319,7 +1319,7 @@ def name_id_version(format_urn) authn_context_comparison: 'exact', requested_ial: Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF, service_provider: 'http://localhost:3000', - endpoint: '/api/saml/auth2022', + endpoint: '/api/saml/auth2023', idv: false, finish_profile: false, request_signed: true, @@ -1354,7 +1354,7 @@ def name_id_version(format_urn) authn_context_comparison: 'exact', requested_ial: Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF, service_provider: auth_settings.issuer, - endpoint: '/api/saml/auth2022', + endpoint: '/api/saml/auth2023', idv: false, finish_profile: false, request_signed: true, @@ -1426,7 +1426,7 @@ def name_id_version(format_urn) authn_context_comparison: 'exact', requested_ial: Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF, service_provider: 'http://localhost:3000', - endpoint: '/api/saml/auth2022', + endpoint: '/api/saml/auth2023', idv: false, finish_profile: false, request_signed: true, @@ -1458,7 +1458,7 @@ def name_id_version(format_urn) authn_context_comparison: 'exact', requested_ial: Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF, service_provider: auth_settings.issuer, - endpoint: '/api/saml/auth2022', + endpoint: '/api/saml/auth2023', idv: false, finish_profile: false, request_signed: true, @@ -1490,7 +1490,7 @@ def name_id_version(format_urn) authn_context_comparison: 'exact', requested_ial: Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF, service_provider: 'http://localhost:3000', - endpoint: '/api/saml/auth2022', + endpoint: '/api/saml/auth2023', idv: false, finish_profile: false, request_signed: true, @@ -1505,7 +1505,7 @@ def name_id_version(format_urn) describe 'HEAD /api/saml/auth', type: :request do it 'responds with "403 Forbidden"' do - head '/api/saml/auth2022?SAMLRequest=bang!' + head '/api/saml/auth2023?SAMLRequest=bang!' expect(response.status).to eq(403) end @@ -1677,7 +1677,7 @@ def name_id_version(format_urn) ds: Saml::XML::Namespaces::SIGNATURE, ) - crt = AppArtifacts.store.saml_2022_cert + crt = AppArtifacts.store.saml_2023_cert expect(element.text).to eq(crt.split("\n")[1...-1].join("\n").delete("\n")) end @@ -1980,7 +1980,7 @@ def stub_auth authn_context_comparison: 'exact', requested_ial: Saml::Idp::Constants::IAL2_AUTHN_CONTEXT_CLASSREF, service_provider: 'http://localhost:3000', - endpoint: '/api/saml/auth2022', + endpoint: '/api/saml/auth2023', idv: true, finish_profile: false, request_signed: false, @@ -2025,7 +2025,7 @@ def stub_requested_attributes authn_context_comparison: 'exact', requested_ial: Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF, service_provider: 'http://localhost:3000', - endpoint: '/api/saml/auth2022', + endpoint: '/api/saml/auth2023', idv: false, finish_profile: false, request_signed: true, @@ -2061,7 +2061,7 @@ def stub_requested_attributes authn_context_comparison: 'exact', requested_ial: Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF, service_provider: 'http://localhost:3000', - endpoint: '/api/saml/auth2022', + endpoint: '/api/saml/auth2023', idv: false, finish_profile: true, request_signed: true, diff --git a/spec/controllers/sign_up/registrations_controller_spec.rb b/spec/controllers/sign_up/registrations_controller_spec.rb index 4d9964e8bdc..6f3511ad465 100644 --- a/spec/controllers/sign_up/registrations_controller_spec.rb +++ b/spec/controllers/sign_up/registrations_controller_spec.rb @@ -25,6 +25,19 @@ expect { get :new }. to raise_error(Mime::Type::InvalidMimeType) end + + context 'IdV unavailable' do + before do + allow(IdentityConfig.store).to receive(:idv_available).and_return(false) + end + it 'redirects to idv vendor outage page when ial2 requested' do + allow(controller).to receive(:ial2_requested?).and_return(true) + get :new + expect(response).to redirect_to( + idv_unavailable_path(from: SignUp::RegistrationsController::CREATE_ACCOUNT), + ) + end + end end describe '#create' do diff --git a/spec/controllers/users/backup_code_setup_controller_spec.rb b/spec/controllers/users/backup_code_setup_controller_spec.rb index 18c03aaaac2..6e97e92ae37 100644 --- a/spec/controllers/users/backup_code_setup_controller_spec.rb +++ b/spec/controllers/users/backup_code_setup_controller_spec.rb @@ -8,7 +8,7 @@ :authenticate_user!, :confirm_user_authenticated_for_2fa_setup, :apply_secure_headers_override, - :confirm_recently_authenticated_2fa, + [:confirm_recently_authenticated_2fa, except: ['reminder']], ) end end diff --git a/spec/factories/service_provider_identities.rb b/spec/factories/service_provider_identities.rb index 3e43c2e7622..ccaf710ba77 100644 --- a/spec/factories/service_provider_identities.rb +++ b/spec/factories/service_provider_identities.rb @@ -15,4 +15,8 @@ trait :soft_deleted_5m_ago do deleted_at { Time.zone.now - 5.minutes } end + + trait :verified do + verified_at { Time.zone.now } + end end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 6313cbd9dd3..09a6e8a671a 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -214,8 +214,7 @@ signed_up after :build do |user| - create(:profile, :fraud_review_pending, :with_pii, user: user) - create(:proofing_component, :eligible_for_review, user: user) + create(:profile, :fraud_review_pending, :verified, :with_pii, user: user) end end diff --git a/spec/features/idv/in_person_spec.rb b/spec/features/idv/in_person_spec.rb index 6cfb066151f..76c4f85a5ac 100644 --- a/spec/features/idv/in_person_spec.rb +++ b/spec/features/idv/in_person_spec.rb @@ -268,7 +268,7 @@ end # prepare page - expect(page).to have_content(t('in_person_proofing.headings.prepare')) + expect(page).to have_content(t('in_person_proofing.headings.prepare'), wait: 5) click_button t('forms.buttons.back') expect(page).to have_content(t('in_person_proofing.headings.po_search.location')) @@ -342,7 +342,7 @@ mock_doc_auth_attention_with_barcode attach_and_submit_images - click_link t('in_person_proofing.body.cta.button') + click_button t('in_person_proofing.body.cta.button') search_for_post_office within page.first('.location-collection-item') do click_spinner_button_and_wait t('in_person_proofing.body.location.location_button') @@ -592,7 +592,7 @@ complete_location_step(user) expect(page).to have_content( - t('in_person_proofing.headings.prepare'), + t('in_person_proofing.headings.prepare'), wait: 5 ) end @@ -607,7 +607,7 @@ end end - context 'in_person_capture_secondary_id_enabled feature flag enabled', allow_browser_log: true do + shared_examples 'captures address with state id' do let(:user) { user_with_2fa } before(:each) do @@ -619,12 +619,11 @@ complete_location_step(user) expect(page).to have_content( - t('in_person_proofing.headings.prepare'), + t('in_person_proofing.headings.prepare'), wait: 5 ) end - - def it_captures_address_with_state_id - # prepare page + # prepare page + it 'successfully proceeds through the flow' do complete_prepare_step(user) complete_state_id_step(user, same_address_as_id: false, double_address_verification: true) @@ -636,11 +635,11 @@ def it_captures_address_with_state_id t('idv.form.ssn_label_html'), ) end + end + context 'in_person_capture_secondary_id_enabled feature flag enabled', allow_browser_log: true do context 'flag remains enabled' do - it 'captures the address, address line 2, city, state and zip code' do - it_captures_address_with_state_id - end + it_behaves_like 'captures address with state id' end context 'flag is then disabled' do @@ -649,9 +648,7 @@ def it_captures_address_with_state_id and_return(false) end - it 'captures the address, address line 2, city, state and zip code' do - it_captures_address_with_state_id - end + it_behaves_like 'captures address with state id' end end end diff --git a/spec/features/idv/outage_spec.rb b/spec/features/idv/outage_spec.rb index e52db17f486..5b221e7ad31 100644 --- a/spec/features/idv/outage_spec.rb +++ b/spec/features/idv/outage_spec.rb @@ -20,12 +20,54 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) let(:new_password) { 'some really awesome new password' } let(:pii) { { ssn: '666-66-1234', dob: '1920-01-01', first_name: 'alice' } } - context 'vendor_status_lexisnexis_phone_finder set to full_outage', js: true do - before do - allow(IdentityConfig.store).to receive(:vendor_status_lexisnexis_phone_finder). - and_return(:full_outage) + let(:vendor_status_acuant) { :operational } + let(:vendor_status_lexisnexis_instant_verify) { :operational } + let(:vendor_status_lexisnexis_phone_finder) { :operational } + let(:vendor_status_lexisnexis_trueid) { :operational } + let(:vendor_status_sms) { :operational } + let(:vendor_status_voice) { :operational } + + let(:enable_usps_verification) { true } + let(:feature_idv_force_gpo_verification_enabled) { false } + let(:feature_idv_hybrid_flow_enabled) { true } + + before do + # Wire up various let()s to configuration keys + %w[ + acuant + lexisnexis_instant_verify + lexisnexis_phone_finder + lexisnexis_trueid + sms + voice + ].each do |service| + vendor_status_key = "vendor_status_#{service}".to_sym + allow(IdentityConfig.store).to receive(vendor_status_key). + and_return(send(vendor_status_key)) + end + + %w[ + enable_usps_verification + feature_idv_force_gpo_verification_enabled + feature_idv_hybrid_flow_enabled + ].each do |key| + allow(IdentityConfig.store).to receive(key). + and_return(send(key)) end + # Configuration / vendor status changes can effect Rails routing tables. + # Force routes to be reloaded when we've modified configuration. + Rails.application.reload_routes! + end + + after do + # Don't leave stale routes sitting around. + Rails.application.reload_routes! + end + + context 'vendor_status_lexisnexis_phone_finder set to full_outage', js: true do + let(:vendor_status_lexisnexis_phone_finder) { :full_outage } + it 'takes the user through the mail only flow, allowing hybrid' do sign_in_with_idv_required(user: user) @@ -51,10 +93,7 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) end context 'GPO only enabled, but user starts over', js: true do - before do - allow(IdentityConfig.store).to receive(:feature_idv_force_gpo_verification_enabled). - and_return(true) - end + let(:feature_idv_force_gpo_verification_enabled) { true } it 'shows mail only warning page before idv welcome page' do sign_in_with_idv_required(user: user) @@ -70,14 +109,7 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) end context 'force GPO only without phone outages', js: true do - before do - allow(IdentityConfig.store).to receive(:feature_idv_force_gpo_verification_enabled). - and_return(true) - allow(IdentityConfig.store).to receive(:vendor_status_sms). - and_return(:operational) - allow(IdentityConfig.store).to receive(:vendor_status_voice). - and_return(:operational) - end + let(:feature_idv_force_gpo_verification_enabled) { true } it 'shows mail only warning page before idv welcome page' do sign_in_with_idv_required(user: user) @@ -91,12 +123,8 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) end context 'force GPO only, but GPO not enabled', js: true do - before do - allow(IdentityConfig.store).to receive(:feature_idv_force_gpo_verification_enabled). - and_return(true) - allow(IdentityConfig.store).to receive(:enable_usps_verification). - and_return(false) - end + let(:feature_idv_force_gpo_verification_enabled) { true } + let(:enable_usps_verification) { false } it 'shows mail only warning page before idv welcome page' do sign_in_with_idv_required(user: user) @@ -110,10 +138,7 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) %i[vendor_status_sms vendor_status_voice].each do |flag| context "#{flag} set to full_outage" do - before do - allow(IdentityConfig.store).to receive(flag). - and_return(:full_outage) - end + let(flag) { :full_outage } it 'shows mail only warning page before idv welcome page' do sign_in_with_idv_required(user: user, sms_or_totp: :totp) @@ -146,13 +171,9 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) end context 'feature_idv_force_gpo_verification_enabled set to true', js: true do + let(:feature_idv_force_gpo_verification_enabled) { true } let(:user) { user_with_2fa } - before do - allow(IdentityConfig.store).to receive(:feature_idv_force_gpo_verification_enabled). - and_return(true) - end - it 'shows mail only warning page before idv welcome page', js: true do sign_in_with_idv_required(user: user, sms_or_totp: :sms) @@ -175,11 +196,7 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) context 'feature_idv_hybrid_flow_enabled set to false', js: true do let(:user) { user_with_2fa } - - before do - allow(IdentityConfig.store).to receive(:feature_idv_hybrid_flow_enabled). - and_return(false) - end + let(:feature_idv_hybrid_flow_enabled) { false } it 'does not show the mail only warning page before idv welcome page' do sign_in_with_idv_required(user: user, sms_or_totp: :sms) @@ -200,16 +217,12 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) %w[acuant lexisnexis_instant_verify lexisnexis_trueid].each do |service| context "vendor_status_#{service} set to full_outage" do let(:user) { user_with_2fa } - before do - allow(IdentityConfig.store).to receive("vendor_status_#{service}".to_sym). - and_return(:full_outage) - end + let("vendor_status_#{service}".to_sym) { :full_outage } it 'prevents an existing ial1 user from verifying their identity' do sign_in_with_idv_required(user: user, sms_or_totp: :sms) - expect(current_path).to eq vendor_outage_path expect(page).to have_content( - t('vendor_outage.blocked.idv.with_sp', service_provider: 'Test SP'), + strip_tags(t('idv.unavailable.idv_explanation.with_sp_html', sp: 'Test SP')), ) end @@ -228,15 +241,20 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) click_on t('links.account.reactivate.without_key') click_on t('forms.buttons.continue') - expect(current_path).to eq vendor_outage_path - expect(page).to have_content(t('vendor_outage.blocked.idv.without_sp')) + expect(page).to have_content(t('idv.unavailable.idv_explanation.without_sp')) end it 'prevents a user from creating an account' do visit_idp_from_sp_with_ial2(:oidc) click_link t('links.create_account') - expect(current_path).to eq vendor_outage_path - expect(page).to have_content(t('vendor_outage.blocked.idv.generic')) + expect(page).to have_content( + strip_tags( + t( + 'idv.unavailable.idv_explanation.with_sp_html', + sp: 'Test SP', + ), + ), + ) end end end diff --git a/spec/features/idv/steps/in_person/verify_info_spec.rb b/spec/features/idv/steps/in_person/verify_info_spec.rb index 7aacb6188f1..3fe16da670b 100644 --- a/spec/features/idv/steps/in_person/verify_info_spec.rb +++ b/spec/features/idv/steps/in_person/verify_info_spec.rb @@ -24,6 +24,7 @@ complete_ssn_step(user) # verify page + expect_in_person_step_indicator_current_step(t('step_indicator.flows.idv.verify_info')) expect(page).to have_current_path(idv_in_person_verify_info_path) expect(page).to have_content(t('headings.verify')) expect(page).to have_text(InPersonHelper::GOOD_FIRST_NAME) diff --git a/spec/features/idv/steps/in_person/verify_step_spec.rb b/spec/features/idv/steps/in_person/verify_step_spec.rb index a8288f3c411..d72e72aa289 100644 --- a/spec/features/idv/steps/in_person/verify_step_spec.rb +++ b/spec/features/idv/steps/in_person/verify_step_spec.rb @@ -110,6 +110,10 @@ expect(page).to have_text(InPersonHelper::GOOD_FIRST_NAME) expect(page).to have_text(InPersonHelper::GOOD_LAST_NAME) expect(page).to have_text(InPersonHelper::GOOD_DOB_FORMATTED_EVENT) + expect(page).to have_text( + "#{I18n.t('idv.form.issuing_state')}: #{Idp::Constants:: + MOCK_IDV_APPLICANT_STATE_ID_JURISDICTION}", + ) expect(page).to have_text(InPersonHelper::GOOD_STATE_ID_NUMBER) expect_good_state_id_address expect(page).to have_content(t('headings.residential_address')) @@ -159,11 +163,19 @@ expect(page).to have_text(InPersonHelper::GOOD_FIRST_NAME) expect(page).to have_text(InPersonHelper::GOOD_LAST_NAME) expect(page).to have_text(InPersonHelper::GOOD_DOB_FORMATTED_EVENT) + expect(page).to have_text( + "#{I18n.t('idv.form.issuing_state')}: #{Idp::Constants:: + MOCK_IDV_APPLICANT_STATE_ID_JURISDICTION}", + ) expect(page).to have_text(InPersonHelper::GOOD_STATE_ID_NUMBER) expect(page).to have_text(InPersonHelper::GOOD_STATE_ID_ADDRESS1).twice expect(page).to have_text(InPersonHelper::GOOD_STATE_ID_ADDRESS2).twice expect(page).to have_text(InPersonHelper::GOOD_STATE_ID_CITY).twice - expect(page).to have_text(Idp::Constants::MOCK_IDV_APPLICANT[:state_id_jurisdiction]).twice + expect(page).to have_text( + Idp::Constants:: + MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[:state_id_state], + ).twice + expect(page).to have_text(Idp::Constants::MOCK_IDV_APPLICANT[:state_id_jurisdiction]).once expect(page).to have_text(InPersonHelper::GOOD_STATE_ID_ZIPCODE).twice expect(page).to have_content(t('headings.residential_address')) expect(page).to have_content(t('headings.ssn')) diff --git a/spec/features/idv/steps/phone_step_spec.rb b/spec/features/idv/steps/phone_step_spec.rb index 9b5a40d73e3..8392b3187e9 100644 --- a/spec/features/idv/steps/phone_step_spec.rb +++ b/spec/features/idv/steps/phone_step_spec.rb @@ -4,9 +4,15 @@ include IdvStepHelper include IdvHelper + let(:user) { user_with_2fa } + let(:gpo_enabled) { true } + + before do + allow(IdentityConfig.store).to receive(:enable_usps_verification).and_return(gpo_enabled) + end + context 'defaults on page load' do it 'selects sms delivery option by default', js: true do - user = user_with_2fa start_idv_from_sp complete_idv_steps_before_phone_step(user) expect(page).to have_checked_field( @@ -18,7 +24,6 @@ context 'with valid information' do it 'redirects to the otp confirmation step when the phone matches the 2fa phone number', js: true do - user = user_with_2fa start_idv_from_sp complete_idv_steps_before_phone_step(user) fill_out_phone_form_ok(MfaContext.new(user).phone_configurations.first.phone) @@ -77,8 +82,6 @@ end it 'is not re-entrant after confirming OTP' do - user = user_with_2fa - start_idv_from_sp complete_idv_steps_before_phone_step(user) fill_out_phone_form_ok @@ -121,39 +124,44 @@ expect(page).to have_current_path(idv_doc_auth_step_path(step: :welcome)) end - shared_examples 'async timed out' do - it 'allows resubmitting form' do - user = user_with_2fa - start_idv_from_sp - complete_idv_steps_before_phone_step(user) + it 'allows resubmitting form' do + start_idv_from_sp + complete_idv_steps_before_phone_step(user) - allow(DocumentCaptureSession).to receive(:find_by).and_return(nil) - fill_out_phone_form_ok(MfaContext.new(user).phone_configurations.first.phone) - click_idv_send_security_code - expect(page).to have_content(t('idv.failure.timeout')) - expect(page).to have_current_path(idv_phone_path) - allow(DocumentCaptureSession).to receive(:find_by).and_call_original - click_idv_send_security_code - expect(page).to have_current_path(idv_otp_verification_path) - end + allow(DocumentCaptureSession).to receive(:find_by).and_return(nil) + fill_out_phone_form_ok(MfaContext.new(user).phone_configurations.first.phone) + click_idv_send_security_code + expect(page).to have_content(t('idv.failure.timeout')) + expect(page).to have_current_path(idv_phone_path) + allow(DocumentCaptureSession).to receive(:find_by).and_call_original + click_idv_send_security_code + expect(page).to have_current_path(idv_otp_verification_path) end - it_behaves_like 'async timed out' - context "when the user's information cannot be verified" do + it 'reports the number the user entered' do + start_idv_from_sp + complete_idv_steps_before_phone_step + fill_out_phone_form_fail + click_idv_send_security_code + + expect(page).to have_content(t('idv.failure.phone.warning.heading')) + expect(page).to have_content('+1 703-555-5555') + end + it 'links to verify by mail, from which user can return back to the warning screen' do start_idv_from_sp complete_idv_steps_before_phone_step fill_out_phone_form_fail click_idv_send_security_code - expect(page).to have_content(t('idv.failure.phone.warning')) + expect(page).to have_content(t('idv.failure.phone.warning.heading')) - click_on t('idv.troubleshooting.options.verify_by_mail') + click_on t('idv.failure.phone.warning.gpo.button') expect(page).to have_content(t('idv.titles.mail.verify')) click_doc_auth_back_link - expect(page).to have_content(t('idv.failure.phone.warning')) + expect(page).to have_content(t('idv.failure.phone.warning.heading')) end it 'does not render the link to proof by mail if proofing by mail is disabled' do @@ -166,10 +174,10 @@ fill_out_phone_form_fail click_idv_send_security_code - expect(page).to have_content(t('idv.failure.phone.warning')) + expect(page).to have_content(t('idv.failure.phone.warning.heading')) expect(page).to_not have_content(t('idv.troubleshooting.options.verify_by_mail')) - click_on t('idv.failure.button.warning') + click_on t('idv.failure.phone.warning.try_again_button') end fill_out_phone_form_fail @@ -189,4 +197,40 @@ it_behaves_like 'verification step max attempts', :phone, :oidc it_behaves_like 'verification step max attempts', :phone, :saml end + + context 'when the user is rate-limited' do + before do + start_idv_from_sp + complete_idv_steps_before_step(:phone, user) + end + + around do |ex| + freeze_time { ex.run } + end + + before do + (Throttle.max_attempts(:proof_address) - 1).times do + fill_out_phone_form_fail + click_idv_continue_for_step(:phone) + click_on t('idv.failure.phone.warning.try_again_button') + end + click_idv_continue_for_step(:phone) + end + + it 'still lets them access the GPO flow and return to the error' do + click_on t('idv.failure.phone.rate_limited.gpo.button') + expect(page).to have_content(t('idv.titles.mail.verify')) + click_doc_auth_back_link + expect(page).to have_content(t('idv.failure.phone.rate_limited.heading')) + end + + context 'GPO is disabled' do + let(:gpo_enabled) { false } + + it 'does not link out to GPO flow' do + expect(page).not_to have_content(t('idv.failure.phone.rate_limited.gpo.prompt')) + expect(page).not_to have_content(t('idv.failure.phone.rate_limited.gpo.button')) + end + end + end end diff --git a/spec/features/reports/authorization_count_spec.rb b/spec/features/reports/authorization_count_spec.rb index 525a4e0f340..034add6b303 100644 --- a/spec/features/reports/authorization_count_spec.rb +++ b/spec/features/reports/authorization_count_spec.rb @@ -306,7 +306,7 @@ def expect_ial1_and_ial2_count(issuer) def reset_monthly_auth_count_and_login(user) SpReturnLog.delete_all - visit api_saml_logout2022_path + visit api_saml_logout2023_path sign_in_live_with_2fa(user) end end diff --git a/spec/features/reports/sp_active_users_report_spec.rb b/spec/features/reports/sp_active_users_report_spec.rb index 980e0133c6f..8be605bff69 100644 --- a/spec/features/reports/sp_active_users_report_spec.rb +++ b/spec/features/reports/sp_active_users_report_spec.rb @@ -17,7 +17,7 @@ app_id: nil, total_ial1_active: 1, total_ial2_active: 0 }].to_json - expect(Db::Identity::SpActiveUserCounts.call('01-01-2019').to_json).to eq(results) + expect(Db::Identity::SpActiveUserCounts.by_issuer('01-01-2019').to_json).to eq(results) end it 'reports a user as ial2 active for an ial2 sign in' do @@ -36,6 +36,6 @@ app_id: nil, total_ial1_active: 0, total_ial2_active: 1 }].to_json - expect(Db::Identity::SpActiveUserCounts.call('01-01-2019').to_json).to eq(results) + expect(Db::Identity::SpActiveUserCounts.by_issuer('01-01-2019').to_json).to eq(results) end end diff --git a/spec/features/saml/multiple_endpoints_spec.rb b/spec/features/saml/multiple_endpoints_spec.rb index 53f9e82a694..63ca9f0e2e7 100644 --- a/spec/features/saml/multiple_endpoints_spec.rb +++ b/spec/features/saml/multiple_endpoints_spec.rb @@ -4,7 +4,7 @@ include SamlAuthHelper include IdvHelper - let(:endpoint_suffix) { '2022' } + let(:endpoint_suffix) { '2023' } let(:user) { create(:user, :signed_up) } let(:endpoint_saml_settings) do diff --git a/spec/features/saml/redirect_uri_validation_spec.rb b/spec/features/saml/redirect_uri_validation_spec.rb index bbe608042e1..75a15ae18c6 100644 --- a/spec/features/saml/redirect_uri_validation_spec.rb +++ b/spec/features/saml/redirect_uri_validation_spec.rb @@ -6,7 +6,7 @@ context 'when redirect_uri param is included in SAML request' do it 'uses the return_to_sp_url URL and not the redirect_uri' do user = create(:user, :signed_up) - visit api_saml_auth2022_path( + visit api_saml_auth2023_path( SAMLRequest: CGI.unescape(saml_request(saml_settings)), redirect_uri: 'http://evil.com', state: '123abc', diff --git a/spec/features/saml/saml_logout_spec.rb b/spec/features/saml/saml_logout_spec.rb index caed7d6f1ae..69cf3d71516 100644 --- a/spec/features/saml/saml_logout_spec.rb +++ b/spec/features/saml/saml_logout_spec.rb @@ -120,7 +120,7 @@ }, ) - expect(current_path).to eq(api_saml_logout2022_path) + expect(current_path).to eq(api_saml_logout2023_path) expect(page.driver.status_code).to eq(400) # The user should be signed in @@ -134,7 +134,7 @@ it 'logs the user out and redirects to the sign in page' do sign_in_and_2fa_user(user) - visit api_saml_logout2022_path + visit api_saml_logout2023_path expect(page).to have_content(t('devise.sessions.signed_out')) expect(page).to have_current_path(root_path) diff --git a/spec/features/saml/saml_spec.rb b/spec/features/saml/saml_spec.rb index 0d6c2cd56c3..36febbce457 100644 --- a/spec/features/saml/saml_spec.rb +++ b/spec/features/saml/saml_spec.rb @@ -226,7 +226,7 @@ it 'redirects to root' do travel(Devise.timeout_in + 1.second) do - visit api_saml_logout2022_url + visit api_saml_logout2023_url expect(page.current_path).to eq('/') end end diff --git a/spec/features/users/sign_up_spec.rb b/spec/features/users/sign_up_spec.rb index 853bd294c36..69b75b4c49c 100644 --- a/spec/features/users/sign_up_spec.rb +++ b/spec/features/users/sign_up_spec.rb @@ -113,25 +113,22 @@ sign_up_and_set_password - freeze_time do - (IdentityConfig.store.phone_confirmation_max_attempts + 1).times do - visit phone_setup_path - fill_in 'new_phone_form_phone', with: '2025551313' - click_send_one_time_code - end + (IdentityConfig.store.phone_confirmation_max_attempts + 1).times do + visit phone_setup_path + fill_in 'new_phone_form_phone', with: '2025551313' + click_send_one_time_code + end - timeout = distance_of_time_in_words( - Throttle.attempt_window_in_minutes(:phone_confirmation).minutes, - ) + # whether it says '9 minutes' or '10 minutes' depends on how + # slowly the test runs. + throttled_message = I18n.t( + 'errors.messages.phone_confirmation_throttled', + timeout: '(10|9) minutes', + ) - expect(current_path).to eq(authentication_methods_setup_path) - expect(page).to have_content( - I18n.t( - 'errors.messages.phone_confirmation_throttled', - timeout: timeout, - ), - ) - end + expect(current_path).to eq(authentication_methods_setup_path) + + expect(page).to have_content(/#{throttled_message}/) end context 'with js', js: true do diff --git a/spec/jobs/get_usps_proofing_results_job_spec.rb b/spec/jobs/get_usps_proofing_results_job_spec.rb index 5a8fc715819..05ee63aee19 100644 --- a/spec/jobs/get_usps_proofing_results_job_spec.rb +++ b/spec/jobs/get_usps_proofing_results_job_spec.rb @@ -6,6 +6,7 @@ pending_enrollment.update( enrollment_established_at: Time.zone.now - 3.days, status_check_attempted_at: Time.zone.now - 15.minutes, + status_check_completed_at: Time.zone.now - 17.minutes, status_updated_at: Time.zone.now - 2.days, ) @@ -21,6 +22,7 @@ fraud_suspected: response['fraudSuspected'], issuer: pending_enrollment.issuer, minutes_since_last_status_check: 15.0, + minutes_since_last_status_check_completed: 17.0, minutes_since_last_status_update: 2.days.in_minutes, minutes_to_completion: 3.days.in_minutes, minutes_since_established: 3.days.in_minutes, @@ -72,6 +74,7 @@ pending_enrollment.reload expect(pending_enrollment.status_updated_at).to eq(Time.zone.now) expect(pending_enrollment.status_check_attempted_at).to eq(Time.zone.now) + expect(pending_enrollment.status_check_completed_at).to eq(Time.zone.now) expect(pending_enrollment.status).to eq(status) expect(pending_enrollment.profile.active).to eq(passed) end @@ -116,6 +119,20 @@ expect(pending_enrollment.status_check_attempted_at).to eq(Time.zone.now) end end + + it 'does not update the status_check_completed_at timestamp' do + freeze_time do + pending_enrollment.update( + status_check_attempted_at: Time.zone.now - 1.day, + status_updated_at: Time.zone.now - 2.days, + ) + job.perform(Time.zone.now) + + pending_enrollment.reload + expect(pending_enrollment.status_updated_at).to eq(Time.zone.now - 2.days) + expect(pending_enrollment.status_check_completed_at).to be_nil + end + end end RSpec.shared_examples 'enrollment_encountering_an_error_that_has_a_nil_response' do |error_type:| @@ -132,6 +149,14 @@ ), ) end + + it 'does not update the status_check_completed_at timestamp' do + freeze_time do + job.perform(Time.zone.now) + pending_enrollment.reload + expect(pending_enrollment.status_check_completed_at).to be_nil + end + end end RSpec.describe GetUspsProofingResultsJob do @@ -227,7 +252,12 @@ expect(pending_enrollments.pluck(:status_check_attempted_at)).to( all(eq nil), - 'failed test precondition: pending enrollments must not have status check time set', + 'failed test precondition: pending enrollments must not set status check attempted time', + ) + + expect(pending_enrollments.pluck(:status_check_completed_at)).to( + all(eq nil), + 'failed test precondition: pending enrollments must not set status check completed time', ) freeze_time do @@ -239,7 +269,16 @@ pluck(:status_check_attempted_at), ).to( all(eq Time.zone.now), - 'job must update status check time for all pending enrollments', + 'job must update status check attempted time for all pending enrollments', + ) + + expect( + pending_enrollments. + map(&:reload). + pluck(:status_check_completed_at), + ).to( + all(eq Time.zone.now), + 'job must update status check completed time for all pending enrollments', ) end end @@ -885,6 +924,7 @@ expect(pending_enrollment.enrollment_established_at).to eq(Time.zone.now - 3.days) expect(pending_enrollment.status_updated_at).to eq(Time.zone.now - 1.day) expect(pending_enrollment.status_check_attempted_at).to eq(Time.zone.now) + expect(pending_enrollment.status_check_completed_at).to eq(Time.zone.now) end expect(pending_enrollment.profile.active).to eq(false) diff --git a/spec/jobs/irs_attempts_events_batch_job_spec.rb b/spec/jobs/irs_attempts_events_batch_job_spec.rb index 1934641fcf9..ad1e15be1b4 100644 --- a/spec/jobs/irs_attempts_events_batch_job_spec.rb +++ b/spec/jobs/irs_attempts_events_batch_job_spec.rb @@ -79,8 +79,6 @@ allow(IdentityConfig.store).to receive(:irs_attempt_api_enabled).and_return(true) allow(IdentityConfig.store).to receive(:irs_attempt_api_aws_s3_enabled).and_return(true) - allow_any_instance_of(described_class).to receive(:reasonable_timespan?).and_return(true) - allow(IdentityConfig.store).to receive(:irs_attempt_api_public_key). and_return(encoded_public_key) diff --git a/spec/jobs/reports/sp_active_users_report_spec.rb b/spec/jobs/reports/sp_active_users_report_spec.rb index 17f18d1f179..744287037ad 100644 --- a/spec/jobs/reports/sp_active_users_report_spec.rb +++ b/spec/jobs/reports/sp_active_users_report_spec.rb @@ -7,8 +7,19 @@ let(:issuer2) { 'foo2' } let(:app_id) { 'app' } - it 'is empty' do - expect(subject.perform(Time.zone.today)).to eq('[]') + it 'has overall data' do + report = JSON.parse(subject.perform(Time.zone.today), symbolize_names: true) + + expect(report).to eq( + [ + { + issuer: nil, + app_id: nil, + total_ial1_active: 0, + total_ial2_active: 0, + }, + ], + ) end it 'returns total active user counts per sp broken down by ial1 and ial2' do @@ -31,12 +42,24 @@ user_id: 4, service_provider: issuer, uuid: 'foo4', last_ial2_authenticated_at: authenticated_time ) - result = [{ issuer: issuer, - app_id: app_id, - total_ial1_active: 2, - total_ial2_active: 3 }].to_json + result = [ + { + issuer: issuer, + app_id: app_id, + total_ial1_active: 1, + total_ial2_active: 3, + }, + { + issuer: nil, + app_id: nil, + total_ial1_active: 1, + total_ial2_active: 3, + }, + ] - expect(subject.perform(job_date)).to eq(result) + report = JSON.parse(subject.perform(job_date), symbolize_names: true) + + expect(report).to match_array(result) end it 'when Oct 1, returns total active user counts per sp by ial1 and ial2 for last fiscal year' do @@ -75,12 +98,24 @@ last_ial2_authenticated_at: current_fiscal_year ) - result = [{ issuer: issuer, - app_id: app_id, - total_ial1_active: 2, - total_ial2_active: 3 }].to_json + result = [ + { + issuer: issuer, + app_id: app_id, + total_ial1_active: 0, + total_ial2_active: 3, + }, + { + issuer: nil, + app_id: nil, + total_ial1_active: 0, + total_ial2_active: 3, + }, + ] + + report = JSON.parse(subject.perform(job_date), symbolize_names: true) - expect(subject.perform(job_date)).to eq(result) + expect(report).to match_array(result) end describe '#reporting_range' do diff --git a/spec/jobs/reports/sp_user_counts_report_spec.rb b/spec/jobs/reports/sp_user_counts_report_spec.rb index 70a2c1d9cea..316b3a6632d 100644 --- a/spec/jobs/reports/sp_user_counts_report_spec.rb +++ b/spec/jobs/reports/sp_user_counts_report_spec.rb @@ -1,68 +1,66 @@ require 'rails_helper' -describe Reports::SpUserCountsReport do +RSpec.describe Reports::SpUserCountsReport do subject { described_class.new } let(:issuer) { 'foo' } let(:app_id) { 'app_id' } - it 'is empty' do - expect(subject.perform(Time.zone.today)).to eq('[]') - end + it 'has overall data' do + report = JSON.parse(subject.perform(Time.zone.today), symbolize_names: true) - it 'logs to analytics' do - ServiceProvider.create(issuer: issuer, friendly_name: issuer, app_id: app_id) - ServiceProviderIdentity.create(user_id: 1, service_provider: issuer, uuid: 'foo2', ial: 1) - ServiceProviderIdentity.create(user_id: 2, service_provider: issuer, uuid: 'foo3', ial: 1) - ServiceProviderIdentity.create(user_id: 3, service_provider: issuer, uuid: 'foo4', ial: 2) - freeze_time do - timestamp = Time.zone.now.iso8601 - expect(subject).to receive(:write_hash_to_reports_log).with( - { - app_id: app_id, - ial1_user_total: 3, - ial2_user_total: 0, - issuer: issuer, - name: 'Report SP User Counts', - time: timestamp, - user_total: 3, - }, - ) - expect(subject).to receive(:write_hash_to_reports_log).with( + expect(report).to eq( + [ { - name: 'Report Registered Users Count', - time: timestamp, - count: 0, + issuer: nil, + total: 0, + ial1_total: 0, + ial2_total: 0, + app_id: nil, }, - ) - expect(subject).to receive(:write_hash_to_reports_log).with( - { - name: 'Report IAL1 Users Linked to SPs Count', - time: timestamp, - count: 2, - }, - ) - expect(subject).to receive(:write_hash_to_reports_log).with( - { - name: 'Report IAL2 Users Linked to SPs Count', - time: timestamp, - count: 1, - }, - ) - subject.perform(Time.zone.today) - end + ], + ) end it 'returns the total user counts per sp broken down by ial1 and ial2' do - ServiceProvider.create(issuer: issuer, friendly_name: issuer, app_id: app_id) - ServiceProviderIdentity.create(user_id: 1, service_provider: issuer, uuid: 'foo1') - ServiceProviderIdentity.create(user_id: 2, service_provider: issuer, uuid: 'foo2') - ServiceProviderIdentity.create( - user_id: 3, service_provider: issuer, uuid: 'foo3', - verified_at: Time.zone.now + create(:service_provider, issuer: issuer, app_id: app_id) + create(:service_provider_identity, user_id: 1, service_provider: issuer) + create(:service_provider_identity, user_id: 2, service_provider: issuer) + create( + :service_provider_identity, :verified, user_id: 3, service_provider: issuer ) - result = [{ issuer: issuer, total: 3, ial1_total: 2, ial2_total: 1, app_id: app_id }].to_json - expect(subject.perform(Time.zone.today)).to eq(result) + issuer2 = 'issuer2' + app_id2 = 'appid2' + create(:service_provider, issuer: issuer2, app_id: app_id2) + create(:service_provider_identity, user_id: 1, service_provider: issuer2) + + expected = [ + { + issuer: issuer, + total: 3, + ial1_total: 2, + ial2_total: 1, + app_id: app_id, + }, + { + issuer: issuer2, + total: 1, + ial1_total: 1, + ial2_total: 0, + app_id: app_id2, + }, + { + issuer: nil, + total: 3, + ial1_total: 2, + ial2_total: 1, + app_id: nil, + }, + ] + + result = JSON.parse(subject.perform(Time.zone.today), symbolize_names: true) + + expect(result).to match_array(expected) end end diff --git a/spec/lib/app_artifacts_spec.rb b/spec/lib/app_artifacts_spec.rb index c6331545552..4df950e0f0c 100644 --- a/spec/lib/app_artifacts_spec.rb +++ b/spec/lib/app_artifacts_spec.rb @@ -43,10 +43,10 @@ context 'when running locally' do it 'reads the artifact from the example folder' do store = instance.build do |store| - store.add_artifact(:test_artifact, '/%s/saml2021.crt') + store.add_artifact(:test_artifact, '/%s/saml2022.crt') end - file_path = Rails.root.join('config', 'artifacts.example', 'local', 'saml2021.crt') + file_path = Rails.root.join('config', 'artifacts.example', 'local', 'saml2022.crt') contents = File.read(file_path) expect(store.test_artifact).to eq(contents) expect(store['test_artifact']).to eq(contents) @@ -65,12 +65,12 @@ it 'allows a block to be used to transform values' do store = instance.build do |store| - store.add_artifact(:test_artifact, '/%s/saml2021.crt') do |cert| + store.add_artifact(:test_artifact, '/%s/saml2022.crt') do |cert| OpenSSL::X509::Certificate.new(cert) end end - file_path = Rails.root.join('config', 'artifacts.example', 'local', 'saml2021.crt') + file_path = Rails.root.join('config', 'artifacts.example', 'local', 'saml2022.crt') contents = File.read(file_path) expect(store.test_artifact).to be_a(OpenSSL::X509::Certificate) expect(store.test_artifact.to_pem).to eq(contents) @@ -80,7 +80,7 @@ describe '#method_missing' do it 'runs methods based on the configd artifact keys' do store = instance.build do |store| - store.add_artifact(:test_artifact, '/%s/saml2021.crt') + store.add_artifact(:test_artifact, '/%s/saml2022.crt') end expect { store.test_artifact }.to_not raise_error diff --git a/spec/lib/feature_management_spec.rb b/spec/lib/feature_management_spec.rb index 2af24ac3a32..5a06a83f728 100644 --- a/spec/lib/feature_management_spec.rb +++ b/spec/lib/feature_management_spec.rb @@ -461,4 +461,40 @@ end end end + + describe '#idv_available?' do + let(:idv_available) { true } + let(:vendor_status_acuant) { :operational } + let(:vendor_status_lexisnexis_instant_verify) { :operational } + let(:vendor_status_lexisnexis_trueid) { :operational } + + before do + allow(IdentityConfig.store).to receive(:idv_available).and_return(idv_available) + allow(IdentityConfig.store).to receive(:vendor_status_acuant).and_return(vendor_status_acuant) + allow(IdentityConfig.store).to receive(:vendor_status_lexisnexis_instant_verify). + and_return(vendor_status_lexisnexis_instant_verify) + allow(IdentityConfig.store).to receive(:vendor_status_lexisnexis_trueid). + and_return(vendor_status_lexisnexis_trueid) + end + + it 'returns true by default' do + expect(FeatureManagement.idv_available?).to eql(true) + end + + context 'idv has been disabled using config flag' do + let(:idv_available) { false } + it 'returns false' do + expect(FeatureManagement.idv_available?).to eql(false) + end + end + + %w[acuant lexisnexis_instant_verify lexisnexis_trueid].each do |service| + context "#{service} is in :full_outage" do + let("vendor_status_#{service}".to_sym) { :full_outage } + it 'returns false' do + expect(FeatureManagement.idv_available?).to eql(false) + end + end + end + end end diff --git a/spec/lib/tasks/review_profile_spec.rb b/spec/lib/tasks/review_profile_spec.rb index 6aa98f44bd2..895ce545e4b 100644 --- a/spec/lib/tasks/review_profile_spec.rb +++ b/spec/lib/tasks/review_profile_spec.rb @@ -78,6 +78,7 @@ invoke_task expect(user.reload.profiles.first.active).to eq(false) expect(user.reload.profiles.first.fraud_rejection).to eq(true) + expect(user.reload.profiles.first.fraud_rejection_at).to_not be_nil end it 'sends the user an email about their account deactivation' do diff --git a/spec/models/in_person_enrollment_spec.rb b/spec/models/in_person_enrollment_spec.rb index d15317ad867..78983e05c15 100644 --- a/spec/models/in_person_enrollment_spec.rb +++ b/spec/models/in_person_enrollment_spec.rb @@ -219,6 +219,24 @@ end end + describe 'minutes_since_last_status_check_completed' do + let(:enrollment) do + create( + :in_person_enrollment, :passed, status_check_completed_at: Time.zone.now - 2.hours + ) + end + + it 'returns number of minutes since last status check was completed' do + expect(enrollment.minutes_since_last_status_check_completed).to be_within(0.01).of(120) + end + + it 'returns nil if enrollment has not completed a status check' do + enrollment.status_check_completed_at = nil + + expect(enrollment.minutes_since_last_status_check_completed).to eq(nil) + end + end + describe 'minutes_since_status_updated' do let(:enrollment) do enrollment = create(:in_person_enrollment, :passed) diff --git a/spec/models/profile_spec.rb b/spec/models/profile_spec.rb index f701a0c7b99..e7a9087c22c 100644 --- a/spec/models/profile_spec.rb +++ b/spec/models/profile_spec.rb @@ -264,14 +264,14 @@ end it 'does not activate a profile if under fraud review' do - profile.update(fraud_review_pending: true) + profile.update(fraud_review_pending_at: Time.zone.today - 1.day) profile.activate expect(profile).to_not be_active end it 'does not activate a profile if rejected for fraud' do - profile.update(fraud_rejection: true) + profile.update(fraud_rejection_at: Time.zone.now - 1.day) profile.activate expect(profile).to_not be_active @@ -294,7 +294,10 @@ describe '#activate_after_passing_review' do it 'activates a profile if it passes fraud review' do - profile = create(:profile, user: user, active: false, fraud_review_pending: true) + profile = create( + :profile, user: user, active: false, + fraud_review_pending_at: Time.zone.today - 1.day + ) profile.activate_after_passing_review expect(profile).to be_active @@ -307,7 +310,7 @@ :profile, user: user, active: false, - fraud_review_pending: true, + fraud_review_pending_at: Time.zone.today - 1.day, initiating_service_provider: sp, ) end @@ -353,7 +356,7 @@ :profile, user: user, active: false, - fraud_review_pending: true, + fraud_review_pending_at: Time.zone.today - 1.day, initiating_service_provider: sp, ) expect(profile.initiating_service_provider.irs_attempts_api_enabled?).to be_falsey @@ -371,7 +374,9 @@ expect(profile).to_not be_active expect(profile.fraud_review_pending).to eq(true) + expect(profile.fraud_review_pending_at).to_not be_nil expect(profile.fraud_rejection).to eq(false) + expect(profile.fraud_rejection_at).to be_nil end end @@ -389,7 +394,7 @@ context 'it notifies the user' do let(:profile) do - profile = create(:profile, user: user, fraud_review_pending: true) + profile = create(:profile, user: user, fraud_review_pending_at: Time.zone.today - 1.day) profile.reject_for_fraud(notify_user: true) profile end @@ -401,11 +406,15 @@ it 'sends an email' do expect { profile }.to change(ActionMailer::Base.deliveries, :count).by(1) end + + it 'sets the fraud_rejection_at timestamp' do + expect(profile.fraud_rejection_at).to_not be_nil + end end context 'it does not notify the user' do let(:profile) do - profile = create(:profile, user: user, fraud_review_pending: true) + profile = create(:profile, user: user, fraud_review_pending_at: Time.zone.today - 1.day) profile.reject_for_fraud(notify_user: false) profile end @@ -424,7 +433,7 @@ :profile, user: user, active: false, - fraud_review_pending: true, + fraud_review_pending_at: Time.zone.today - 1.day, initiating_service_provider: sp, ) end @@ -471,7 +480,7 @@ :profile, user: user, active: false, - fraud_review_pending: true, + fraud_review_pending_at: Time.zone.today - 1.day, initiating_service_provider: sp, ) allow(IdentityConfig.store).to receive(:irs_attempt_api_enabled).and_return(true) diff --git a/spec/models/proofing_component_spec.rb b/spec/models/proofing_component_spec.rb deleted file mode 100644 index f0ba6887f40..00000000000 --- a/spec/models/proofing_component_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'rails_helper' - -RSpec.describe ProofingComponent do - describe '#review_eligible?' do - subject(:review_eligible?) do - build(:proofing_component, verified_at: verified_at).review_eligible? - end - - context 'when verified_at is nil' do - let(:verified_at) { nil } - - it { is_expected.to be_falsey } - end - - context 'when verified_at is within 30 days' do - let(:verified_at) { 15.days.ago } - - it { is_expected.to be_truthy } - end - - context 'when verified_at is older than 30 days' do - let(:verified_at) { 45.days.ago } - - it { is_expected.to be_falsey } - end - end -end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 0d826f73dce..888de6f0ca0 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -510,6 +510,35 @@ end end + describe '#fraud_review_eligible?' do + context 'when verified_at is nil' do + it 'returns false' do + user = User.new + create(:profile, user: user, fraud_review_pending: true, verified_at: nil) + + expect(user.fraud_review_eligible?).to be_falsey + end + end + + context 'when verified_at is within 30 days' do + it 'returns true' do + user = User.new + create(:profile, user: user, fraud_review_pending: true, verified_at: 15.days.ago) + + expect(user.fraud_review_eligible?).to eq true + end + end + + context 'when verified_at is older than 30 days' do + it 'returns false' do + user = User.new + create(:profile, user: user, fraud_review_pending: true, verified_at: 45.days.ago) + + expect(user.fraud_review_eligible?).to eq false + end + end + end + describe '#fraud_review_pending?' do it 'returns true if fraud review is pending' do user = User.new diff --git a/spec/services/access_token_verifier_spec.rb b/spec/services/access_token_verifier_spec.rb index ed134b39bf1..9e620cc8465 100644 --- a/spec/services/access_token_verifier_spec.rb +++ b/spec/services/access_token_verifier_spec.rb @@ -7,7 +7,13 @@ subject(:verifier) { AccessTokenVerifier.new(http_authorization_header) } let(:http_authorization_header) { "Bearer #{access_token}" } - let(:identity) { build(:service_provider_identity, access_token: SecureRandom.urlsafe_base64) } + let(:identity) do + build( + :service_provider_identity, + rails_session_id: '123', + access_token: SecureRandom.urlsafe_base64, + ) + end describe '#submit' do let(:result) { verifier.submit } diff --git a/spec/services/db/identity/sp_active_user_counts_spec.rb b/spec/services/db/identity/sp_active_user_counts_spec.rb index 87cf357b557..93f2edd2af0 100644 --- a/spec/services/db/identity/sp_active_user_counts_spec.rb +++ b/spec/services/db/identity/sp_active_user_counts_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Db::Identity::SpActiveUserCounts do +RSpec.describe Db::Identity::SpActiveUserCounts do subject { described_class } let(:fiscal_start_date) { 1.year.ago } @@ -8,96 +8,156 @@ let(:issuer2) { 'foo2' } let(:app_id1) { 'app1' } let(:app_id2) { 'app2' } + let(:now) { Time.zone.now } - it 'is empty' do - expect(subject.call(fiscal_start_date).ntuples).to eq(0) - end + describe '.by_issuer' do + it 'is empty' do + expect(subject.by_issuer(fiscal_start_date).size).to eq(0) + end - it 'returns total active user counts per sp broken down by ial1 and ial2 for ial1 only sps' do - now = Time.zone.now - ServiceProvider.create(issuer: issuer, friendly_name: issuer, app_id: 'app1') - ServiceProvider.create(issuer: issuer2, friendly_name: issuer2, app_id: 'app2') - ServiceProviderIdentity.create( - user_id: 1, service_provider: issuer, uuid: 'foo1', - last_ial1_authenticated_at: now - ) - ServiceProviderIdentity.create( - user_id: 2, service_provider: issuer, uuid: 'foo2', - last_ial1_authenticated_at: now - ) - ServiceProviderIdentity.create( - user_id: 3, service_provider: issuer2, uuid: 'foo3', - last_ial1_authenticated_at: now - ) - result = { issuer: issuer, app_id: app_id1, total_ial1_active: 2, total_ial2_active: 0 }.to_json - result2 = { issuer: issuer2, - app_id: app_id2, - total_ial1_active: 1, - total_ial2_active: 0 }.to_json - - tuples = subject.call(fiscal_start_date) - expect(tuples.ntuples).to eq(2) - expect(tuples[0].to_json).to eq(result) - expect(tuples[1].to_json).to eq(result2) - end + it 'returns total active user counts per sp broken down by ial1 and ial2 for ial1 only sps' do + ServiceProvider.create(issuer: issuer, friendly_name: issuer, app_id: 'app1') + ServiceProvider.create(issuer: issuer2, friendly_name: issuer2, app_id: 'app2') + ServiceProviderIdentity.create( + user_id: 1, service_provider: issuer, uuid: 'foo1', + last_ial1_authenticated_at: now + ) + ServiceProviderIdentity.create( + user_id: 2, service_provider: issuer, uuid: 'foo2', + last_ial1_authenticated_at: now + ) + ServiceProviderIdentity.create( + user_id: 3, service_provider: issuer2, uuid: 'foo3', + last_ial1_authenticated_at: now + ) + result = { issuer: issuer, + app_id: app_id1, + total_ial1_active: 2, + total_ial2_active: 0 }.to_json + result2 = { issuer: issuer2, + app_id: app_id2, + total_ial1_active: 1, + total_ial2_active: 0 }.to_json + + tuples = subject.by_issuer(fiscal_start_date) + expect(tuples.size).to eq(2) + expect(tuples[0].to_json).to eq(result) + expect(tuples[1].to_json).to eq(result2) + end + + it 'returns total active user counts per sp broken down by ial1 and ial2 for ial2 only sps' do + ServiceProvider.create(issuer: issuer, friendly_name: issuer, app_id: 'app1') + ServiceProvider.create(issuer: issuer2, friendly_name: issuer2, app_id: 'app2') + ServiceProviderIdentity.create( + user_id: 1, service_provider: issuer, uuid: 'foo1', + last_ial2_authenticated_at: now + ) + ServiceProviderIdentity.create( + user_id: 2, service_provider: issuer, uuid: 'foo2', + last_ial2_authenticated_at: now + ) + ServiceProviderIdentity.create( + user_id: 3, service_provider: issuer2, uuid: 'foo3', + last_ial2_authenticated_at: now + ) + result = { issuer: issuer, + app_id: app_id1, + total_ial1_active: 0, + total_ial2_active: 2 }.to_json + result2 = { issuer: issuer2, + app_id: app_id2, + total_ial1_active: 0, + total_ial2_active: 1 }.to_json + + tuples = subject.by_issuer(fiscal_start_date) + expect(tuples.size).to eq(2) + expect(tuples[0].to_json).to eq(result) + expect(tuples[1].to_json).to eq(result2) + end + + it 'returns total active user counts per sp broken down by ial1 and ial2 for ial1 ial2 sps' do + ServiceProvider.create(issuer: issuer, friendly_name: issuer, app_id: 'app1') + ServiceProvider.create(issuer: issuer2, friendly_name: issuer2, app_id: 'app2') + ServiceProviderIdentity.create( + user_id: 1, service_provider: issuer, uuid: 'foo1', + last_ial1_authenticated_at: now, last_ial2_authenticated_at: now + ) + ServiceProviderIdentity.create( + user_id: 2, service_provider: issuer, uuid: 'foo2', + last_ial1_authenticated_at: now + ) + ServiceProviderIdentity.create( + user_id: 3, service_provider: issuer2, uuid: 'foo3', + last_ial1_authenticated_at: now, last_ial2_authenticated_at: now + ) + ServiceProviderIdentity.create( + user_id: 4, service_provider: issuer2, uuid: 'foo4', + last_ial2_authenticated_at: now + ) + result = { issuer: issuer, + app_id: app_id1, + total_ial1_active: 1, + total_ial2_active: 1 }.to_json + result2 = { issuer: issuer2, + app_id: app_id2, + total_ial1_active: 0, + total_ial2_active: 2 }.to_json - it 'returns total active user counts per sp broken down by ial1 and ial2 for ial2 only sps' do - now = Time.zone.now - ServiceProvider.create(issuer: issuer, friendly_name: issuer, app_id: 'app1') - ServiceProvider.create(issuer: issuer2, friendly_name: issuer2, app_id: 'app2') - ServiceProviderIdentity.create( - user_id: 1, service_provider: issuer, uuid: 'foo1', - last_ial2_authenticated_at: now - ) - ServiceProviderIdentity.create( - user_id: 2, service_provider: issuer, uuid: 'foo2', - last_ial2_authenticated_at: now - ) - ServiceProviderIdentity.create( - user_id: 3, service_provider: issuer2, uuid: 'foo3', - last_ial2_authenticated_at: now - ) - result = { issuer: issuer, app_id: app_id1, total_ial1_active: 0, total_ial2_active: 2 }.to_json - result2 = { issuer: issuer2, - app_id: app_id2, - total_ial1_active: 0, - total_ial2_active: 1 }.to_json - - tuples = subject.call(fiscal_start_date) - expect(tuples.ntuples).to eq(2) - expect(tuples[0].to_json).to eq(result) - expect(tuples[1].to_json).to eq(result2) + tuples = subject.by_issuer(fiscal_start_date) + expect(tuples.size).to eq(2) + expect(tuples[0].to_json).to eq(result) + expect(tuples[1].to_json).to eq(result2) + end end - it 'returns total active user counts per sp broken down by ial1 and ial2 for ial1 ial2 sps' do - now = Time.zone.now - ServiceProvider.create(issuer: issuer, friendly_name: issuer, app_id: 'app1') - ServiceProvider.create(issuer: issuer2, friendly_name: issuer2, app_id: 'app2') - ServiceProviderIdentity.create( - user_id: 1, service_provider: issuer, uuid: 'foo1', - last_ial1_authenticated_at: now, last_ial2_authenticated_at: now - ) - ServiceProviderIdentity.create( - user_id: 2, service_provider: issuer, uuid: 'foo2', - last_ial1_authenticated_at: now - ) - ServiceProviderIdentity.create( - user_id: 3, service_provider: issuer2, uuid: 'foo3', - last_ial1_authenticated_at: now, last_ial2_authenticated_at: now - ) - ServiceProviderIdentity.create( - user_id: 4, service_provider: issuer2, uuid: 'foo4', - last_ial2_authenticated_at: now - ) - result = { issuer: issuer, app_id: app_id1, total_ial1_active: 2, total_ial2_active: 1 }.to_json - result2 = { issuer: issuer2, - app_id: app_id2, - total_ial1_active: 1, - total_ial2_active: 2 }.to_json - - tuples = subject.call(fiscal_start_date) - expect(tuples.ntuples).to eq(2) - expect(tuples[0].to_json).to eq(result) - expect(tuples[1].to_json).to eq(result2) + describe '.overall' do + let(:sp1) { create(:service_provider) } + let(:sp2) { create(:service_provider) } + + it 'has placeholder rows with no data' do + result = subject.overall(fiscal_start_date) + + expect(result.size).to eq(1) + expect(result.first).to eq( + 'issuer' => nil, + 'app_id' => nil, + 'total_ial1_active' => 0, + 'total_ial2_active' => 0, + ) + end + + it 'counts the numbers of users that were ial1 active and ial2 active' do + # ial1 and ial2, counts as ial2 + create( + :service_provider_identity, + user_id: 1, + service_provider_record: sp1, + last_ial1_authenticated_at: now, + ) + create( + :service_provider_identity, + user_id: 1, + service_provider_record: sp2, + last_ial2_authenticated_at: now, + ) + + # ial1 only, counts as ial1 + create( + :service_provider_identity, + user_id: 2, + service_provider_record: sp1, + last_ial1_authenticated_at: now, + ) + + result = subject.overall(fiscal_start_date) + + expect(result.size).to eq(1) + expect(result.first).to eq( + 'issuer' => nil, + 'app_id' => nil, + 'total_ial1_active' => 1, + 'total_ial2_active' => 1, + ) + end end end diff --git a/spec/services/db/identity/sp_user_counts_spec.rb b/spec/services/db/identity/sp_user_counts_spec.rb index bca11a850ca..85c6f998770 100644 --- a/spec/services/db/identity/sp_user_counts_spec.rb +++ b/spec/services/db/identity/sp_user_counts_spec.rb @@ -1,36 +1,74 @@ require 'rails_helper' -describe Db::Identity::SpUserCounts do +RSpec.describe Db::Identity::SpUserCounts do subject { described_class } - let(:issuer) { 'foo' } - let(:app_id) { 'app_id' } - let(:issuer2) { 'foo2' } - let(:app_id2) { 'app_id2' } + describe '.by_issuer' do + let(:issuer) { 'foo' } + let(:app_id) { 'app_id' } + let(:issuer2) { 'foo2' } + let(:app_id2) { 'app_id2' } - it 'is empty' do - expect(subject.call.ntuples).to eq(0) + it 'is empty' do + expect(subject.by_issuer.size).to eq(0) + end + + it 'returns the total user counts per sp broken down by ial1 and ial2' do + ServiceProvider.create(issuer: issuer, friendly_name: issuer, app_id: app_id) + ServiceProvider.create(issuer: issuer2, friendly_name: issuer2, app_id: app_id2) + ServiceProviderIdentity.create(user_id: 1, service_provider: issuer, uuid: 'foo1') + ServiceProviderIdentity.create(user_id: 2, service_provider: issuer, uuid: 'foo2') + ServiceProviderIdentity.create( + user_id: 3, service_provider: issuer, uuid: 'foo3', + verified_at: Time.zone.now + ) + ServiceProviderIdentity.create( + user_id: 4, service_provider: issuer2, uuid: 'foo4', + verified_at: Time.zone.now + ) + result = { issuer: issuer, total: 3, ial1_total: 2, ial2_total: 1, app_id: app_id }.to_json + result2 = { issuer: issuer2, total: 1, ial1_total: 0, ial2_total: 1, app_id: app_id2 }.to_json + + tuples = subject.by_issuer + expect(tuples.size).to eq(2) + expect(tuples[0].to_json).to eq(result) + expect(tuples[1].to_json).to eq(result2) + end end - it 'returns the total user counts per sp broken down by ial1 and ial2' do - ServiceProvider.create(issuer: issuer, friendly_name: issuer, app_id: app_id) - ServiceProvider.create(issuer: issuer2, friendly_name: issuer2, app_id: app_id2) - ServiceProviderIdentity.create(user_id: 1, service_provider: issuer, uuid: 'foo1') - ServiceProviderIdentity.create(user_id: 2, service_provider: issuer, uuid: 'foo2') - ServiceProviderIdentity.create( - user_id: 3, service_provider: issuer, uuid: 'foo3', - verified_at: Time.zone.now - ) - ServiceProviderIdentity.create( - user_id: 4, service_provider: issuer2, uuid: 'foo4', - verified_at: Time.zone.now - ) - result = { issuer: issuer, total: 3, ial1_total: 2, ial2_total: 1, app_id: app_id }.to_json - result2 = { issuer: issuer2, total: 1, ial1_total: 0, ial2_total: 1, app_id: app_id2 }.to_json - - tuples = subject.call - expect(tuples.ntuples).to eq(2) - expect(tuples[0].to_json).to eq(result) - expect(tuples[1].to_json).to eq(result2) + describe '.overall' do + let(:sp1) { create(:service_provider) } + let(:sp2) { create(:service_provider) } + + it 'has zeroes with no data' do + result = subject.overall + expect(result.size).to eq(1) + + expect(result.first).to eq( + 'issuer' => nil, + 'app_id' => nil, + 'total' => 0, + 'ial1_total' => 0, + 'ial2_total' => 0, + ) + end + + it 'aggregates across all issuers' do + create(:service_provider_identity, user_id: 1, service_provider_record: sp1) + create(:service_provider_identity, :verified, user_id: 1, service_provider_record: sp2) + + create(:service_provider_identity, user_id: 2, service_provider_record: sp1) + + result = subject.overall + expect(result.size).to eq(1) + + expect(result.first).to eq( + 'issuer' => nil, + 'app_id' => nil, + 'total' => 2, + 'ial1_total' => 1, + 'ial2_total' => 1, + ) + end end end diff --git a/spec/services/id_token_builder_spec.rb b/spec/services/id_token_builder_spec.rb index 17b11420f10..e67521855c7 100644 --- a/spec/services/id_token_builder_spec.rb +++ b/spec/services/id_token_builder_spec.rb @@ -11,6 +11,7 @@ nonce: SecureRandom.hex, uuid: SecureRandom.uuid, ial: 2, + rails_session_id: '123', # this is a known value from an example developer guide # https://www.pingidentity.com/content/developer/en/resources/openid-connect-developers-guide.html access_token: 'dNZX1hEZ9wBCzNL40Upu646bdzQA', diff --git a/spec/services/idv/steps/in_person/verify_step_spec.rb b/spec/services/idv/steps/in_person/verify_step_spec.rb index 61fac585527..e21f8070e92 100644 --- a/spec/services/idv/steps/in_person/verify_step_spec.rb +++ b/spec/services/idv/steps/in_person/verify_step_spec.rb @@ -141,11 +141,5 @@ def redirect(step_instance) expect(redirect(user2_step)).to eq(idv_session_errors_ssn_failure_url) end end - - it 'updates proofing component vendor' do - step.call - - expect(user.proofing_component.document_check).to eq Idp::Constants::Vendors::USPS - end end end diff --git a/spec/services/outage_status_spec.rb b/spec/services/outage_status_spec.rb index 8c1f234bda0..84bb778b259 100644 --- a/spec/services/outage_status_spec.rb +++ b/spec/services/outage_status_spec.rb @@ -1,11 +1,8 @@ require 'rails_helper' describe OutageStatus do - let(:from) { nil } - let(:from_idv) { nil } - let(:sp) { nil } subject(:vendor_status) do - OutageStatus.new(from: from, from_idv: from_idv, sp: sp) + OutageStatus.new end it 'raises an error if passed an unknown vendor' do @@ -52,38 +49,8 @@ expect(subject.any_idv_vendor_outage?).to be end - context 'user coming from create_account' do - let(:from) { SignUp::RegistrationsController::CREATE_ACCOUNT } - - it 'returns the correct message' do - expect(subject.outage_message).to eq I18n.t('vendor_outage.blocked.idv.generic') - end - end - - context 'user coming from idv flow' do - let(:from) { :welcome } - let(:from_idv) { true } - - context 'no service_provider in session' do - it 'returns the correct message' do - expect(subject.outage_message).to eq( - I18n.t('vendor_outage.blocked.idv.without_sp'), - ) - end - end - - context 'with service_provider in session' do - let(:sp) { create(:service_provider) } - - it 'returns the correct message tailored to the service provider' do - expect(subject.outage_message).to eq( - I18n.t( - 'vendor_outage.blocked.idv.with_sp', - service_provider: sp.friendly_name, - ), - ) - end - end + it 'returns the correct message' do + expect(subject.outage_message).to eq I18n.t('vendor_outage.blocked.idv.generic') end end @@ -171,14 +138,6 @@ it 'returns default phone outage message' do expect(outage_message).to eq(t('vendor_outage.blocked.phone.default')) end - - context 'from idv' do - let(:from_idv) { true } - - it 'returns idv phone outage message' do - expect(outage_message).to eq(t('vendor_outage.blocked.phone.idv')) - end - end end end @@ -187,7 +146,7 @@ analytics = FakeAnalytics.new expect(analytics).to receive(:track_event).with( 'Vendor Outage', - redirect_from: from, + redirect_from: nil, vendor_status: OutageStatus::ALL_VENDORS.index_with do |_vendor| satisfy { |status| IdentityConfig::VENDOR_STATUS_OPTIONS.include?(status) } end, diff --git a/spec/services/pii/attributes_spec.rb b/spec/services/pii/attributes_spec.rb index 73deb5a7241..69cdd51c7e8 100644 --- a/spec/services/pii/attributes_spec.rb +++ b/spec/services/pii/attributes_spec.rb @@ -43,6 +43,7 @@ state_id_city: 'Washington', state_id_jurisdiction: 'DC', state_id_zipcode: '20005', + state_id_state: 'NY', ) expect(pii.state_id_address1).to eq('1600 Pennsylvania Avenue') @@ -50,6 +51,7 @@ expect(pii.state_id_city).to eq('Washington') expect(pii.state_id_jurisdiction).to eq('DC') expect(pii.state_id_zipcode).to eq('20005') + expect(pii.state_id_state).to eq('NY') end end diff --git a/spec/services/saml_endpoint_spec.rb b/spec/services/saml_endpoint_spec.rb index ca059b822ab..8f3b4f4834d 100644 --- a/spec/services/saml_endpoint_spec.rb +++ b/spec/services/saml_endpoint_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' describe SamlEndpoint do - let(:path) { '/api/saml/auth2022' } + let(:path) { '/api/saml/auth2023' } let(:request) do request_double = double allow(request_double).to receive(:path).and_return(path) @@ -14,7 +14,7 @@ it 'should list the suffixes that are configured' do result = described_class.suffixes - expect(result).to eq(%w[2022]) + expect(result).to eq(%w[2023]) end end @@ -24,7 +24,7 @@ expect(result).to eq( [ - { suffix: '2022', secret_key_passphrase: 'trust-but-verify' }, + { suffix: '2023', secret_key_passphrase: 'trust-but-verify' }, ], ) end @@ -36,7 +36,7 @@ subject.secret_key.to_pem, ).to eq( OpenSSL::PKey::RSA.new( - AppArtifacts.store.saml_2022_key, + AppArtifacts.store.saml_2023_key, 'trust-but-verify', ).to_pem, ) @@ -66,7 +66,7 @@ expect( subject.x509_certificate, ).to eq( - AppArtifacts.store.saml_2022_cert, + AppArtifacts.store.saml_2023_cert, ) end end @@ -75,7 +75,7 @@ it 'returns the saml metadata with the suffix added to the urls' do result = subject.saml_metadata - expect(result.configurator.single_service_post_location).to match(%r{api/saml/auth2022\Z}) + expect(result.configurator.single_service_post_location).to match(%r{api/saml/auth2023\Z}) end it 'does not include the SingLogoutService endpoints when configured' do @@ -93,10 +93,10 @@ result = subject.saml_metadata expect(result.configurator.single_logout_service_post_location).to match( - %r{api/saml/logout2022\Z}, + %r{api/saml/logout2023\Z}, ) expect(result.configurator.remote_logout_service_post_location).to match( - %r{api/saml/remotelogout2022\Z}, + %r{api/saml/remotelogout2023\Z}, ) end end diff --git a/spec/services/usps_in_person_proofing/enrollment_helper_spec.rb b/spec/services/usps_in_person_proofing/enrollment_helper_spec.rb index b8309908231..c32a3d399cc 100644 --- a/spec/services/usps_in_person_proofing/enrollment_helper_spec.rb +++ b/spec/services/usps_in_person_proofing/enrollment_helper_spec.rb @@ -9,7 +9,7 @@ let(:pii) do Pii::Attributes.new_from_hash( Idp::Constants::MOCK_IDV_APPLICANT_WITH_PHONE. - merge(same_address_as_id: current_address_matches_id). + merge(same_address_as_id: current_address_matches_id ? 'true' : 'false'). transform_keys(&:to_s), ) end @@ -101,7 +101,7 @@ let(:pii) do Pii::Attributes.new_from_hash( Idp::Constants::MOCK_IDV_APPLICANT_WITH_PHONE. - merge(same_address_as_id: current_address_matches_id). + merge(same_address_as_id: current_address_matches_id ? 'true' : 'false'). merge(Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS). transform_keys(&:to_s), ) @@ -121,7 +121,7 @@ }", city: Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[:state_id_city], state: Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[ - :state_id_jurisdiction + :state_id_state ], zip_code: Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[:state_id_zipcode], ) diff --git a/spec/support/features/idv_step_helper.rb b/spec/support/features/idv_step_helper.rb index 88f33b7ab49..e1e6f139772 100644 --- a/spec/support/features/idv_step_helper.rb +++ b/spec/support/features/idv_step_helper.rb @@ -116,7 +116,7 @@ def complete_idv_steps_before_step(step, user = user_with_2fa) end def expect_step_indicator_current_step(text) - expect(page).to have_css('.step-indicator__step--current', text: text) + expect(page).to have_css('.step-indicator__step--current', text: text, wait: 5) end private diff --git a/spec/support/features/in_person_helper.rb b/spec/support/features/in_person_helper.rb index fa52c358d19..a6eb1f629cc 100644 --- a/spec/support/features/in_person_helper.rb +++ b/spec/support/features/in_person_helper.rb @@ -23,6 +23,7 @@ module InPersonHelper GOOD_STATE = Idp::Constants::MOCK_IDV_APPLICANT_FULL_STATE GOOD_STATE_ID_ADDRESS1 = Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[:state_id_address1] GOOD_STATE_ID_ADDRESS2 = Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[:state_id_address2] + GOOD_STATE_ID_STATE = Idp::Constants::MOCK_IDV_APPLICANT_FULL_STATE_ID_STATE GOOD_STATE_ID_CITY = Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[:city] GOOD_STATE_ID_ZIPCODE = Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[:zipcode] @@ -43,8 +44,10 @@ def fill_out_state_id_form_ok(double_address_verification: false, same_address_a fill_in t('in_person_proofing.form.state_id.city'), with: GOOD_STATE_ID_CITY fill_in t('in_person_proofing.form.state_id.zipcode'), with: GOOD_STATE_ID_ZIPCODE if same_address_as_id + select GOOD_STATE_ID_STATE, from: t('in_person_proofing.form.state_id.state_id_state') choose t('in_person_proofing.form.state_id.same_address_as_id_yes') else + select GOOD_STATE, from: t('in_person_proofing.form.state_id.state_id_state') choose t('in_person_proofing.form.state_id.same_address_as_id_no') end end @@ -59,11 +62,11 @@ def fill_out_address_form_ok(double_address_verification: false, same_address_as fill_in t('idv.form.city'), with: same_address_as_id ? GOOD_STATE_ID_CITY : GOOD_CITY fill_in t('idv.form.zipcode'), with: same_address_as_id ? GOOD_STATE_ID_ZIPCODE : GOOD_ZIPCODE if same_address_as_id - select GOOD_STATE_ID_JURISDICTION, - from: t('in_person_proofing.form.state_id.state_id_jurisdiction') + select GOOD_STATE_ID_STATE, from: t('idv.form.state') else select GOOD_STATE, from: t('idv.form.state') end + unless double_address_verification choose t('in_person_proofing.form.address.same_address_choice_yes') end @@ -73,7 +76,7 @@ def begin_in_person_proofing(_user = nil) complete_doc_auth_steps_before_document_capture_step mock_doc_auth_attention_with_barcode attach_and_submit_images - click_link t('in_person_proofing.body.cta.button') + click_button t('in_person_proofing.body.cta.button') end def search_for_post_office diff --git a/spec/support/idv_examples/max_attempts.rb b/spec/support/idv_examples/max_attempts.rb index 7f5e232ea09..cdf3c580f7c 100644 --- a/spec/support/idv_examples/max_attempts.rb +++ b/spec/support/idv_examples/max_attempts.rb @@ -1,12 +1,7 @@ shared_examples 'verification step max attempts' do |step, sp| include ActionView::Helpers::DateHelper - let(:locale) { LinkLocaleResolver.locale } let(:user) { user_with_2fa } - let(:step_locale_key) do - return :sessions if step == :profile - step - end before do start_idv_from_sp(sp) @@ -33,12 +28,12 @@ end scenario 'user sees the failure screen' do - expect(page).to have_content(t("idv.failure.#{step_locale_key}.heading")) + expect(page).to have_content(t('idv.failure.phone.rate_limited.heading')) expect(page).to have_content( strip_tags( t( - 'idv.failure.phone.fail_html', - timeout: distance_of_time_in_words( + 'idv.failure.phone.rate_limited.body', + time_left: distance_of_time_in_words( IdentityConfig.store.idv_attempt_window_in_hours.hours, ), ), @@ -52,7 +47,7 @@ (Throttle.max_attempts(:proof_address) - 1).times do fill_out_phone_form_fail click_idv_continue_for_step(step) - click_on t('idv.failure.button.warning') + click_on t('idv.failure.phone.warning.try_again_button') end fill_out_phone_form_ok @@ -67,15 +62,15 @@ def perfom_maximum_allowed_idv_step_attempts(step) (Throttle.max_attempts(:proof_address) - 1).times do yield click_idv_continue_for_step(step) - click_on t('idv.failure.button.warning') + click_on t('idv.failure.phone.warning.try_again_button') end yield click_idv_continue_for_step(step) end def expect_user_to_fail_at_phone_step - expect(page).to have_content(t("idv.failure.#{step_locale_key}.heading")) - expect(current_url).to eq(idv_phone_errors_failure_url(locale: locale)) - expect(page).to have_link(t('idv.troubleshooting.options.verify_by_mail')) + expect(page).to have_content(t('idv.failure.phone.rate_limited.heading')) + expect(current_url).to eq(idv_phone_errors_failure_url) + expect(page).to have_link(t('idv.failure.phone.rate_limited.gpo.button')) end end diff --git a/spec/support/idv_examples/sp_requested_attributes.rb b/spec/support/idv_examples/sp_requested_attributes.rb index e06efed3f06..f61de453275 100644 --- a/spec/support/idv_examples/sp_requested_attributes.rb +++ b/spec/support/idv_examples/sp_requested_attributes.rb @@ -71,7 +71,7 @@ if javascript_enabled? expect(current_path).to eq(test_saml_decode_assertion_path) else - expect(current_url).to include(api_saml_auth2022_url) + expect(current_url).to include(api_saml_auth2023_url) end end end diff --git a/spec/support/matchers/have_actions.rb b/spec/support/matchers/have_actions.rb index 70583f08a51..cb57b06c5a0 100644 --- a/spec/support/matchers/have_actions.rb +++ b/spec/support/matchers/have_actions.rb @@ -71,9 +71,7 @@ def parsed_only_action(action) end def parsed_except_action(action) - except_option = unless_option_for(action)[0] - - "#{except_option.class}OptionParser".constantize.new(except_option).parse + unless_option_for(action)[0].instance_variable_get(:@actions).to_a end class ProcOptionParser diff --git a/spec/support/saml_auth_helper.rb b/spec/support/saml_auth_helper.rb index 0973f2a1993..a0fe9c8c2ca 100644 --- a/spec/support/saml_auth_helper.rb +++ b/spec/support/saml_auth_helper.rb @@ -23,8 +23,8 @@ def saml_settings(overrides: {}) settings.double_quote_xml_attribute_values = true # IdP setting - settings.idp_sso_target_url = "http://#{IdentityConfig.store.domain_name}/api/saml/auth2022" - settings.idp_slo_target_url = "http://#{IdentityConfig.store.domain_name}/api/saml/logout2022" + settings.idp_sso_target_url = "http://#{IdentityConfig.store.domain_name}/api/saml/auth2023" + settings.idp_slo_target_url = "http://#{IdentityConfig.store.domain_name}/api/saml/logout2023" settings.idp_cert_fingerprint = idp_fingerprint settings.idp_cert_fingerprint_algorithm = 'http://www.w3.org/2001/04/xmlenc#sha256' @@ -79,7 +79,7 @@ def saml_logout_request_url(overrides: {}, params: {}) end def saml_remote_logout_request_url(overrides: {}, params: {}) - overrides[:idp_slo_target_url] = "http://#{IdentityConfig.store.domain_name}/api/saml/remotelogout2022" + overrides[:idp_slo_target_url] = "http://#{IdentityConfig.store.domain_name}/api/saml/remotelogout2023" logout_request.create( saml_settings(overrides: overrides), params, @@ -108,12 +108,12 @@ def saml_get_auth(settings) def saml_post_auth(saml_request) # POST redirect binding Authn Request - request.path = '/api/saml/authpost2022' + request.path = '/api/saml/authpost2023' post :auth, params: { SAMLRequest: CGI.unescape(saml_request) } end def saml_final_post_auth(saml_request) - request.path = '/api/saml/finalauthpost2022' + request.path = '/api/saml/finalauthpost2023' post :auth, params: { SAMLRequest: CGI.unescape(saml_request) } end @@ -130,7 +130,7 @@ def saml_test_sp_key end def saml_test_idp_cert - AppArtifacts.store.saml_2022_cert + AppArtifacts.store.saml_2023_cert end public diff --git a/spec/views/idv/phone_errors/failure.html.erb_spec.rb b/spec/views/idv/phone_errors/failure.html.erb_spec.rb index 02ac43246e8..9367bae1c66 100644 --- a/spec/views/idv/phone_errors/failure.html.erb_spec.rb +++ b/spec/views/idv/phone_errors/failure.html.erb_spec.rb @@ -3,6 +3,7 @@ describe 'idv/phone_errors/failure.html.erb' do let(:sp_name) { 'Example SP' } let(:timeout_hours) { 6 } + let(:gpo_letter_available) { true } around do |ex| freeze_time { ex.run } @@ -11,7 +12,7 @@ before do decorated_session = instance_double(ServiceProviderSessionDecorator, sp_name: sp_name) allow(view).to receive(:decorated_session).and_return(decorated_session) - assign(:gpo_letter_available, true) + assign(:gpo_letter_available, gpo_letter_available) allow(IdentityConfig.store).to receive(:idv_attempt_window_in_hours).and_return(timeout_hours) @expires_at = Time.zone.now + timeout_hours.hours @@ -34,10 +35,36 @@ expect(rendered).to have_text( strip_tags( t( - 'idv.failure.phone.fail_html', - timeout: distance_of_time_in_words(timeout_hours.hours), + 'idv.failure.phone.rate_limited.body', + time_left: distance_of_time_in_words(timeout_hours.hours), ), ), ) end + + it 'describes GPO as an alternative' do + expect(rendered).to have_text(t('idv.failure.phone.rate_limited.gpo.prompt')) + end + + it 'includes a link to GPO flow' do + expect(rendered).to have_css( + '.usa-button', + text: t('idv.failure.phone.rate_limited.gpo.button'), + ) + end + + context 'GPO is not available' do + let(:gpo_letter_available) { false } + + it 'does not describe GPO as an alternative' do + expect(rendered).not_to have_text(t('idv.failure.phone.rate_limited.gpo.prompt')) + end + + it 'does not include a link to GPO flow' do + expect(rendered).not_to have_css( + '.usa-button', + text: t('idv.failure.phone.rate_limited.gpo.button'), + ) + end + end end diff --git a/spec/views/idv/phone_errors/warning.html.erb_spec.rb b/spec/views/idv/phone_errors/warning.html.erb_spec.rb index 71e20bc0a2e..62a1e929a99 100644 --- a/spec/views/idv/phone_errors/warning.html.erb_spec.rb +++ b/spec/views/idv/phone_errors/warning.html.erb_spec.rb @@ -4,27 +4,78 @@ let(:sp_name) { 'Example SP' } let(:remaining_attempts) { 5 } let(:gpo_letter_available) { false } + let(:phone) { '+13602345678' } + let(:country_code) { 'US' } + let(:formatted_phone) { '+1 360-234-5678' } before do decorated_session = instance_double(ServiceProviderSessionDecorator, sp_name: sp_name) allow(view).to receive(:decorated_session).and_return(decorated_session) assign(:gpo_letter_available, gpo_letter_available) - assign(:remaining_attempts, remaining_attempts) + assign(:country_code, country_code) + assign(:phone, phone) render end - it 'shows warning text' do - expect(rendered).to have_text(t('idv.failure.phone.warning')) + it 'shows correct h1' do + expect(rendered).to have_css('h1', text: t('idv.failure.phone.warning.heading')) end - it 'shows a primary action' do - expect(rendered).to have_link(t('idv.failure.button.warning'), href: idv_phone_path) + it 'shows number entered' do + expect(rendered).to have_text(t('idv.failure.phone.warning.you_entered')) + expect(rendered).to have_text(formatted_phone) + end + + it 'shows next steps' do + expect(rendered).to include(t('idv.failure.phone.warning.next_steps_html')) + end + + it 'links to help screen' do + expect(rendered).to have_link( + t('idv.failure.phone.warning.learn_more_link'), + href: help_center_redirect_path( + category: 'verify-your-identity', + article: 'phone-number', + flow: :idv, + step: :phone, + location: 'learn_more', + ), + ) end it 'shows remaining attempts' do - expect(rendered).to have_text(t('idv.failure.attempts', count: remaining_attempts)) + expect(rendered).to have_text( + t( + 'idv.failure.phone.warning.attempts', + count: remaining_attempts, + ), + ) + end + + it 'shows a primary action' do + expect(rendered).to have_link( + t('idv.failure.phone.warning.try_again_button'), + href: idv_phone_path, + ) + end + + it 'renders a list of troubleshooting options' do + expect(rendered).to have_link( + t('idv.troubleshooting.options.get_help_at_sp', sp_name: sp_name), + href: return_to_sp_failure_to_proof_path(step: 'phone', location: 'warning'), + ) + end + + context 'no sp' do + let(:sp_name) { nil } + it 'does not prompt user to get help at sp' do + expect(rendered).not_to have_link( + t('idv.troubleshooting.options.get_help_at_sp', sp_name: sp_name), + href: return_to_sp_failure_to_proof_path(step: 'phone', location: 'warning'), + ) + end end context 'gpo verification disabled' do @@ -33,6 +84,8 @@ t('idv.troubleshooting.options.get_help_at_sp', sp_name: sp_name), href: return_to_sp_failure_to_proof_path(step: 'phone', location: 'warning'), ) + end + it 'does not render link to gpo flow' do expect(rendered).not_to have_link( t('idv.troubleshooting.options.verify_by_mail'), href: idv_gpo_path, @@ -43,15 +96,25 @@ context 'gpo verification enabled' do let(:gpo_letter_available) { true } - it 'renders a list of troubleshooting options' do - expect(rendered).to have_link( - t('idv.troubleshooting.options.get_help_at_sp', sp_name: sp_name), - href: return_to_sp_failure_to_proof_path(step: 'phone', location: 'warning'), + it 'has an h2' do + expect(rendered).to have_css('h2', text: t('idv.failure.phone.warning.gpo.heading')) + end + + it 'explains gpo' do + expect(rendered).to have_text( + t('idv.failure.phone.warning.gpo.explanation'), ) - expect(rendered).to have_link( - t('idv.troubleshooting.options.verify_by_mail'), - href: idv_gpo_path, + end + + it 'says how long gpo takes' do + expect(rendered).to have_css( + 'strong', + text: t('idv.failure.phone.warning.gpo.how_long_it_takes'), ) end + + it 'has a secondary cta' do + expect(rendered).to have_link(t('idv.failure.phone.warning.gpo.button'), href: idv_gpo_path) + end end end diff --git a/spec/views/idv/shared/_error.html.erb_spec.rb b/spec/views/idv/shared/_error.html.erb_spec.rb index 3f5439ee979..8ab6c5f2225 100644 --- a/spec/views/idv/shared/_error.html.erb_spec.rb +++ b/spec/views/idv/shared/_error.html.erb_spec.rb @@ -7,12 +7,15 @@ let(:action) { nil } let(:action_secondary) { nil } let(:type) { nil } + let(:current_step) { nil } + let(:step_indicator_steps) { nil } let(:params) do { type: type, heading: heading, action: action, action_secondary: action_secondary, + current_step: current_step, options: options, } end @@ -21,6 +24,10 @@ decorated_session = instance_double(ServiceProviderSessionDecorator, sp_name: sp_name) allow(view).to receive(:decorated_session).and_return(decorated_session) + if step_indicator_steps + allow(view).to receive(:step_indicator_steps).and_return(step_indicator_steps) + end + render 'idv/shared/error', **params end @@ -163,4 +170,32 @@ end end end + + describe 'current_step' do + it 'does not render a step indicator by default' do + expect(view.content_for(:pre_flash_content)).not_to have_css('lg-step-indicator') + end + + context 'current_step provided' do + let(:current_step) { :verify_phone_or_address } + + it 'does not render a step indicator' do + expect(view.content_for(:pre_flash_content)).not_to have_css('lg-step-indicator') + end + + context 'step_indicator_steps helper available' do + let(:step_indicator_steps) { Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS } + it 'renders a step indicator' do + expect(view.content_for(:pre_flash_content)).to have_css('lg-step-indicator') + end + + it 'selects the correct step' do + expect(view.content_for(:pre_flash_content)).to have_css( + '.step-indicator__step--current .step-indicator__step-title', + text: t('step_indicator.flows.idv.verify_phone_or_address'), + ) + end + end + end + end end diff --git a/spec/views/idv/unavailable/show.html.erb_spec.rb b/spec/views/idv/unavailable/show.html.erb_spec.rb new file mode 100644 index 00000000000..502a5e2f796 --- /dev/null +++ b/spec/views/idv/unavailable/show.html.erb_spec.rb @@ -0,0 +1,52 @@ +require 'rails_helper' + +describe 'idv/unavailable/show.html.erb' do + let(:sp_name) { nil } + subject(:rendered) { render } + + before do + allow(view).to receive(:decorated_session).and_return( + instance_double(ServiceProviderSessionDecorator, sp_name: sp_name), + ) + end + + it 'sets a title' do + expect(view).to receive(:title).with(t('idv.titles.unavailable')) + render + end + it 'has an h1' do + expect(rendered).to have_selector('h1', text: t('idv.titles.unavailable')) + end + it 'links to the status page in a new window' do + expect(rendered).to have_selector( + 'a[target=_blank]', + text: t('idv.unavailable.status_page_link'), + ) + end + + describe('exit button') do + it 'is rendered' do + expect(rendered).to have_selector( + 'a', + text: t('idv.unavailable.exit_button', app_name: APP_NAME), + ) + end + it 'links to the right place' do + expect(rendered).to have_link( + t('idv.unavailable.exit_button', app_name: APP_NAME), + href: return_to_sp_failure_to_proof_path(location: 'unavailable'), + ) + end + end + + it 'does not render any l13n markers' do + expect(rendered).not_to include('%{') + end + + context 'with sp' do + let(:sp_name) { 'Department of Ice Cream' } + it 'renders the explanation with the sp name' do + expect(rendered).to include(sp_name) + end + end +end diff --git a/spec/views/layouts/application.html.erb_spec.rb b/spec/views/layouts/application.html.erb_spec.rb index 14e1dc36ff7..94d95663f0a 100644 --- a/spec/views/layouts/application.html.erb_spec.rb +++ b/spec/views/layouts/application.html.erb_spec.rb @@ -167,6 +167,7 @@ it 'it render the new relic javascript' do allow(IdentityConfig.store).to receive(:newrelic_browser_key).and_return('foo') allow(IdentityConfig.store).to receive(:newrelic_browser_app_id).and_return('foo') + allow(BrowserSupport).to receive(:supported?).and_return(true) render