diff --git a/app/controllers/concerns/idv/verify_info_concern.rb b/app/controllers/concerns/idv/verify_info_concern.rb index 0166442e024..a9de14f38f1 100644 --- a/app/controllers/concerns/idv/verify_info_concern.rb +++ b/app/controllers/concerns/idv/verify_info_concern.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true module Idv + # @attr idv_session [Idv::Session] module VerifyInfoConcern extend ActiveSupport::Concern @@ -39,6 +40,16 @@ def shared_update threatmetrix_session_id: idv_session.threatmetrix_session_id, request_ip: request.remote_ip, ipp_enrollment_in_progress: ipp_enrollment_in_progress?, + # Attempting to get the current set of proofing components + # so we can "see" document_check vendor. + # Unclear if the document_check vendor at this point is static though + # May need to save the field onto session + proofing_components: ProofingComponents.new( + user: current_user, + idv_session:, + session:, + user_session:, + ), ) return true @@ -354,5 +365,9 @@ def delete_threatmetrix_response_body(form_response) def add_cost(token, transaction_id: nil) Db::SpCost::AddSpCost.call(current_sp, token, transaction_id: transaction_id) end + + def user_session + current_user && session&.dig('warden.user.user.session') || {} + end end end diff --git a/app/jobs/resolution_proofing_job.rb b/app/jobs/resolution_proofing_job.rb index dd17ee46fa4..c2de734fe5c 100644 --- a/app/jobs/resolution_proofing_job.rb +++ b/app/jobs/resolution_proofing_job.rb @@ -75,7 +75,7 @@ def perform( timing: timer.results, ) - if use_shadow_mode?(user:) + if use_shadow_mode?(user:, proofing_components:) SocureShadowModeProofingJob.perform_later( document_capture_session_result_id: document_capture_session&.result_id, encrypted_arguments:, @@ -86,15 +86,20 @@ def perform( end end - def use_shadow_mode?(user:) - IdentityConfig.store.idv_socure_shadow_mode_enabled && - AbTests::SOCURE_IDV_SHADOW_MODE.bucket( + # @param user [User] + def use_shadow_mode?(user:, proofing_components: {}) + ( + IdentityConfig.store.idv_socure_shadow_mode_enabled || + IdentityConfig.store.idv_socure_shadow_mode_enabled_for_docv_users && + proofing_components[:document_check] == Idp::Constants::Vendors::SOCURE + ) && + AbTests::SOCURE_IDV_SHADOW_MODE_FOR_NON_DOCV_USERS.bucket( request: nil, service_provider: nil, session: nil, user:, user_session: nil, - ) == :shadow_mode_enabled + ) == :socure_shadow_mode_for_non_docv_users end private @@ -143,6 +148,11 @@ def log_threatmetrix_info(threatmetrix_result, user) ) end + # @param user [User] + def docv_user?(user, result_id) + user.document_capture_sessions.find_by(id: result_id) + end + def logger_info_hash(hash) logger.info(hash.to_json) end diff --git a/app/models/document_capture_session.rb b/app/models/document_capture_session.rb index 7caa58febf5..a1dac53100d 100644 --- a/app/models/document_capture_session.rb +++ b/app/models/document_capture_session.rb @@ -11,6 +11,7 @@ def load_result EncryptedRedisStructStorage.load(result_id, type: DocumentCaptureSessionResult) end + # @param doc_auth_response [DocAuth::Response] def store_result_from_response(doc_auth_response) session_result = load_result || DocumentCaptureSessionResult.new( id: generate_result_id, @@ -22,6 +23,7 @@ def store_result_from_response(doc_auth_response) session_result.doc_auth_success = doc_auth_response.doc_auth_success? session_result.selfie_status = doc_auth_response.selfie_status session_result.errors = doc_auth_response.errors + session_result.vendor = doc_auth_response.extra[:vendor] EncryptedRedisStructStorage.store( session_result, diff --git a/app/services/idv/agent.rb b/app/services/idv/agent.rb index 6a0cb8bedd5..b8908bd78db 100644 --- a/app/services/idv/agent.rb +++ b/app/services/idv/agent.rb @@ -6,13 +6,16 @@ def initialize(applicant) @applicant = applicant.symbolize_keys end + # @param document_capture_session [DocumentCaptureSession] + # @param proofing_components [Idv::ProofingComponents] def proof_resolution( document_capture_session, trace_id:, user_id:, threatmetrix_session_id:, request_ip:, - ipp_enrollment_in_progress: + ipp_enrollment_in_progress:, + proofing_components: ) document_capture_session.create_proofing_session @@ -29,6 +32,7 @@ def proof_resolution( threatmetrix_session_id: threatmetrix_session_id, request_ip: request_ip, ipp_enrollment_in_progress: ipp_enrollment_in_progress, + proofing_components: proofing_components.to_h, } if IdentityConfig.store.ruby_workers_idv_enabled diff --git a/config/application.yml.default b/config/application.yml.default index dcd7ef6c452..e382a0d62c7 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -167,6 +167,7 @@ idv_send_link_attempt_window_in_minutes: 10 idv_send_link_max_attempts: 5 idv_socure_reason_code_download_enabled: false idv_socure_shadow_mode_enabled: false +idv_socure_shadow_mode_enabled_for_docv_users: true idv_sp_required: false in_person_completion_survey_url: 'https://login.gov' in_person_doc_auth_button_enabled: true diff --git a/config/initializers/ab_tests.rb b/config/initializers/ab_tests.rb index c4a4cce8924..ecc04e5f716 100644 --- a/config/initializers/ab_tests.rb +++ b/config/initializers/ab_tests.rb @@ -97,11 +97,11 @@ def self.all }, ).freeze - SOCURE_IDV_SHADOW_MODE = AbTest.new( + SOCURE_IDV_SHADOW_MODE_FOR_NON_DOCV_USERS = AbTest.new( experiment_name: 'Socure shadow mode', should_log: ['IdV: doc auth verify proofing results'].to_set, buckets: { - shadow_mode_enabled: IdentityConfig.store.socure_idplus_shadow_mode_percent, + socure_shadow_mode_for_non_docv_users: IdentityConfig.store.socure_idplus_shadow_mode_percent, }, ).freeze diff --git a/lib/identity_config.rb b/lib/identity_config.rb index c8178d27958..4a41c3f82d4 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -193,6 +193,7 @@ def self.store config.add(:idv_send_link_max_attempts, type: :integer) config.add(:idv_socure_reason_code_download_enabled, type: :boolean) config.add(:idv_socure_shadow_mode_enabled, type: :boolean) + config.add(:idv_socure_shadow_mode_enabled_for_docv_users, type: :boolean) config.add(:idv_sp_required, type: :boolean) config.add(:in_person_completion_survey_url, type: :string) config.add(:in_person_doc_auth_button_enabled, type: :boolean) diff --git a/spec/config/initializers/ab_tests_spec.rb b/spec/config/initializers/ab_tests_spec.rb index 2865e06cec3..42be37e8d68 100644 --- a/spec/config/initializers/ab_tests_spec.rb +++ b/spec/config/initializers/ab_tests_spec.rb @@ -59,17 +59,21 @@ }, } end + it 'returns a bucket' do expect(bucket).not_to be_nil end end + context 'and the user does not have an Idv::Session' do let(:user_session) do {} end + it 'does not return a bucket' do expect(bucket).to be_nil end + it 'does not write :idv key in user_session' do expect { bucket }.not_to change { user_session } end @@ -81,6 +85,7 @@ let(:session) do { document_capture_session_uuid: 'a-random-uuid' } end + it 'returns a bucket' do expect(bucket).not_to be_nil end @@ -96,6 +101,7 @@ context 'when A/B test is disabled and it would otherwise assign a bucket' do let(:user) { build(:user) } + let(:user_session) do { idv: { @@ -108,6 +114,7 @@ disable_ab_test.call reload_ab_tests end + it 'does not assign a bucket' do expect(bucket).to be_nil end @@ -266,11 +273,11 @@ end end - describe 'SOCURE_IDV_SHADOW_MODE' do + describe 'SOCURE_IDV_SHADOW_MODE_FOR_NON_DOCV_USERS' do let(:user) { create(:user) } subject(:bucket) do - AbTests::SOCURE_IDV_SHADOW_MODE.bucket( + AbTests::SOCURE_IDV_SHADOW_MODE_FOR_NON_DOCV_USERS.bucket( request: nil, service_provider: nil, session: nil, @@ -301,7 +308,7 @@ end it 'returns a bucket' do - expect(bucket).to eq :shadow_mode_enabled + expect(bucket).to eq :socure_shadow_mode_for_non_docv_users end end end