Skip to content

Commit

Permalink
Merge pull request #11117 from 18F/stages/rc-2024-08-20
Browse files Browse the repository at this point in the history
Deploy RC 407 to Production
  • Loading branch information
solipet authored Aug 20, 2024
2 parents 68d60be + a897789 commit 7e4c865
Show file tree
Hide file tree
Showing 83 changed files with 1,850 additions and 339 deletions.
4 changes: 4 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,9 @@ trigger_devops:
- kubectl config get-contexts
- export CONTEXT=$(kubectl config get-contexts | grep reviewapp | awk '{print $1}' | head -1)
- kubectl config use-context "$CONTEXT"
- export SANITIZED_BRANCH_NAME=$(echo "$CI_COMMIT_REF_NAME" | tr '/' '-' | tr -c '[:alnum:]-_' '-' | sed 's/-*$//')
- echo "${CI_COMMIT_REF_NAME}"
- echo "${SANITIZED_BRANCH_NAME}"
- |-
export IDP_CONFIG=$(cat <<EOF
{
Expand Down Expand Up @@ -532,6 +535,7 @@ trigger_devops:
- >-
helm upgrade --install --namespace review-apps
--debug
--set global.labels.branch="${SANITIZED_BRANCH_NAME}"
--set env="reviewapps-$CI_ENVIRONMENT_SLUG"
--set idp.image.repository="${ECR_REGISTRY}/identity-idp/review"
--set idp.image.tag="${CI_COMMIT_SHA}"
Expand Down
7 changes: 1 addition & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,7 @@ commits together, merges it, then deletes the branch.

Everyone is encouraged to participate in code review. To solicit feedback from specific people,
consider adding individuals or groups as requested reviewers on your pull request. Most internal
product teams have a team handle which can be used to notify everyone on that team, or you can
request reviews from one of the available interest group teams:

- `18f/identity-frontend` for developers interested in frontend development

To request to join any of these teams, you can contact any existing member and ask to be added.
product teams have a team handle which can be used to notify everyone on that team.

## Public domain

Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ GEM
profanity_filter (0.1.1)
prometheus_exporter (2.1.0)
webrick
propshaft (0.7.0)
propshaft (0.9.1)
actionpack (>= 7.0.0)
activesupport (>= 7.0.0)
rack
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ lint_erb: ## Lints ERB files
bundle exec erblint app/views app/components

lint_yaml: normalize_yaml ## Lints YAML files
(! git diff --name-only | grep "^config/.*\.yml$$") || (echo "Error: Run 'make normalize_yaml' to normalize YAML"; exit 1)
(! git diff --name-only | grep "^config/.*\.yml") || (echo "Error: Run 'make normalize_yaml' to normalize YAML"; exit 1)

lint_font_glyphs: ## Lints to validate content glyphs match expectations from fonts
scripts/yaml_characters \
Expand Down
9 changes: 9 additions & 0 deletions app/controllers/socure_webhook_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class SocureWebhookController < ApplicationController
skip_before_action :verify_authenticity_token

def create
render json: { message: 'Got here.' }
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ def show
service_provider: current_sp,
remember_device_default: remember_device_default,
)
@backup_code_form = BackupCodeVerificationForm.new(current_user)
@backup_code_form = BackupCodeVerificationForm.new(user: current_user, request:)
end

def create
@backup_code_form = BackupCodeVerificationForm.new(current_user)
@backup_code_form = BackupCodeVerificationForm.new(user: current_user, request:)
result = @backup_code_form.submit(backup_code_params)
handle_result(result)
end
Expand All @@ -46,10 +46,10 @@ def presenter_for_two_factor_authentication_method
)
end

def handle_invalid_backup_code
def handle_invalid_backup_code(result)
update_invalid_user

flash.now[:error] = t('two_factor_authentication.invalid_backup_code')
flash.now[:error] = result.first_error_message

if current_user.locked_out?
handle_second_factor_locked_user(type: 'backup_code')
Expand All @@ -69,7 +69,7 @@ def handle_result(result)
return handle_last_code if all_codes_used?
handle_valid_backup_code
else
handle_invalid_backup_code
handle_invalid_backup_code(result)
end
end

Expand Down
55 changes: 47 additions & 8 deletions app/forms/backup_code_verification_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,74 @@

class BackupCodeVerificationForm
include ActiveModel::Model
include ActionView::Helpers::TranslationHelper
include DOTIW::Methods

def initialize(user)
validate :validate_rate_limited
validate :validate_and_consume_backup_code!

attr_reader :user, :backup_code, :request

def initialize(user:, request:)
@user = user
@backup_code = ''
@request = request
end

def submit(params)
@backup_code = params[:backup_code]

rate_limiter.increment!

FormResponse.new(
success: valid_backup_code?,
success: valid?,
errors:,
extra: extra_analytics_attributes,
serialize_error_details_only: true,
)
end

private

def validate_rate_limited
return if !rate_limiter.limited?
errors.add(
:backup_code,
:rate_limited,
message: t(
'errors.messages.phone_confirmation_limited',
timeout: distance_of_time_in_words(Time.zone.now, rate_limiter.expires_at),
),
)
end

attr_reader :user, :backup_code
def validate_and_consume_backup_code!
return if rate_limiter.limited? || valid_backup_code?
errors.add(:backup_code, :invalid, message: t('two_factor_authentication.invalid_backup_code'))
end

def valid_backup_code?
valid_backup_code_config_created_at.present?
end

def valid_backup_code_config_created_at
return @valid_backup_code_config_created_at if defined?(@valid_backup_code_config_created_at)
@valid_backup_code_config_created_at = BackupCodeGenerator.new(@user).
@valid_backup_code_config_created_at = BackupCodeGenerator.new(user).
if_valid_consume_code_return_config_created_at(backup_code)
end

def rate_limiter
@rate_limiter ||= RateLimiter.new(
rate_limit_type: :backup_code_user_id_per_ip,
target: [user.id, request.ip].join('-'),
)
end

def extra_analytics_attributes
{
multi_factor_auth_method_created_at: valid_backup_code_config_created_at&.strftime('%s%L'),
}
{ multi_factor_auth_method_created_at: }
end

def multi_factor_auth_method_created_at
return nil if !valid?
valid_backup_code_config_created_at.strftime('%s%L')
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { FormStepsButton } from '@18f/identity-form-steps';
import { Cancel } from '@18f/identity-verify-flow';
import { useI18n, HtmlTextWithStrongNoWrap } from '@18f/identity-react-i18n';
import type { FormStepComponentProps } from '@18f/identity-form-steps';
import UnknownError from './unknown-error';
import GeneralError from './general-error';
import TipList from './tip-list';
import { SelfieCaptureContext } from '../context';
import {
DocumentCaptureSubheaderOne,
SelfieCaptureWithHeader,
DocumentFrontAndBackCapture,
} from './documents-step';
} from './documents-and-selfie-step';
import type { ReviewIssuesStepValue } from './review-issues-step';

interface DocumentCaptureReviewIssuesProps extends FormStepComponentProps<ReviewIssuesStepValue> {
Expand Down Expand Up @@ -53,7 +53,7 @@ function DocumentCaptureReviewIssues({
{isSelfieCaptureEnabled && (
<DocumentCaptureSubheaderOne isSelfieCaptureEnabled={isSelfieCaptureEnabled} />
)}
<UnknownError
<GeneralError
unknownFieldErrors={unknownFieldErrors}
isFailedDocType={isFailedDocType}
isFailedSelfie={isFailedSelfie}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { FormStepError } from '@18f/identity-form-steps';
import type { I18n } from '@18f/identity-i18n';
import Warning from './warning';
import DocumentCaptureTroubleshootingOptions from './document-capture-troubleshooting-options';
import UnknownError from './unknown-error';
import GeneralError from './general-error';
import { InPersonContext } from '../context';
import AnalyticsContext from '../context/analytics';
import SelfieCaptureContext from '../context/selfie-capture';
Expand Down Expand Up @@ -124,7 +124,7 @@ function DocumentCaptureWarning({
>
<div ref={subheadingRef}>{!!subheading && subheading}</div>
<div ref={errorMessageDisplayedRef}>
<UnknownError
<GeneralError
unknownFieldErrors={unknownFieldErrors}
isFailedDocType={isFailedDocType}
isFailedSelfie={isFailedSelfie}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useDidUpdateEffect } from '@18f/identity-react-hooks';
import type { FormStep } from '@18f/identity-form-steps';
import { getConfigValue } from '@18f/identity-config';
import { UploadFormEntriesError } from '../services/upload';
import DocumentsStep from './documents-step';
import DocumentsAndSelfieStep from './documents-and-selfie-step';
import InPersonPrepareStep from './in-person-prepare-step';
import InPersonLocationPostOfficeSearchStep from './in-person-location-post-office-search-step';
import InPersonLocationFullAddressEntryPostOfficeSearchStep from './in-person-location-full-address-entry-post-office-search-step';
Expand Down Expand Up @@ -53,7 +53,7 @@ function DocumentCapture({ onStepChange = () => {} }: DocumentCaptureProps) {
// Define different states to be used in human readable array declaration
const documentFormStep: FormStep = {
name: 'documents',
form: DocumentsStep,
form: DocumentsAndSelfieStep,
title: t('doc_auth.headings.document_capture'),
};
const reviewFormStep: FormStep = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export function DocumentFrontAndBackCapture({

type ImageValue = Blob | string | null | undefined;

interface DocumentsStepValue {
interface DocumentsAndSelfieStepValue {
front: ImageValue;
back: ImageValue;
selfie: ImageValue;
Expand All @@ -93,17 +93,17 @@ interface DocumentsStepValue {
}

type DefaultSideProps = Pick<
FormStepComponentProps<DocumentsStepValue>,
FormStepComponentProps<DocumentsAndSelfieStepValue>,
'registerField' | 'onChange' | 'errors' | 'onError'
>;

function DocumentsStep({
export default function DocumentsAndSelfieStep({
value = {},
onChange = () => {},
errors = [],
onError = () => {},
registerField = () => undefined,
}: FormStepComponentProps<DocumentsStepValue>) {
}: FormStepComponentProps<DocumentsAndSelfieStepValue>) {
const { t } = useI18n();
const { isMobile } = useContext(DeviceContext);
const { isLastStep } = useContext(FormStepsContext);
Expand Down Expand Up @@ -145,5 +145,3 @@ function DocumentsStep({
</>
);
}

export default DocumentsStep;
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Link } from '@18f/identity-components';
import formatHTML from '@18f/identity-react-i18n/format-html';
import MarketingSiteContext from '../context/marketing-site';

interface UnknownErrorProps extends ComponentProps<'p'> {
interface GeneralErrorProps extends ComponentProps<'p'> {
unknownFieldErrors: FormStepError<{ front: string; back: string }>[];
isFailedDocType: boolean;
isFailedSelfie: boolean;
Expand Down Expand Up @@ -40,15 +40,15 @@ function getError({ unknownFieldErrors }: GetErrorArguments) {
return err;
}

function UnknownError({
function GeneralError({
unknownFieldErrors = [],
isFailedDocType = false,
isFailedSelfie = false,
isFailedSelfieLivenessOrQuality = false,
altFailedDocTypeMsg = null,
altIsFailedSelfieDontIncludeAttempts = false,
hasDismissed,
}: UnknownErrorProps) {
}: GeneralErrorProps) {
const { t } = useI18n();
const { getHelpCenterURL } = useContext(MarketingSiteContext);
const helpCenterLink = getHelpCenterURL({
Expand Down Expand Up @@ -107,4 +107,4 @@ function UnknownError({
return <p />;
}

export default UnknownError;
export default GeneralError;
1 change: 1 addition & 0 deletions app/jobs/get_usps_proofing_results_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ def handle_expired_status_update(enrollment, response, response_message)
status: :expired,
status_check_completed_at: Time.zone.now,
)
enrollment.profile.deactivate_due_to_ipp_expiration

if fraud_result_pending?(enrollment)
analytics(user: enrollment.user).idv_ipp_deactivated_for_never_visiting_post_office(
Expand Down
6 changes: 6 additions & 0 deletions app/jobs/reports/monthly_key_metrics_report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require 'csv'
require 'reporting/proofing_rate_report'
require 'reporting/monthly_idv_report'

module Reports
class MonthlyKeyMetricsReport < BaseReport
Expand Down Expand Up @@ -68,6 +69,7 @@ def reports
@reports ||= [
active_users_count_report.active_users_count_emailable_report,
total_user_count_report.total_user_count_emailable_report,
monthly_idv_report.monthly_idv_report_emailable_report,
proofing_rate_report.proofing_rate_emailable_report,
account_deletion_rate_report.account_deletion_emailable_report,
account_reuse_report.account_reuse_emailable_report,
Expand Down Expand Up @@ -113,6 +115,10 @@ def agency_and_sp_report
@agency_and_sp_report ||= Reporting::AgencyAndSpReport.new(report_date)
end

def monthly_idv_report
@monthly_idv_report ||= Reporting::MonthlyIdvReport.new(end_date: report_date)
end

def upload_to_s3(report_body, report_name: nil)
_latest, path = generate_s3_paths(REPORT_NAME, 'csv', subname: report_name, now: report_date)

Expand Down
2 changes: 1 addition & 1 deletion app/mailers/report_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def tables_report(
@message = message

@reports = reports.map(&:dup).each_with_index do |report, index|
report.title ||= "Table #{index + 1}"
report.title ||= report.subtitle || "Table #{index + 1}"
end

case attachment_format
Expand Down
8 changes: 8 additions & 0 deletions app/models/profile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,14 @@ def deactivate_due_to_gpo_expiration
)
end

def deactivate_due_to_ipp_expiration
update!(
active: false,
deactivation_reason: :verification_cancelled,
in_person_verification_pending_at: nil,
)
end

def deactivate_for_in_person_verification
update!(active: false, in_person_verification_pending_at: Time.zone.now)
end
Expand Down
4 changes: 2 additions & 2 deletions app/presenters/completions_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ class CompletionsPresenter
attr_reader :current_user, :current_sp, :decrypted_pii, :requested_attributes, :completion_context

SORTED_IAL2_ATTRIBUTE_MAPPING = [
[[:email], :email],
[[:all_emails], :all_emails],
[%i[given_name family_name], :full_name],
[[:address], :address],
[[:phone], :phone],
[[:email], :email],
[[:all_emails], :all_emails],
[[:birthdate], :birthdate],
[[:social_security_number], :social_security_number],
[[:x509_subject], :x509_subject],
Expand Down
Loading

0 comments on commit 7e4c865

Please sign in to comment.