From 00f7db077fdfb769881ee6e7106b93a7d532117b Mon Sep 17 00:00:00 2001 From: Andrew Duthie <1779930+aduth@users.noreply.github.com> Date: Tue, 5 Nov 2024 08:01:48 -0500 Subject: [PATCH 1/9] Add error handling for failed reCAPTCHA execute (#11449) * Add error handling for failed reCAPTCHA execute changelog: Internal, reCAPTCHA, Add error handling for failed reCAPTCHA execute * Improve line breaks for arrange, act, assert * Improve line breaks for arrange, act, assert --- app/javascript/packages/analytics/index.ts | 2 + .../captcha-submit-button-element.spec.ts | 45 ++++++++++++++++++- .../captcha-submit-button-element.ts | 11 ++++- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/app/javascript/packages/analytics/index.ts b/app/javascript/packages/analytics/index.ts index 1e9261ddae5..22fa2d91308 100644 --- a/app/javascript/packages/analytics/index.ts +++ b/app/javascript/packages/analytics/index.ts @@ -24,6 +24,8 @@ export function trackEvent(event: string, payload?: object) { * Logs an error. * * @param error Error object. + * @param event Error event, if error is caught using an `error` event handler. Including this can + * add additional resolution to the logged error, notably the filename where the error occurred. */ export const trackError = ({ name, message, stack }: Error, event?: ErrorEvent) => trackEvent('Frontend Error', { name, message, stack, filename: event?.filename }); diff --git a/app/javascript/packages/captcha-submit-button/captcha-submit-button-element.spec.ts b/app/javascript/packages/captcha-submit-button/captcha-submit-button-element.spec.ts index ca980626684..f0bdece5bb7 100644 --- a/app/javascript/packages/captcha-submit-button/captcha-submit-button-element.spec.ts +++ b/app/javascript/packages/captcha-submit-button/captcha-submit-button-element.spec.ts @@ -1,12 +1,26 @@ +import quibble from 'quibble'; import type { SinonStub } from 'sinon'; import userEvent from '@testing-library/user-event'; import { screen, waitFor, fireEvent } from '@testing-library/dom'; import { useSandbox, useDefineProperty } from '@18f/identity-test-helpers'; import '@18f/identity-spinner-button/spinner-button-element'; -import './captcha-submit-button-element'; describe('CaptchaSubmitButtonElement', () => { const sandbox = useSandbox(); + const trackError = sandbox.stub(); + + before(async () => { + quibble('@18f/identity-analytics', { trackError }); + await import('./captcha-submit-button-element'); + }); + + afterEach(() => { + trackError.reset(); + }); + + after(() => { + quibble.reset(); + }); context('without ancestor form element', () => { beforeEach(() => { @@ -157,6 +171,35 @@ describe('CaptchaSubmitButtonElement', () => { await waitFor(() => expect(didSubmit).to.be.true()); }); }); + + context('when recaptcha fails to execute', () => { + let error: Error; + + beforeEach(() => { + error = new Error('Invalid site key or not loaded in api.js: badkey'); + ((global as any).grecaptcha.execute as SinonStub).throws(error); + }); + + it('does not prevent default form submission', async () => { + const button = screen.getByRole('button', { name: 'Submit' }); + const form = document.querySelector('form')!; + sandbox.stub(form, 'submit'); + + await userEvent.click(button); + + await expect(form.submit).to.eventually.be.called(); + }); + + it('tracks error', async () => { + const button = screen.getByRole('button', { name: 'Submit' }); + const form = document.querySelector('form')!; + sandbox.stub(form, 'submit'); + + await userEvent.click(button); + + await expect(trackError).to.eventually.be.calledWith(error); + }); + }); }); }); }); diff --git a/app/javascript/packages/captcha-submit-button/captcha-submit-button-element.ts b/app/javascript/packages/captcha-submit-button/captcha-submit-button-element.ts index 3ec45cbb5b0..45f6e33afeb 100644 --- a/app/javascript/packages/captcha-submit-button/captcha-submit-button-element.ts +++ b/app/javascript/packages/captcha-submit-button/captcha-submit-button-element.ts @@ -1,3 +1,5 @@ +import { trackError } from '@18f/identity-analytics'; + class CaptchaSubmitButtonElement extends HTMLElement { form: HTMLFormElement | null; @@ -46,7 +48,14 @@ class CaptchaSubmitButtonElement extends HTMLElement { invokeChallenge() { this.recaptchaClient!.ready(async () => { const { recaptchaSiteKey: siteKey, recaptchaAction: action } = this; - const token = await this.recaptchaClient!.execute(siteKey!, { action }); + + let token; + try { + token = await this.recaptchaClient!.execute(siteKey!, { action }); + } catch (error) { + trackError(error); + } + this.tokenInput.value = token; this.submit(); }); From c94a31704dec756bbcb5f050e7aecade4a812446 Mon Sep 17 00:00:00 2001 From: voidlily Date: Tue, 5 Nov 2024 09:01:45 -0800 Subject: [PATCH 2/9] Some smol improvements to secret detection (#11454) * No dependencies so it can run sooner * Point to where the artifact report lives on the security tab Ported from https://gitlab.login.gov/lg/identity-dashboard/-/merge_requests/130 [skip changelog] --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7ed90ce7bfa..f263fbeaea3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -503,6 +503,7 @@ include: secret_detection: allow_failure: false + needs: [] variables: SECRET_DETECTION_EXCLUDED_PATHS: 'keys.example,config/artifacts.example,public/acuant/*/opencv.min.js,tmp/0.0.0.0-3000.key' SECRET_DETECTION_REPORT_FILE: 'gl-secret-detection-report.json' @@ -527,6 +528,7 @@ secret_detection: # check if '{ "vulnerabilities": [], ..' is empty in the report file if it exists if [ "$(jq ".vulnerabilities | length" $SECRET_DETECTION_REPORT_FILE)" -gt 0 ]; then echo "Vulnerabilities detected. Please analyze the artifact $SECRET_DETECTION_REPORT_FILE produced by the 'secret-detection' job." + echo "Check the \"Security\" tab on the overall pipeline run to download the report for more information." exit 80 fi else From 2ef75e5135b85b009745b1ce14e374c4ac1c91a4 Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Tue, 5 Nov 2024 13:55:01 -0500 Subject: [PATCH 3/9] changelog: Internal, CI, Testing out using the same image as everything else (#11452) --- .gitlab-ci.yml | 2 +- dockerfiles/application.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f263fbeaea3..31f338017b9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -462,7 +462,7 @@ review-app: stage: review allow_failure: true needs: - - job: build-review-image + - job: build-idp-image resource_group: $CI_ENVIRONMENT_SLUG.reviewapps.identitysandbox.gov extends: .deploy environment: diff --git a/dockerfiles/application.yaml b/dockerfiles/application.yaml index 58d4707d8fa..9803a90beb8 100644 --- a/dockerfiles/application.yaml +++ b/dockerfiles/application.yaml @@ -396,7 +396,7 @@ spec: patch: |- - op: replace path: /spec/template/spec/containers/0/image - value: {{ECR_REGISTRY}}/identity-idp/review:{{IDP_CONTAINER_TAG}} + value: {{ECR_REGISTRY}}/identity-idp/idp:{{IDP_CONTAINER_TAG}} - op: replace path: /spec/template/spec/containers/0/imagePullPolicy value: Always @@ -406,7 +406,7 @@ spec: patch: |- - op: replace path: /spec/template/spec/containers/0/image - value: {{ECR_REGISTRY}}/identity-idp/review:{{IDP_CONTAINER_TAG}} + value: {{ECR_REGISTRY}}/identity-idp/idp:{{IDP_CONTAINER_TAG}} - op: replace path: /spec/template/spec/containers/0/imagePullPolicy value: Always @@ -416,7 +416,7 @@ spec: patch: |- - op: replace path: /spec/template/spec/containers/0/image - value: {{ECR_REGISTRY}}/identity-idp/review:{{IDP_CONTAINER_TAG}} + value: {{ECR_REGISTRY}}/identity-idp/idp:{{IDP_CONTAINER_TAG}} - op: replace path: /spec/template/spec/containers/0/imagePullPolicy value: Always @@ -489,7 +489,7 @@ spec: patch: |- - op: replace path: /spec/template/spec/containers/0/image - value: {{ECR_REGISTRY}}/identity-idp/review:{{IDP_CONTAINER_TAG}} + value: {{ECR_REGISTRY}}/identity-idp/idp:{{IDP_CONTAINER_TAG}} - op: replace path: /spec/template/spec/containers/0/imagePullPolicy value: Always @@ -500,7 +500,7 @@ spec: patch: |- - op: replace path: /spec/template/spec/containers/0/image - value: {{ECR_REGISTRY}}/identity-idp/review:{{IDP_CONTAINER_TAG}} + value: {{ECR_REGISTRY}}/identity-idp/idp:{{IDP_CONTAINER_TAG}} - op: replace path: /spec/template/spec/containers/0/imagePullPolicy value: Always From b899a25d16b6d17695e455a4071414caa295bb37 Mon Sep 17 00:00:00 2001 From: Matt Wagner Date: Tue, 5 Nov 2024 15:39:52 -0500 Subject: [PATCH 4/9] LG-14830 | Send ID type to AAMVA (#11428) changelog: Internal, Identity Proofing, Send state ID type to AAMVA --- .../concerns/idv/verify_info_concern.rb | 2 - .../idv/in_person/verify_info_controller.rb | 8 --- app/controllers/idv/verify_info_controller.rb | 3 - .../aamva/request/verification_request.rb | 27 +++++++++ .../proofing/mock/state_id_mock_client.rb | 4 +- config/application.yml.default | 2 + lib/identity_config.rb | 1 + .../in_person/verify_info_controller_spec.rb | 9 +-- spec/features/idv/analytics_spec.rb | 2 +- .../aamva/requests/verification_request.xml | 4 +- .../services/proofing/aamva/applicant_spec.rb | 2 +- .../request/verification_request_spec.rb | 60 ++++++++++++++++++- 12 files changed, 96 insertions(+), 28 deletions(-) diff --git a/app/controllers/concerns/idv/verify_info_concern.rb b/app/controllers/concerns/idv/verify_info_concern.rb index efceb72bc06..e2608ab854e 100644 --- a/app/controllers/concerns/idv/verify_info_concern.rb +++ b/app/controllers/concerns/idv/verify_info_concern.rb @@ -19,8 +19,6 @@ def shared_update Funnel::DocAuth::RegisterStep.new(current_user.id, sp_session[:issuer]). call('verify', :update, true) - set_state_id_type - ssn_rate_limiter.increment! document_capture_session = DocumentCaptureSession.create( diff --git a/app/controllers/idv/in_person/verify_info_controller.rb b/app/controllers/idv/in_person/verify_info_controller.rb index 5284d5e6881..1eb612bb664 100644 --- a/app/controllers/idv/in_person/verify_info_controller.rb +++ b/app/controllers/idv/in_person/verify_info_controller.rb @@ -57,14 +57,6 @@ def flow_param 'in_person' end - # state_id_type is hard-coded here because it's required for proofing against - # AAMVA. We're sticking with driver's license because most states don't discern - # between various ID types and driver's license is the most common one that will - # be supported. See also LG-3852 and related findings document. - def set_state_id_type - pii_from_user[:state_id_type] = 'drivers_license' unless invalid_state? - end - def invalid_state? pii_from_user.blank? end diff --git a/app/controllers/idv/verify_info_controller.rb b/app/controllers/idv/verify_info_controller.rb index 9496890cf04..bc11819486b 100644 --- a/app/controllers/idv/verify_info_controller.rb +++ b/app/controllers/idv/verify_info_controller.rb @@ -64,9 +64,6 @@ def self.step_info def flow_param; end - # state ID type isn't manually set for Idv::VerifyInfoController - def set_state_id_type; end - def prev_url idv_ssn_url end diff --git a/app/services/proofing/aamva/request/verification_request.rb b/app/services/proofing/aamva/request/verification_request.rb index ecff76af4a4..84e25e75b34 100644 --- a/app/services/proofing/aamva/request/verification_request.rb +++ b/app/services/proofing/aamva/request/verification_request.rb @@ -84,9 +84,36 @@ def add_user_provided_data_to_body inside: '//dldv:verifyDriverLicenseDataRequest', ) + if IdentityConfig.store.aamva_send_id_type + add_state_id_type( + applicant.state_id_data.state_id_type, + document, + ) + end + @body = document.to_s end + def add_state_id_type(id_type, document) + category_code = case id_type + when 'drivers_license' + 1 + when 'drivers_permit' + 2 + when 'state_id_card' + 3 + end + + if category_code + add_optional_element( + 'aa:DocumentCategoryCode', + value: category_code, + document:, + inside: '//dldv:verifyDriverLicenseDataRequest', + ) + end + end + def add_optional_element(name, value:, document:, inside: nil, after: nil) return if value.blank? diff --git a/app/services/proofing/mock/state_id_mock_client.rb b/app/services/proofing/mock/state_id_mock_client.rb index 7f01945df57..3b86f0bff68 100644 --- a/app/services/proofing/mock/state_id_mock_client.rb +++ b/app/services/proofing/mock/state_id_mock_client.rb @@ -72,8 +72,8 @@ def invalid_state_id_number?(state_id_number) end def invalid_state_id_type?(state_id_type) - !SUPPORTED_STATE_ID_TYPES.include?(state_id_type) || - state_id_type.nil? + !SUPPORTED_STATE_ID_TYPES.include?(state_id_type) && + !state_id_type.nil? end end end diff --git a/config/application.yml.default b/config/application.yml.default index 4bdf5c9b6dc..376fe87c200 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -19,6 +19,7 @@ aamva_auth_url: 'https://example.org:12345/auth/url' aamva_cert_enabled: true aamva_private_key: '' aamva_public_key: '' +aamva_send_id_type: true aamva_supported_jurisdictions: '["AL","AR","AZ","CO","CT","DC","DE","FL","GA","HI","IA","ID","IL","IN","KS","KY","MA","MD","ME","MI","MO","MS","MT","NC","ND","NE","NJ","NM","NV","OH","OR","PA","RI","SC","SD","TN","TX","VA","VT","WA","WI","WV","WY"]' aamva_verification_request_timeout: 5.0 aamva_verification_url: https://example.org:12345/verification/url @@ -501,6 +502,7 @@ development: # production: aamva_auth_url: 'https://authentication-cert.aamva.org/Authentication/Authenticate.svc' + aamva_send_id_type: false aamva_verification_url: 'https://verificationservices-cert.aamva.org:18449/dldv/2.1/online' available_locales: 'en,es,fr' biometric_ial_enabled: false diff --git a/lib/identity_config.rb b/lib/identity_config.rb index 88003036bb8..8eaaf9bd709 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -34,6 +34,7 @@ def self.store config.add(:aamva_cert_enabled, type: :boolean) config.add(:aamva_private_key, type: :string) config.add(:aamva_public_key, type: :string) + config.add(:aamva_send_id_type, type: :boolean) config.add(:aamva_supported_jurisdictions, type: :json) config.add(:aamva_verification_request_timeout, type: :float) config.add(:aamva_verification_url) 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 4a6dbda956b..a05953e8b96 100644 --- a/spec/controllers/idv/in_person/verify_info_controller_spec.rb +++ b/spec/controllers/idv/in_person/verify_info_controller_spec.rb @@ -234,22 +234,15 @@ allow(user).to receive(:establishing_in_person_enrollment).and_return(enrollment) end - it 'sets ssn and state_id_type on pii_from_user' do + it 'sets ssn on pii_from_user' do expect(Idv::Agent).to receive(:new).with( hash_including( - state_id_type: 'drivers_license', ssn: Idp::Constants::MOCK_IDV_APPLICANT_SAME_ADDRESS_AS_ID[:ssn], consent_given_at: subject.idv_session.idv_consent_given_at, ), ).and_call_original - # our test data already has the expected value by default - subject.user_session['idv/in_person'][:pii_from_user].delete(:state_id_type) - put :update - - expect(subject.user_session['idv/in_person'][:pii_from_user][:state_id_type]). - to eq 'drivers_license' end context 'a user does not have an establishing in person enrollment associated with them' do diff --git a/spec/features/idv/analytics_spec.rb b/spec/features/idv/analytics_spec.rb index 7505f8b7717..606eb9373ec 100644 --- a/spec/features/idv/analytics_spec.rb +++ b/spec/features/idv/analytics_spec.rb @@ -153,7 +153,7 @@ vendor_name: 'ResolutionMock', vendor_workflow: nil, verified_attributes: nil }, - state_id: state_id_resolution_with_id_type, + state_id: state_id_resolution, threatmetrix: threatmetrix_response, }, }, diff --git a/spec/fixtures/proofing/aamva/requests/verification_request.xml b/spec/fixtures/proofing/aamva/requests/verification_request.xml index 32d5a25010f..c42882043d4 100644 --- a/spec/fixtures/proofing/aamva/requests/verification_request.xml +++ b/spec/fixtures/proofing/aamva/requests/verification_request.xml @@ -31,7 +31,7 @@ VA 20176 - + 1 - \ No newline at end of file + diff --git a/spec/services/proofing/aamva/applicant_spec.rb b/spec/services/proofing/aamva/applicant_spec.rb index bb22b20d376..b2172ce9bd5 100644 --- a/spec/services/proofing/aamva/applicant_spec.rb +++ b/spec/services/proofing/aamva/applicant_spec.rb @@ -14,7 +14,7 @@ end describe '.from_proofer_applicant(applicant)' do - it 'should create an AAMVA applicant with necessary proofer applcant data' do + it 'should create an AAMVA applicant with necessary proofer applicant data' do aamva_applicant = described_class.from_proofer_applicant(proofer_applicant) expect(aamva_applicant.uuid).to eq(proofer_applicant[:uuid]) diff --git a/spec/services/proofing/aamva/request/verification_request_spec.rb b/spec/services/proofing/aamva/request/verification_request_spec.rb index 190d9edf374..68c2a874d83 100644 --- a/spec/services/proofing/aamva/request/verification_request_spec.rb +++ b/spec/services/proofing/aamva/request/verification_request_spec.rb @@ -33,7 +33,7 @@ describe '#body' do it 'should be a request body' do - expect(subject.body).to eq(AamvaFixtures.verification_request) + expect(subject.body + "\n").to eq(AamvaFixtures.verification_request) end it 'should escape XML in applicant data' do @@ -88,6 +88,64 @@ '2030-01-02', ) end + + context '#state_id_type' do + context 'when the feature flag is off' do + before do + expect(IdentityConfig.store).to receive(:aamva_send_id_type).and_return(false) + end + + it 'does not add a DocumentCategoryCode' do + applicant.state_id_data.state_id_type = 'drivers_license' + expect(subject.body).to_not include('') + end + end + + context 'when the feature flag is on' do + before do + expect(IdentityConfig.store).to receive(:aamva_send_id_type).and_return(true) + end + + context 'when the type is a Drivers License' do + it 'includes DocumentCategoryCode=1' do + applicant.state_id_data.state_id_type = 'drivers_license' + expect(subject.body).to include( + '1', + ) + end + end + + context 'when the type is a learners permit' do + it 'includes DocumentCategoryCode=2' do + applicant.state_id_data.state_id_type = 'drivers_permit' + expect(subject.body).to include( + '2', + ) + end + end + + context 'when the type is an ID Card' do + it 'includes DocumentCategoryCode=3' do + applicant.state_id_data.state_id_type = 'state_id_card' + expect(subject.body).to include( + '3', + ) + end + end + + context 'when the type is something invalid' do + it 'does not add a DocumentCategoryCode for nil ID type' do + applicant.state_id_data.state_id_type = nil + expect(subject.body).to_not include('') + end + + it 'does not add a DocumentCategoryCode for invalid ID types' do + applicant.state_id_data.state_id_type = 'License to Keep an Alpaca' + expect(subject.body).to_not include('') + end + end + end + end end describe '#headers' do From f15db1eccaf5a0733627e04862735262c43a57b9 Mon Sep 17 00:00:00 2001 From: Malick Diarra Date: Tue, 5 Nov 2024 16:53:32 -0500 Subject: [PATCH 5/9] LG-14692: Banner message for selected email confirmation (#11443) * changelog: Upcoming Features, Email Selection feature, Add new message for email confirmation * update spec to set value to false * update edit confirmation emails so it only shows proper message * fix rubocop * fix to show when user also signs in after confirming email * add spec for accounts controller flash logic, clean up emails confirmation logic * use hidden field instead of user session * add user mailer spec for additional attribute * move back to using session, but also ensure we delete session after submission * update rubocop and to work for the resend or add different email * fix verify html spec --- app/controllers/accounts_controller.rb | 6 ++++ .../users/email_confirmations_controller.rb | 5 +++ app/controllers/users/emails_controller.rb | 17 ++++++--- app/forms/add_user_email_form.rb | 8 +++-- app/mailers/user_mailer.rb | 3 +- app/services/send_add_email_confirmation.rb | 6 ++-- .../selected_email/edit.html.erb | 2 +- app/views/sign_up/completions/show.html.erb | 2 +- app/views/sign_up/select_email/show.html.erb | 2 +- app/views/users/emails/verify.html.erb | 2 +- config/locales/en.yml | 1 + config/locales/es.yml | 1 + config/locales/fr.yml | 1 + config/locales/zh.yml | 1 + spec/controllers/accounts_controller_spec.rb | 36 +++++++++++++++++++ .../email_confirmations_controller_spec.rb | 20 +++++++++++ spec/mailers/user_mailer_spec.rb | 16 +++++++++ .../users/emails/verify.html.erb_spec.rb | 1 + 18 files changed, 117 insertions(+), 13 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 90d78f33bf3..e6068396f1c 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -19,6 +19,12 @@ def show user: current_user, locked_for_session: pii_locked_for_session?(current_user), ) + if session.delete(:from_select_email_flow) + flash.now[:success] = t( + 'account.emails.confirmed_html', + url: account_connected_accounts_url, + ) + end end def reauthentication diff --git a/app/controllers/users/email_confirmations_controller.rb b/app/controllers/users/email_confirmations_controller.rb index fdd01844ad0..7e7e87e9f8b 100644 --- a/app/controllers/users/email_confirmations_controller.rb +++ b/app/controllers/users/email_confirmations_controller.rb @@ -42,6 +42,7 @@ def email_address_already_confirmed? def process_successful_confirmation(email_address) confirm_and_notify(email_address) + store_from_select_email_flow_in_session if current_user flash[:success] = t('devise.confirmations.confirmed') redirect_to account_url @@ -98,5 +99,9 @@ def email_address_already_confirmed_by_current_user? def confirmation_params params.permit(:confirmation_token) end + + def store_from_select_email_flow_in_session + session[:from_select_email_flow] = params[:from_select_email_flow].to_s == 'true' + end end end diff --git a/app/controllers/users/emails_controller.rb b/app/controllers/users/emails_controller.rb index e213740f38c..b52c7625d8c 100644 --- a/app/controllers/users/emails_controller.rb +++ b/app/controllers/users/emails_controller.rb @@ -12,14 +12,19 @@ class EmailsController < ApplicationController def show analytics.add_email_visit + session[:in_select_email_flow] = params[:in_select_email_flow] @add_user_email_form = AddUserEmailForm.new @pending_completions_consent = pending_completions_consent? end def add - @add_user_email_form = AddUserEmailForm.new + @add_user_email_form = AddUserEmailForm.new( + session[:in_select_email_flow], + ) - result = @add_user_email_form.submit(current_user, permitted_params) + result = @add_user_email_form.submit( + current_user, permitted_params + ) analytics.add_email_request(**result.to_h) if result.success? @@ -71,7 +76,8 @@ def verify if session_email.blank? redirect_to add_email_url else - render :verify, locals: { email: session_email } + render :verify, + locals: { email: session_email, in_select_email_flow: params[:in_select_email_flow] } end end @@ -97,7 +103,10 @@ def process_successful_creation resend_confirmation = params[:user][:resend] session[:email] = @add_user_email_form.email - redirect_to add_email_verify_email_url(resend: resend_confirmation) + redirect_to add_email_verify_email_url( + resend: resend_confirmation, + in_select_email_flow: session.delete(:in_select_email_flow), + ) end def session_email diff --git a/app/forms/add_user_email_form.rb b/app/forms/add_user_email_form.rb index 99530bb5bb2..cc91ff62fa2 100644 --- a/app/forms/add_user_email_form.rb +++ b/app/forms/add_user_email_form.rb @@ -5,12 +5,16 @@ class AddUserEmailForm include FormAddEmailValidator include ActionView::Helpers::TranslationHelper - attr_reader :email + attr_reader :email, :in_select_email_flow def self.model_name ActiveModel::Name.new(self, nil, 'User') end + def initialize(in_select_email_flow = nil) + @in_select_email_flow = in_select_email_flow + end + def user @user ||= User.new end @@ -47,7 +51,7 @@ def email_address_record(email) def process_successful_submission @success = true email_address.save! - SendAddEmailConfirmation.new(user).call(email_address) + SendAddEmailConfirmation.new(user).call(email_address, in_select_email_flow) end def extra_analytics_attributes diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index e92294e73d0..2f46ed4195e 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -199,13 +199,14 @@ def verify_by_mail_letter_requested end end - def add_email(token) + def add_email(token, from_select_email_flow = nil) with_user_locale(user) do presenter = ConfirmationEmailPresenter.new(user, view_context) @first_sentence = presenter.first_sentence @confirmation_period = presenter.confirmation_period @add_email_url = add_email_confirmation_url( confirmation_token: token, + from_select_email_flow:, locale: locale_url_param, ) mail(to: email_address.email, subject: t('user_mailer.add_email.subject')) diff --git a/app/services/send_add_email_confirmation.rb b/app/services/send_add_email_confirmation.rb index cc9eb7dc7d8..fbeb8d900a8 100644 --- a/app/services/send_add_email_confirmation.rb +++ b/app/services/send_add_email_confirmation.rb @@ -7,8 +7,9 @@ def initialize(user) @user = user end - def call(email_address) + def call(email_address, in_select_email_flow = nil) @email_address = email_address + @in_select_email_flow = in_select_email_flow update_email_address_record send_email end @@ -23,7 +24,7 @@ def confirmation_sent_at email_address.confirmation_sent_at end - attr_reader :email_address + attr_reader :email_address, :in_select_email_flow def update_email_address_record email_address.update!( @@ -59,6 +60,7 @@ def send_email_associated_with_another_account_email def send_confirmation_email UserMailer.with(user: user, email_address: email_address).add_email( confirmation_token, + in_select_email_flow, ).deliver_now_or_later end end diff --git a/app/views/accounts/connected_accounts/selected_email/edit.html.erb b/app/views/accounts/connected_accounts/selected_email/edit.html.erb index f513ad8ddd7..f2a57f126e5 100644 --- a/app/views/accounts/connected_accounts/selected_email/edit.html.erb +++ b/app/views/accounts/connected_accounts/selected_email/edit.html.erb @@ -34,7 +34,7 @@ <% end %> <%= render ButtonComponent.new( - url: add_email_path, + url: add_email_path(in_select_email_flow: true), outline: true, big: true, wide: true, diff --git a/app/views/sign_up/completions/show.html.erb b/app/views/sign_up/completions/show.html.erb index e019e17a33d..b40f9ce2a3c 100644 --- a/app/views/sign_up/completions/show.html.erb +++ b/app/views/sign_up/completions/show.html.erb @@ -49,7 +49,7 @@ <% if @presenter.multiple_emails? %> <%= link_to t('help_text.requested_attributes.change_email_link'), sign_up_select_email_path %> <% else %> - <%= link_to t('account.index.email_add'), add_email_path %> + <%= link_to t('account.index.email_add'), add_email_path(in_select_email_flow: true) %> <% end %>

diff --git a/app/views/sign_up/select_email/show.html.erb b/app/views/sign_up/select_email/show.html.erb index 0403c5d2653..53b0c04e5de 100644 --- a/app/views/sign_up/select_email/show.html.erb +++ b/app/views/sign_up/select_email/show.html.erb @@ -30,7 +30,7 @@ <% end %> <%= render ButtonComponent.new( - url: add_email_path, + url: add_email_path(in_select_email_flow: true), outline: true, big: true, wide: true, diff --git a/app/views/users/emails/verify.html.erb b/app/views/users/emails/verify.html.erb index 471f93d0a34..211b59fc6ee 100644 --- a/app/views/users/emails/verify.html.erb +++ b/app/views/users/emails/verify.html.erb @@ -22,7 +22,7 @@ <%= t('notices.signed_up_and_confirmed.no_email_sent_explanation_start') %> <%= button_to(add_email_resend_path, method: :post, class: 'usa-button usa-button--unstyled', form_class: 'display-inline-block padding-left-1') { t('links.resend') } %> -

<%= t('notices.use_diff_email.text_html', link_html: link_to(t('notices.use_diff_email.link'), add_email_path)) %>

+

<%= t('notices.use_diff_email.text_html', link_html: link_to(t('notices.use_diff_email.link'), add_email_path(in_select_email_flow: in_select_email_flow))) %>

<%= t('devise.registrations.close_window') %>

<% if FeatureManagement.enable_load_testing_mode? && EmailAddress.find_with_email(email) %> diff --git a/config/locales/en.yml b/config/locales/en.yml index def5a8cfd80..c9377403782 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -51,6 +51,7 @@ account.email_language.name.es: Español account.email_language.name.fr: Français account.email_language.name.zh: 中文 (简体) account.email_language.updated: Your email language preference has been updated. +account.emails.confirmed_html: You have confirmed your email address. Go to your connected accounts to update the email you share with connected agencies. account.forget_all_browsers.longer_description: Once you choose to ‘forget all browsers,’ we’ll need additional information to know that it’s actually you signing in to your account. We’ll ask for a multi-factor authentication method (such as text/SMS code or a security key) each time you want to access your account. account.index.auth_app_add: Add app account.index.auth_app_disabled: not enabled diff --git a/config/locales/es.yml b/config/locales/es.yml index a3d073ec453..f27cbad7794 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -51,6 +51,7 @@ account.email_language.name.es: Español account.email_language.name.fr: Français account.email_language.name.zh: 中文 (简体) account.email_language.updated: Se actualizó su preferencia de idioma del correo electrónico. +account.emails.confirmed_html: Usted confirmó su dirección de correo electrónico. Vaya a Sus cuentas conectadas para actualizar el correo electrónico que proporcionó a las agencias conectadas. account.forget_all_browsers.longer_description: Una vez que elija “Olvidar todos los navegadores”, necesitaremos más información para saber que realmente es usted quien está iniciando sesión en su cuenta. Le pediremos un método de autenticación multifactor (como código de texto o de SMS, o una clave de seguridad) cada vez que desee acceder a su cuenta. account.index.auth_app_add: Agregar aplicación account.index.auth_app_disabled: no habilitada diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 15199f121a5..2a41643f85c 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -51,6 +51,7 @@ account.email_language.name.es: Español account.email_language.name.fr: Français account.email_language.name.zh: 中文 (简体) account.email_language.updated: Votre langue de préférence pour les e-mails a été mise à jour. +account.emails.confirmed_html: Vous avez confirmé votre adresse e-mail. Rendez-vous sur vos comptes connectés pour actualiser l’adresse e-mail que vous communiquez aux organismes connectés. account.forget_all_browsers.longer_description: Une fois que vous aurez choisi d’« oublier tous les navigateurs », nous aurons besoin d’informations supplémentaires pour savoir que c’est bien vous qui vous connectez à votre compte. Nous vous demanderons une méthode d’authentification multi-facteurs (comme un code SMS/texto ou une clé de sécurité) chaque fois que vous souhaiterez accéder à votre compte. account.index.auth_app_add: Ajouter une appli account.index.auth_app_disabled: non activé diff --git a/config/locales/zh.yml b/config/locales/zh.yml index 7d6260e8ef1..e40a3f9067c 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -51,6 +51,7 @@ account.email_language.name.es: Español account.email_language.name.fr: Français account.email_language.name.zh: 中文 (简体) account.email_language.updated: 你的电邮语言选择已更新。 +account.emails.confirmed_html: 你已确认了你的电邮地址。请到你已连接的账户来更新你与已连接机构所分享的电邮。 account.forget_all_browsers.longer_description: 你选择“忘掉所有浏览器”后,我们将需要额外信息来知道的确是你在登录你自己的账户。每次你要访问自己的账户时,我们都会向你要一个多因素身份证实方法(比如短信/SMS 代码或安全密钥) account.index.auth_app_add: 添加应用程序 account.index.auth_app_disabled: 未启用 diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/controllers/accounts_controller_spec.rb index 52818437548..0bae12eabd0 100644 --- a/spec/controllers/accounts_controller_spec.rb +++ b/spec/controllers/accounts_controller_spec.rb @@ -80,6 +80,42 @@ end end + context 'when user just added new email through select email flow' do + context 'when user is in select email form flow' do + before do + session[:from_select_email_flow] = true + end + it 'renders the proper flash message' do + flash_message = t( + 'account.emails.confirmed_html', + url: account_connected_accounts_url, + ) + user = create(:user, :fully_registered) + sign_in user + + get :show + + expect(response).to_not be_redirect + expect(flash[:success]).to eq(flash_message) + expect(session[:from_select_email_flow]).to be_nil + end + end + + context 'when user is not in email form flow' do + before do + session[:from_select_email_flow] = false + end + it 'renders proper flash message' do + t('devise.confirmations.confirmed') + user = create(:user, :fully_registered) + sign_in user + + get :show + expect(flash[:success]).to be_nil + end + end + end + context 'when a profile has been deactivated by password reset' do it 'renders the profile and shows a deactivation banner' do user = create( diff --git a/spec/controllers/users/email_confirmations_controller_spec.rb b/spec/controllers/users/email_confirmations_controller_spec.rb index 8c984d65584..c6a7613e381 100644 --- a/spec/controllers/users/email_confirmations_controller_spec.rb +++ b/spec/controllers/users/email_confirmations_controller_spec.rb @@ -25,6 +25,26 @@ get :create, params: { confirmation_token: email_record.reload.confirmation_token } end + context 'when select email feature is disabled' do + before do + allow(IdentityConfig.store).to receive(:feature_select_email_to_share_enabled). + and_return(false) + end + it 'should render proper flash member' do + flash_message = t('devise.confirmations.confirmed') + user = create(:user) + sign_in user + new_email = Faker::Internet.email + + add_email_form = AddUserEmailForm.new + add_email_form.submit(user, email: new_email) + email_record = add_email_form.email_address_record(new_email) + + get :create, params: { confirmation_token: email_record.reload.confirmation_token } + expect(flash[:success]).to eq(flash_message) + end + end + it 'rejects an otherwise valid token for unconfirmed users' do user = create(:user, :unconfirmed, email_addresses: []) new_email = Faker::Internet.email diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb index 7f4b80dd228..71f615af5fe 100644 --- a/spec/mailers/user_mailer_spec.rb +++ b/spec/mailers/user_mailer_spec.rb @@ -43,6 +43,22 @@ expect(mail.html_part.body).to have_content(add_email_url) expect(mail.html_part.body).to_not have_content(sign_up_create_email_confirmation_url) end + + context 'when user adds email from select email flow' do + let(:token) { SecureRandom.hex } + let(:mail) do + UserMailer.with(user: user, email_address: email_address).add_email(token, true) + end + + it 'renders the add_email_confirmation_url' do + add_email_url = add_email_confirmation_url( + confirmation_token: token, + from_select_email_flow: true, + ) + + expect(mail.html_part.body).to have_content(add_email_url) + end + end end describe '#email_deleted' do diff --git a/spec/views/users/emails/verify.html.erb_spec.rb b/spec/views/users/emails/verify.html.erb_spec.rb index 5c74dd8b7ed..f90ae443004 100644 --- a/spec/views/users/emails/verify.html.erb_spec.rb +++ b/spec/views/users/emails/verify.html.erb_spec.rb @@ -4,6 +4,7 @@ let(:email) { 'foo@bar.com' } before do allow(view).to receive(:email).and_return(email) + allow(view).to receive(:in_select_email_flow).and_return(nil) @resend_email_confirmation_form = ResendEmailConfirmationForm.new end From 0c37e09bfe4d8ea204df8482b799a6ac001c5ea5 Mon Sep 17 00:00:00 2001 From: Andrew Duthie <1779930+aduth@users.noreply.github.com> Date: Wed, 6 Nov 2024 07:24:02 -0500 Subject: [PATCH 6/9] Include FormResponse error details for reCAPTCHA at sign-in (#11456) * Include FormResponse error details for reCAPTCHA at sign-in changelog: Internal, Analytics, Include FormResponse error details for reCAPTCHA at sign-in * Fix user_id described as UUID, not database ID * Fix grammAr for new_device description --- app/controllers/users/sessions_controller.rb | 14 +++++++------- app/services/analytics_events.rb | 9 ++++++--- spec/controllers/users/sessions_controller_spec.rb | 1 + 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/app/controllers/users/sessions_controller.rb b/app/controllers/users/sessions_controller.rb index 95c4149e587..b77e7351c39 100644 --- a/app/controllers/users/sessions_controller.rb +++ b/app/controllers/users/sessions_controller.rb @@ -39,7 +39,7 @@ def create return process_rate_limited if session_bad_password_count_max_exceeded? return process_locked_out_user if current_user && user_locked_out?(current_user) return process_rate_limited if rate_limited? - return process_failed_captcha unless valid_captcha_result? || log_captcha_failures_only? + return process_failed_captcha unless recaptcha_response.success? || log_captcha_failures_only? rate_limit_password_failure = true self.resource = warden.authenticate!(auth_options) @@ -100,11 +100,10 @@ def locked_out_time_remaining distance_of_time_in_words(Time.zone.now, time_lockout_expires, true) end - def valid_captcha_result? - return @valid_captcha_result if defined?(@valid_captcha_result) - @valid_captcha_result = recaptcha_form.submit( + def recaptcha_response + @recaptcha_response ||= recaptcha_form.submit( recaptcha_token: params.require(:user)[:recaptcha_token], - ).success? + ) end def recaptcha_form @@ -206,15 +205,16 @@ def track_authentication_attempt success = current_user.present? && !user_locked_out?(user) && - (valid_captcha_result? || log_captcha_failures_only?) + (recaptcha_response.success? || log_captcha_failures_only?) analytics.email_and_password_auth( + **recaptcha_response.to_h, success: success, user_id: user.uuid, user_locked_out: user_locked_out?(user), rate_limited: rate_limited?, captcha_validation_performed: captcha_validation_performed?, - valid_captcha_result: valid_captcha_result?, + valid_captcha_result: recaptcha_response.success?, bad_password_count: session[:bad_password_count].to_i, sp_request_url_present: sp_session[:request_url].present?, remember_device: remember_device_cookie.present?, diff --git a/app/services/analytics_events.rb b/app/services/analytics_events.rb index 21041899d5a..5d6c0b352cd 100644 --- a/app/services/analytics_events.rb +++ b/app/services/analytics_events.rb @@ -436,8 +436,9 @@ def edit_password_visit(required_password_change: false, **extra) ) end - # @param [Boolean] success - # @param [String] user_id + # @param [Boolean] success Whether form validation was successful + # @param [Hash] error_details Details for errors that occurred in unsuccessful submission + # @param [String] user_id UUID for user associated with attempted email address # @param [Boolean] user_locked_out if the user is currently locked out of their second factor # @param [Boolean] rate_limited Whether the user has exceeded user IP rate limiting # @param [Boolean] valid_captcha_result Whether user passed the reCAPTCHA check or was exempt @@ -446,7 +447,7 @@ def edit_password_visit(required_password_change: false, **extra) # @param [Boolean] sp_request_url_present if was an SP request URL in the session # @param [Boolean] remember_device if the remember device cookie was present # @param [Boolean, nil] new_device Whether the user is authenticating from a new device. Nil if - # there is the attempt was unsuccessful, since it cannot be known whether it's a new device. + # the attempt was unsuccessful, since it cannot be known whether it's a new device. # Tracks authentication attempts at the email/password screen def email_and_password_auth( success:, @@ -459,11 +460,13 @@ def email_and_password_auth( sp_request_url_present:, remember_device:, new_device:, + error_details: nil, **extra ) track_event( 'Email and Password Authentication', success:, + error_details:, user_id:, user_locked_out:, rate_limited:, diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb index 6a535885546..c0a3f57cf76 100644 --- a/spec/controllers/users/sessions_controller_spec.rb +++ b/spec/controllers/users/sessions_controller_spec.rb @@ -372,6 +372,7 @@ expect(@analytics).to have_logged_event( 'Email and Password Authentication', success: false, + error_details: { recaptcha_token: { blank: true } }, user_id: user.uuid, user_locked_out: false, rate_limited: false, From 8f41ad7c07a85a2bd736f4c7bb67024eaa025c2c Mon Sep 17 00:00:00 2001 From: eileen-nava <80347702+eileen-nava@users.noreply.github.com> Date: Wed, 6 Nov 2024 16:45:11 -0500 Subject: [PATCH 7/9] LG-9008: Remove code that supports pre-launch IPP functionality (#11440) * remove is_pilot from implementation * increment up @18F/identity-address-search version to reflect change in interface * Changelog: Internal, In-person proofing, update address search interface to remove obsolete is_pilot field --- app/javascript/packages/address-search/CHANGELOG.md | 4 ++++ .../components/in-person-locations.spec.tsx | 2 -- .../components/in-person-locations.tsx | 12 ++++-------- app/javascript/packages/address-search/package.json | 2 +- app/javascript/packages/address-search/types.d.ts | 2 -- app/javascript/packages/address-search/utils.ts | 1 - .../usps_in_person_proofing/enrollment_helper.rb | 1 - app/services/usps_in_person_proofing/post_office.rb | 1 - app/services/usps_in_person_proofing/proofer.rb | 1 - 9 files changed, 9 insertions(+), 17 deletions(-) diff --git a/app/javascript/packages/address-search/CHANGELOG.md b/app/javascript/packages/address-search/CHANGELOG.md index 5c682803c51..ee448b8734e 100644 --- a/app/javascript/packages/address-search/CHANGELOG.md +++ b/app/javascript/packages/address-search/CHANGELOG.md @@ -1,5 +1,9 @@ # `Change Log` +## v3.3.0 (2024-11-05) + +- Remove obsolete `is_pilot` field from PostOffice and FormattedLocation types + ## v3.2.0 (2024-10-01) ### New feature diff --git a/app/javascript/packages/address-search/components/in-person-locations.spec.tsx b/app/javascript/packages/address-search/components/in-person-locations.spec.tsx index 89971bc062b..195206b9f81 100644 --- a/app/javascript/packages/address-search/components/in-person-locations.spec.tsx +++ b/app/javascript/packages/address-search/components/in-person-locations.spec.tsx @@ -25,7 +25,6 @@ describe('InPersonLocations', () => { saturdayHours: '9 AM - 6 PM', sundayHours: 'Closed', id: 1, - isPilot: false, }, { name: 'test name', @@ -36,7 +35,6 @@ describe('InPersonLocations', () => { saturdayHours: '10 AM - 5 PM', sundayHours: 'Closed', id: 1, - isPilot: false, }, ]; diff --git a/app/javascript/packages/address-search/components/in-person-locations.tsx b/app/javascript/packages/address-search/components/in-person-locations.tsx index 7b446bb2def..af2f807cbe7 100644 --- a/app/javascript/packages/address-search/components/in-person-locations.tsx +++ b/app/javascript/packages/address-search/components/in-person-locations.tsx @@ -12,7 +12,6 @@ export interface FormattedLocation { streetAddress: string; sundayHours: string; weekdayHours: string; - isPilot: boolean; } function InPersonLocations({ @@ -22,8 +21,6 @@ function InPersonLocations({ noInPersonLocationsDisplay: NoInPersonLocationsDisplay, resultsHeaderComponent: HeaderComponent, }: InPersonLocationsProps) { - const isPilot = locations?.some((l) => l.isPilot); - if (locations?.length === 0) { return ; } @@ -31,11 +28,10 @@ function InPersonLocations({ return ( <>

- {!isPilot && - t('in_person_proofing.body.location.po_search.results_description', { - address, - count: locations?.length, - })} + {t('in_person_proofing.body.location.po_search.results_description', { + address, + count: locations?.length, + })}

{HeaderComponent && } {onSelect &&

{t('in_person_proofing.body.location.po_search.results_instructions')}

} diff --git a/app/javascript/packages/address-search/package.json b/app/javascript/packages/address-search/package.json index 8afaaa3524d..a02eebaee2d 100644 --- a/app/javascript/packages/address-search/package.json +++ b/app/javascript/packages/address-search/package.json @@ -1,6 +1,6 @@ { "name": "@18f/identity-address-search", - "version": "3.2.0", + "version": "3.3.0", "type": "module", "private": false, "files": [ diff --git a/app/javascript/packages/address-search/types.d.ts b/app/javascript/packages/address-search/types.d.ts index 86455ca4f6f..d75c0b971be 100644 --- a/app/javascript/packages/address-search/types.d.ts +++ b/app/javascript/packages/address-search/types.d.ts @@ -10,7 +10,6 @@ interface FormattedLocation { streetAddress: string; sundayHours: string; weekdayHours: string; - isPilot: boolean; } interface PostOffice { @@ -24,7 +23,6 @@ interface PostOffice { weekday_hours: string; zip_code_4: string; zip_code_5: string; - is_pilot: boolean; } interface LocationQuery { diff --git a/app/javascript/packages/address-search/utils.ts b/app/javascript/packages/address-search/utils.ts index 79d895ee6fb..d1f635868c7 100644 --- a/app/javascript/packages/address-search/utils.ts +++ b/app/javascript/packages/address-search/utils.ts @@ -10,7 +10,6 @@ export const formatLocations = (postOffices: PostOffice[]): FormattedLocation[] streetAddress: po.address, sundayHours: po.sunday_hours, weekdayHours: po.weekday_hours, - isPilot: !!po.is_pilot, })); export const snakeCase = (value: string) => diff --git a/app/services/usps_in_person_proofing/enrollment_helper.rb b/app/services/usps_in_person_proofing/enrollment_helper.rb index 564f9a7e96b..c6599c3f2e0 100644 --- a/app/services/usps_in_person_proofing/enrollment_helper.rb +++ b/app/services/usps_in_person_proofing/enrollment_helper.rb @@ -111,7 +111,6 @@ def localized_location(location) weekday_hours: EnrollmentHelper.localized_hours(location.weekday_hours), zip_code_4: location.zip_code_4, zip_code_5: location.zip_code_5, - is_pilot: location.is_pilot, } end diff --git a/app/services/usps_in_person_proofing/post_office.rb b/app/services/usps_in_person_proofing/post_office.rb index f2350621978..54def242031 100644 --- a/app/services/usps_in_person_proofing/post_office.rb +++ b/app/services/usps_in_person_proofing/post_office.rb @@ -12,7 +12,6 @@ module UspsInPersonProofing :weekday_hours, :zip_code_4, :zip_code_5, - :is_pilot, keyword_init: true, ) end diff --git a/app/services/usps_in_person_proofing/proofer.rb b/app/services/usps_in_person_proofing/proofer.rb index f94ad4a1040..9d24bc856c5 100644 --- a/app/services/usps_in_person_proofing/proofer.rb +++ b/app/services/usps_in_person_proofing/proofer.rb @@ -204,7 +204,6 @@ def parse_facilities(facilities) weekday_hours: hours['weekdayHours'], zip_code_4: post_office['zip4'], zip_code_5: post_office['zip5'], - is_pilot: post_office['isPilot'], ) end end From 5be5f2d9b7fb25fb6adec365666f7652bbd1de86 Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 6 Nov 2024 15:52:05 -0600 Subject: [PATCH 8/9] LG-14425: update s3 bucket name (#11462) * update s3 bucket name * changelog: Internal, Reporting, S3 Bucket Name change --- app/jobs/data_warehouse/daily_sensitive_column_job.rb | 2 +- config/application.yml.default | 2 +- lib/identity_config.rb | 2 +- .../daily_sensitive_column_report_spec.rb | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/jobs/data_warehouse/daily_sensitive_column_job.rb b/app/jobs/data_warehouse/daily_sensitive_column_job.rb index bdb0bec755e..d8c6d5d1317 100644 --- a/app/jobs/data_warehouse/daily_sensitive_column_job.rb +++ b/app/jobs/data_warehouse/daily_sensitive_column_job.rb @@ -42,7 +42,7 @@ def generate_column_data(columns, table) end def bucket_name - bucket_name = IdentityConfig.store.s3_idp_internal_dw_tasks + bucket_name = IdentityConfig.store.s3_idp_dw_tasks env = Identity::Hostdata.env aws_account_id = Identity::Hostdata.aws_account_id aws_region = Identity::Hostdata.aws_region diff --git a/config/application.yml.default b/config/application.yml.default index 376fe87c200..8a39f3775fd 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -344,7 +344,7 @@ ruby_workers_idv_enabled: true rules_of_use_horizon_years: 5 rules_of_use_updated_at: '2022-01-19T00:00:00Z' # Production has a newer timestamp than this, update directly in S3 s3_data_warehouse_bucket_prefix: 'login-gov-analytics-export' -s3_idp_internal_dw_tasks: 'login-gov-idp-internal-dw-tasks' +s3_idp_dw_tasks: 'login-gov-idp-dw-tasks' s3_public_reports_enabled: false s3_report_bucket_prefix: login-gov.reports s3_report_public_bucket_prefix: login-gov-pubdata diff --git a/lib/identity_config.rb b/lib/identity_config.rb index 8eaaf9bd709..dbdc4874fa7 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -373,7 +373,7 @@ def self.store config.add(:s3_report_bucket_prefix, type: :string) config.add(:s3_report_public_bucket_prefix, type: :string) config.add(:s3_data_warehouse_bucket_prefix, type: :string) - config.add(:s3_idp_internal_dw_tasks, type: :string) + config.add(:s3_idp_dw_tasks, type: :string) config.add(:s3_reports_enabled, type: :boolean) config.add(:saml_endpoint_configs, type: :json, options: { symbolize_names: true }) config.add(:saml_secret_rotation_enabled, type: :boolean) diff --git a/spec/jobs/data_warehouse/daily_sensitive_column_report_spec.rb b/spec/jobs/data_warehouse/daily_sensitive_column_report_spec.rb index b671355600a..5c81de89a0b 100644 --- a/spec/jobs/data_warehouse/daily_sensitive_column_report_spec.rb +++ b/spec/jobs/data_warehouse/daily_sensitive_column_report_spec.rb @@ -5,9 +5,9 @@ let(:timestamp) { Date.new(2024, 10, 15).in_time_zone('UTC') } let(:job) { described_class.new } - let(:expected_bucket) { 'login-gov-ipd-internal-dw-tasks-test-1234-us-west-2' } + let(:expected_bucket) { 'login-gov-ipd-dw-tasks-test-1234-us-west-2' } let(:tables) { ['auth_app_configurations'] } - let(:s3_idp_internal_dw_tasks) { 'login-gov-idp-internal-dw-tasks' } + let(:s3_idp_dw_tasks) { 'login-gov-idp-dw-tasks' } let(:expected_json) do { @@ -58,7 +58,7 @@ { body: anything, content_type: 'application/json', - bucket: 'login-gov-idp-internal-dw-tasks-int-1234-us-west-1', + bucket: 'login-gov-idp-dw-tasks-int-1234-us-west-1', } end @@ -66,8 +66,8 @@ allow(Identity::Hostdata).to receive(:env).and_return('int') allow(Identity::Hostdata).to receive(:aws_account_id).and_return('1234') allow(Identity::Hostdata).to receive(:aws_region).and_return('us-west-1') - allow(IdentityConfig.store).to receive(:s3_idp_internal_dw_tasks). - and_return(s3_idp_internal_dw_tasks) + allow(IdentityConfig.store).to receive(:s3_idp_dw_tasks). + and_return(s3_idp_dw_tasks) Aws.config[:s3] = { stub_responses: { From cc00194dfbe8cc991bb3ff5faafe1be36098af5c Mon Sep 17 00:00:00 2001 From: Jeremy Curcio Date: Thu, 7 Nov 2024 10:17:45 -0500 Subject: [PATCH 9/9] Include missing bg-secondary class to make HR be red (#11465) * Include missing bg-secondary class to make HR be red * Include in the footer HR as well changelog: User-Facing Improvements, Automated Reports, Add color class to the recently added HRs --- app/views/report_mailer/tables_report.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/report_mailer/tables_report.html.erb b/app/views/report_mailer/tables_report.html.erb index f102bfea68c..403db2ce5fa 100644 --- a/app/views/report_mailer/tables_report.html.erb +++ b/app/views/report_mailer/tables_report.html.erb @@ -10,7 +10,7 @@ height: 21, ) %> -
+
<%= @message %>
<% @reports.each do |report| %> <% header, *rows = report.table %> @@ -47,4 +47,4 @@ <% end %> -
+