- |
+ |
<%= image_tag('email/letter-warning.png', width: 140, height: 140, alt: '') %>
|
diff --git a/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb b/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb
index 8c095e20d82..cd8ce7bc386 100644
--- a/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb
+++ b/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb
@@ -1,7 +1,7 @@
<% if @presenter.outage_message_enabled? %>
- |
+ |
<%= image_tag('email/warning.png', width: 16, height: 16, alt: '') %>
|
@@ -28,7 +28,7 @@
<%# Alert box %>
- |
+ |
<%= image_tag('email/info.png', width: 16, height: 16, alt: '') %>
|
@@ -51,9 +51,9 @@
- |
+ |
<%= image_tag(
- asset_url('idv/real-id.svg'),
+ asset_url('email/real-id.png'),
width: 110,
height: 80,
alt: t('in_person_proofing.process.eipp_bring_id.image_alt_text'),
@@ -61,7 +61,7 @@
class: 'margin-bottom-3',
) %>
|
-
+ |
|
<%= t('in_person_proofing.process.eipp_bring_id.info') %>
@@ -70,7 +70,7 @@
|
-
+
<%# Option 2: Bring a standard State ID... %>
<%= t('in_person_proofing.process.eipp_what_to_bring.heading') %>
@@ -80,16 +80,16 @@
- |
+ |
<%= image_tag(
- asset_url('idv/state-id-and-passport.svg'),
- width: 110.46,
- height: 129.11,
+ asset_url('email/state-id-and-passport.png'),
+ width: 110,
+ height: 129,
alt: t('in_person_proofing.process.eipp_state_id_passport.image_alt_text'),
role: 'img',
) %>
|
-
+ |
|
<%= t('in_person_proofing.process.eipp_state_id_passport.heading') %>
@@ -98,22 +98,22 @@
|
-
+
<%# B. State ID + Military ID %>
- |
+ |
<%= image_tag(
- asset_url('idv/state-id-and-military-id.svg'),
- width: 110.46,
+ asset_url('email/state-id-and-military-id.png'),
+ width: 110,
height: 93,
alt: t('in_person_proofing.process.eipp_state_id_military_id.image_alt_text'),
role: 'img',
) %>
|
-
+ |
|
<%= t('in_person_proofing.process.eipp_state_id_military_id.heading') %>
@@ -122,22 +122,22 @@
|
-
+
<%# C. State ID + two supporting documents %>
- |
+ |
<%= image_tag(
- asset_url('idv/state-id-and-fair-evidence-documents.svg'),
- width: 110.46,
+ asset_url('email/state-id-and-fair-evidence-documents.png'),
+ width: 110,
height: 107,
alt: t('in_person_proofing.process.eipp_state_id_supporting_docs.image_alt_text'),
role: 'img',
) %>
|
-
+ |
|
<%= t('in_person_proofing.process.eipp_state_id_supporting_docs.heading') %>
diff --git a/config/application.yml.default b/config/application.yml.default
index 490eac60801..24e0c0ecfb4 100644
--- a/config/application.yml.default
+++ b/config/application.yml.default
@@ -276,7 +276,6 @@ reset_password_email_max_attempts: 20
reset_password_email_window_in_minutes: 60
reset_password_on_auth_fraud_event: true
risc_notifications_local_enabled: false
-risc_notifications_active_job_enabled: false
risc_notifications_rate_limit_interval: 60
risc_notifications_rate_limit_max_requests: 1_000
risc_notifications_rate_limit_overrides: '{"https://example.com/push":{"interval":120,"max_requests":10000}}'
@@ -298,6 +297,7 @@ session_timeout_in_minutes: 15
session_timeout_warning_seconds: 150
session_total_duration_timeout_in_minutes: 720
ses_configuration_set_name: ''
+sign_in_recaptcha_score_threshold: 0.0
sp_handoff_bounce_max_seconds: 2
show_unsupported_passkey_platform_authentication_setup: false
show_user_attribute_deprecation_warnings: false
@@ -411,6 +411,7 @@ development:
secret_key_base: development_secret_key_base
session_encryption_key: 27bad3c25711099429c1afdfd1890910f3b59f5a4faec1c85e945cb8b02b02f261ba501d99cfbb4fab394e0102de6fecf8ffe260f322f610db3e96b2a775c120
show_unsupported_passkey_platform_authentication_setup: true
+ sign_in_recaptcha_score_threshold: 0.3
skip_encryption_allowed_list: '["urn:gov:gsa:SAML:2.0.profiles:sp:sso:localhost"]'
state_tracking_enabled: true
telephony_adapter: test
diff --git a/config/application.yml.default.docker b/config/application.yml.default.docker
index 5692d6a86a7..4aa054a39ba 100644
--- a/config/application.yml.default.docker
+++ b/config/application.yml.default.docker
@@ -26,6 +26,7 @@ production:
piv_cac_verify_token_secret: "a6ed2fb16320ae85a7a8e48f4b0eeb6afca5f1ac64af2a05a0c486df1c20b693987832a11f0910729f199b3ce5c7609fe6d580bed428d035ea8460990e38a382"
piv_cac_verify_token_url: ['env', 'PIV_CAC_VERIFY_TOKEN_URL']
secret_key_base: development_secret_key_base
+ sign_in_recaptcha_score_threshold: 0.3
domain_name: ['env', 'DOMAIN_NAME']
use_kms: false
email_from: no-reply@identitysandbox.gov
diff --git a/docs/frontend.md b/docs/frontend.md
index 0b2285cd49a..2aef106c123 100644
--- a/docs/frontend.md
+++ b/docs/frontend.md
@@ -125,8 +125,11 @@ yarn add -W webpack
As much as possible, try to use the same version of a dependency when it is used across multiple
workspace packages. Otherwise, it can inflate the size of the compiled bundles and have a negative
-performance impact on users. Similarly, consider using a tool like [`yarn-deduplicate`](https://github.com/scinos/yarn-deduplicate)
-to deduplicate resolved package versions within the Yarn lockfile.
+performance impact on users.
+
+We use [`yarn-deduplicate`](https://github.com/scinos/yarn-deduplicate)
+to deduplicate resolved package versions within the Yarn lockfile, and enforce it with
+the `make lint_yarn_lock` check.
### Localization
diff --git a/lib/data_requests/local/fetch_cloudwatch_logs.rb b/lib/data_requests/local/fetch_cloudwatch_logs.rb
index f9474818dfc..090d666e784 100644
--- a/lib/data_requests/local/fetch_cloudwatch_logs.rb
+++ b/lib/data_requests/local/fetch_cloudwatch_logs.rb
@@ -81,6 +81,7 @@ def query_string
<<~QUERY
fields @timestamp, @message
| filter properties.user_id = '#{uuid}' and name != 'IRS Attempt API: Event metadata'
+ | limit #{Reporting::CloudwatchClient::MAX_RESULTS_LIMIT}
QUERY
end
diff --git a/lib/feature_management.rb b/lib/feature_management.rb
index 45a8a465c9d..c5469bb8dc5 100644
--- a/lib/feature_management.rb
+++ b/lib/feature_management.rb
@@ -106,10 +106,18 @@ def self.log_to_stdout?
end
def self.phone_recaptcha_enabled?
- return false if IdentityConfig.store.recaptcha_site_key.blank? ||
- !IdentityConfig.store.phone_recaptcha_score_threshold.positive?
+ IdentityConfig.store.phone_recaptcha_score_threshold.positive? && recaptcha_enabled?
+ end
+
+ def self.sign_in_recaptcha_enabled?
+ IdentityConfig.store.sign_in_recaptcha_score_threshold.positive? && recaptcha_enabled?
+ end
- recaptcha_enterprise? || IdentityConfig.store.recaptcha_secret_key.present?
+ def self.recaptcha_enabled?
+ IdentityConfig.store.recaptcha_site_key.present? && (
+ recaptcha_enterprise? ||
+ IdentityConfig.store.recaptcha_secret_key.present?
+ )
end
def self.recaptcha_enterprise?
diff --git a/lib/identity_config.rb b/lib/identity_config.rb
index 98314846d7b..773018ff91a 100644
--- a/lib/identity_config.rb
+++ b/lib/identity_config.rb
@@ -13,6 +13,7 @@ def self.store
Identity::Hostdata.config
end
+ # identity-hostdata transforms these configs to the described type
# rubocop:disable Metrics/BlockLength
BUILDER = proc do |config|
# ______________________________________
@@ -334,7 +335,6 @@ def self.store
config.add(:reset_password_email_max_attempts, type: :integer)
config.add(:reset_password_email_window_in_minutes, type: :integer)
config.add(:reset_password_on_auth_fraud_event, type: :boolean)
- config.add(:risc_notifications_active_job_enabled, type: :boolean)
config.add(:risc_notifications_local_enabled, type: :boolean)
config.add(:risc_notifications_rate_limit_interval, type: :integer)
config.add(:risc_notifications_rate_limit_max_requests, type: :integer)
@@ -367,6 +367,7 @@ def self.store
config.add(:show_user_attribute_deprecation_warnings, type: :boolean)
config.add(:short_term_phone_otp_max_attempts, type: :integer)
config.add(:short_term_phone_otp_max_attempt_window_in_seconds, type: :integer)
+ config.add(:sign_in_recaptcha_score_threshold, type: :float)
config.add(:skip_encryption_allowed_list, type: :json)
config.add(:sp_handoff_bounce_max_seconds, type: :integer)
config.add(:sp_issuer_user_counts_report_configs, type: :json)
diff --git a/lib/reporting/cloudwatch_client.rb b/lib/reporting/cloudwatch_client.rb
index ba67c0f1bf1..1829e0e3f77 100644
--- a/lib/reporting/cloudwatch_client.rb
+++ b/lib/reporting/cloudwatch_client.rb
@@ -4,12 +4,14 @@
require 'ruby-progressbar'
require 'identity/hostdata'
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/string/filters'
module Reporting
class CloudwatchClient
DEFAULT_NUM_THREADS = 5
DEFAULT_WAIT_DURATION = 3
MAX_RESULTS_LIMIT = 10_000
+ MAX_RESULTS_LIMIT_MATCHER = /\|\s+limit\s+#{MAX_RESULTS_LIMIT}/i
attr_reader :num_threads, :wait_duration, :slice_interval, :logger, :log_group_name
@@ -55,6 +57,8 @@ def initialize(
# @yieldparam [Hash] row a row of the query result
# @return [nil]
def fetch(query:, from: nil, to: nil, time_slices: nil)
+ validate_query!(query)
+
results = Concurrent::Array.new if !block_given?
errors = Concurrent::Array.new
each_result_queue = Queue.new if block_given?
@@ -290,6 +294,16 @@ def wait_for_query_result(query_id)
end
# rubocop:enable Rails/TimeZone
+ # @raise [ArgumentError] if the query is missing a limit
+ def validate_query!(query)
+ if ensure_complete_logs? && !query.match?(MAX_RESULTS_LIMIT_MATCHER)
+ raise ArgumentError, <<~STR.squish
+ ensure_complete_logs is true but query is missing '| limit #{MAX_RESULTS_LIMIT}',
+ script is unable to detect incomplete results
+ STR
+ end
+ end
+
# @yield [ProgressBar]
def with_progress_bar
@progress_bar_mutex&.synchronize do
diff --git a/package.json b/package.json
index 643fd7f2833..279d76117b7 100644
--- a/package.json
+++ b/package.json
@@ -91,7 +91,8 @@
"svgo": "^3.2.0",
"swr": "^2.0.0",
"typescript": "^5.2.2",
- "webpack-dev-server": "^5.0.4"
+ "webpack-dev-server": "^5.0.4",
+ "yarn-deduplicate": "^6.0.2"
},
"resolutions": {
"minimist": "1.2.6",
diff --git a/spec/components/alert_component_spec.rb b/spec/components/alert_component_spec.rb
index f52b2666ecb..f31ec38f0d5 100644
--- a/spec/components/alert_component_spec.rb
+++ b/spec/components/alert_component_spec.rb
@@ -19,10 +19,10 @@
expect(rendered).to have_content('locals')
end
- it 'defaults to type "info"' do
+ it 'renders without modifier classes by default' do
rendered = render_inline AlertComponent.new(message: 'FYI')
- expect(rendered).to have_selector('.usa-alert.usa-alert--info')
+ expect(rendered).to have_selector('.usa-alert:not([class*=usa-alert--])')
end
it 'accepts alert type param' do
diff --git a/spec/components/captcha_submit_button_component_spec.rb b/spec/components/captcha_submit_button_component_spec.rb
index 7e18e155f7b..ec8a2a055a0 100644
--- a/spec/components/captcha_submit_button_component_spec.rb
+++ b/spec/components/captcha_submit_button_component_spec.rb
@@ -71,6 +71,14 @@
end
end
+ context 'with button options' do
+ let(:options) { super().merge(button_options: { full_width: true }) }
+
+ it 'renders spinner button with additional options' do
+ expect(rendered).to have_css('lg-spinner-button .usa-button--full-width')
+ end
+ end
+
describe 'mock score field' do
let(:recaptcha_mock_validator) { nil }
diff --git a/spec/components/previews/alert_component_preview.rb b/spec/components/previews/alert_component_preview.rb
index 73f932b740f..3d60ce6a258 100644
--- a/spec/components/previews/alert_component_preview.rb
+++ b/spec/components/previews/alert_component_preview.rb
@@ -24,18 +24,14 @@ def emergency
render(AlertComponent.new(message: 'An emergency message', type: :emergency))
end
- def other
- render(AlertComponent.new(message: 'An other message', type: :other))
- end
-
def with_custom_text_tag
render(AlertComponent.new(type: :success, message: 'A custom message', text_tag: 'div'))
end
# @!endgroup
# @param message text
- # @param type select [info, success, warning, error, emergency, other]
- def workbench(message: 'An important message', type: :info)
- render(AlertComponent.new(message:, type:))
+ # @param type select [~, info, success, warning, error, emergency]
+ def workbench(message: 'An important message', type: nil)
+ render(AlertComponent.new(message:, type: type&.to_sym))
end
end
diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb
index 6a9f029888a..e50c63953fe 100644
--- a/spec/controllers/users/sessions_controller_spec.rb
+++ b/spec/controllers/users/sessions_controller_spec.rb
@@ -53,6 +53,7 @@
success: true,
user_id: user.uuid,
user_locked_out: false,
+ valid_captcha_result: true,
bad_password_count: 0,
sp_request_url_present: false,
remember_device: false,
@@ -123,6 +124,7 @@
success: false,
user_id: user.uuid,
user_locked_out: false,
+ valid_captcha_result: true,
bad_password_count: 1,
sp_request_url_present: false,
remember_device: false,
@@ -142,6 +144,7 @@
success: false,
user_id: 'anonymous-uuid',
user_locked_out: false,
+ valid_captcha_result: true,
bad_password_count: 1,
sp_request_url_present: false,
remember_device: false,
@@ -173,6 +176,7 @@
success: false,
user_id: user.uuid,
user_locked_out: true,
+ valid_captcha_result: true,
bad_password_count: 0,
sp_request_url_present: false,
remember_device: false,
@@ -184,6 +188,28 @@
post :create, params: { user: { email: user.email.upcase, password: user.password } }
end
+ it 'tracks unsuccessful authentication for failed reCAPTCHA' do
+ user = create(:user, :fully_registered)
+
+ allow(FeatureManagement).to receive(:sign_in_recaptcha_enabled?).and_return(true)
+ allow(IdentityConfig.store).to receive(:recaptcha_mock_validator).and_return(true)
+ allow(IdentityConfig.store).to receive(:sign_in_recaptcha_score_threshold).and_return(0.2)
+ stub_analytics
+
+ post :create, params: { user: { email: user.email, password: user.password, score: 0.1 } }
+
+ expect(@analytics).to have_logged_event(
+ 'Email and Password Authentication',
+ success: false,
+ user_id: user.uuid,
+ user_locked_out: false,
+ valid_captcha_result: false,
+ bad_password_count: 0,
+ remember_device: false,
+ sp_request_url_present: false,
+ )
+ end
+
it 'tracks count of multiple unsuccessful authentication attempts' do
user = create(
:user,
@@ -196,6 +222,7 @@
success: false,
user_id: user.uuid,
user_locked_out: false,
+ valid_captcha_result: true,
bad_password_count: 2,
sp_request_url_present: false,
remember_device: false,
@@ -214,6 +241,7 @@
success: false,
user_id: 'anonymous-uuid',
user_locked_out: false,
+ valid_captcha_result: true,
bad_password_count: 1,
sp_request_url_present: true,
remember_device: false,
@@ -384,6 +412,7 @@
success: true,
user_id: user.uuid,
user_locked_out: false,
+ valid_captcha_result: true,
bad_password_count: 0,
sp_request_url_present: false,
remember_device: false,
@@ -510,6 +539,7 @@
success: true,
user_id: user.uuid,
user_locked_out: false,
+ valid_captcha_result: true,
bad_password_count: 0,
sp_request_url_present: false,
remember_device: true,
@@ -535,6 +565,7 @@
success: true,
user_id: user.uuid,
user_locked_out: false,
+ valid_captcha_result: true,
bad_password_count: 0,
sp_request_url_present: false,
remember_device: true,
diff --git a/spec/controllers/users/webauthn_setup_controller_spec.rb b/spec/controllers/users/webauthn_setup_controller_spec.rb
index 434ad532ff5..96a5f9b9612 100644
--- a/spec/controllers/users/webauthn_setup_controller_spec.rb
+++ b/spec/controllers/users/webauthn_setup_controller_spec.rb
@@ -348,8 +348,10 @@
'Multi-Factor Authentication Setup',
{
enabled_mfa_methods_count: 0,
- errors: { name: [I18n.t('errors.webauthn_platform_setup.general_error')] },
- error_details: { name: { attestation_error: true } },
+ errors: {
+ attestation_object: [I18n.t('errors.webauthn_platform_setup.general_error')],
+ },
+ error_details: { attestation_object: { invalid: true } },
in_account_creation_flow: false,
mfa_method_counts: {},
multi_factor_auth_method: 'webauthn_platform',
diff --git a/spec/forms/sign_in_recaptcha_form_spec.rb b/spec/forms/sign_in_recaptcha_form_spec.rb
new file mode 100644
index 00000000000..65c7e0328f4
--- /dev/null
+++ b/spec/forms/sign_in_recaptcha_form_spec.rb
@@ -0,0 +1,87 @@
+require 'rails_helper'
+
+RSpec.describe SignInRecaptchaForm do
+ let(:user) { create(:user, :with_authenticated_device) }
+ let(:score_threshold_config) { 0.2 }
+ let(:analytics) { FakeAnalytics.new }
+ let(:email) { user.email }
+ let(:recaptcha_token) { 'token' }
+ let(:device_cookie) { Random.hex }
+ let(:score) { 1.0 }
+ subject(:form) do
+ described_class.new(form_class: RecaptchaMockForm, analytics:, score:)
+ end
+ before do
+ allow(IdentityConfig.store).to receive(:sign_in_recaptcha_score_threshold).
+ and_return(score_threshold_config)
+ end
+
+ it 'passes instance variables to form' do
+ recaptcha_form = instance_double(
+ RecaptchaMockForm,
+ submit: FormResponse.new(success: true),
+ )
+ expect(RecaptchaMockForm).to receive(:new).
+ with(
+ score_threshold: score_threshold_config,
+ score:,
+ analytics:,
+ recaptcha_action: described_class::RECAPTCHA_ACTION,
+ ).
+ and_return(recaptcha_form)
+
+ form.submit(email:, recaptcha_token:, device_cookie:)
+ end
+
+ context 'with custom recaptcha form class' do
+ subject(:form) do
+ described_class.new(
+ analytics:,
+ form_class: RecaptchaForm,
+ )
+ end
+
+ it 'validates using form instance of the given class' do
+ recaptcha_form = instance_double(
+ RecaptchaForm,
+ submit: FormResponse.new(success: true),
+ )
+ expect(RecaptchaForm).to receive(:new).and_return(recaptcha_form)
+ expect(recaptcha_form).to receive(:submit)
+
+ form.submit(email:, recaptcha_token:, device_cookie:)
+ end
+ end
+
+ describe '#submit' do
+ let(:recaptcha_form_success) { false }
+ subject(:response) { form.submit(email:, recaptcha_token:, device_cookie:) }
+
+ context 'recaptcha form validates as unsuccessful' do
+ let(:score) { 0.0 }
+
+ context 'existing device for user' do
+ let(:device_cookie) { user.devices.first.cookie_uuid }
+
+ it 'is successful' do
+ expect(response.to_h).to eq(success: true)
+ end
+ end
+
+ context 'new device for user' do
+ it 'is unsuccessful with errors from recaptcha validation' do
+ expect(response.to_h).to eq(
+ success: false,
+ error_details: { recaptcha_token: { invalid: true } },
+ )
+ end
+ end
+ end
+
+ context 'recaptcha form validates as successful' do
+ it 'is successful' do
+ expect(response.to_h).to eq(success: true)
+ end
+ end
+ end
+end
diff --git a/spec/forms/webauthn_setup_form_spec.rb b/spec/forms/webauthn_setup_form_spec.rb
index 284b5811446..21aa0aa9c29 100644
--- a/spec/forms/webauthn_setup_form_spec.rb
+++ b/spec/forms/webauthn_setup_form_spec.rb
@@ -15,6 +15,7 @@
platform_authenticator: false,
transports: 'usb',
authenticator_data_value: '153',
+ protocol:,
}
end
let(:subject) { WebauthnSetupForm.new(user:, user_session:, device_name:) }
@@ -41,7 +42,7 @@
pii_like_keypaths: [[:mfa_method_counts, :phone]],
}
- expect(subject.submit(protocol, params).to_h).to eq(
+ expect(subject.submit(params).to_h).to eq(
success: true,
errors: {},
**extra_attributes,
@@ -57,7 +58,7 @@
expect(PushNotification::HttpPush).to receive(:deliver).
with(PushNotification::RecoveryInformationChangedEvent.new(user: user))
- subject.submit(protocol, params)
+ subject.submit(params)
end
context 'with platform authenticator' do
@@ -66,7 +67,7 @@
end
it 'creates a platform authenticator' do
- result = subject.submit(protocol, params)
+ result = subject.submit(params)
expect(result.extra[:multi_factor_auth_method]).to eq 'webauthn_platform'
user.reload
@@ -81,7 +82,7 @@
let(:params) { super().merge(authenticator_data_value: '65') }
it 'includes data flags with bs set as false ' do
- result = subject.submit(protocol, params)
+ result = subject.submit(params)
expect(result.to_h[:authenticator_data_flags]).to eq(
up: true,
@@ -98,7 +99,7 @@
let(:params) { super().merge(authenticator_data_value: 'bad_error') }
it 'should not include authenticator data flag' do
- result = subject.submit(protocol, params)
+ result = subject.submit(params)
expect(result.to_h[:authenticator_data_flags]).to be_nil
end
@@ -108,7 +109,7 @@
let(:params) { super().merge(authenticator_data_value: nil) }
it 'should not include authenticator data flag' do
- result = subject.submit(protocol, params)
+ result = subject.submit(params)
expect(result.to_h[:authenticator_data_flags]).to be_nil
end
@@ -119,7 +120,7 @@
let(:params) { super().merge(transports: 'wrong') }
it 'creates a webauthn configuration without transports' do
- subject.submit(protocol, params)
+ subject.submit(params)
user.reload
@@ -127,7 +128,7 @@
end
it 'includes unknown transports in extra analytics' do
- result = subject.submit(protocol, params)
+ result = subject.submit(params)
expect(result.to_h).to eq(
success: true,
@@ -169,13 +170,17 @@
pii_like_keypaths: [[:mfa_method_counts, :phone]],
}
- expect(subject.submit(protocol, params).to_h).to eq(
+ expect(subject.submit(params).to_h).to eq(
success: false,
- errors: { name: [I18n.t(
- 'errors.webauthn_setup.general_error_html',
- link_html: I18n.t('errors.webauthn_setup.additional_methods_link'),
- )] },
- error_details: { name: { attestation_error: true } },
+ errors: {
+ attestation_object: [
+ I18n.t(
+ 'errors.webauthn_setup.general_error_html',
+ link_html: I18n.t('errors.webauthn_setup.additional_methods_link'),
+ ),
+ ],
+ },
+ error_details: { attestation_object: { invalid: true } },
**extra_attributes,
)
end
@@ -185,7 +190,7 @@
let(:params) { super().except(:transports) }
it 'creates a webauthn configuration without transports' do
- subject.submit(protocol, params)
+ subject.submit(params)
user.reload
@@ -214,13 +219,17 @@
pii_like_keypaths: [[:mfa_method_counts, :phone]],
}
- expect(subject.submit(protocol, params).to_h).to eq(
+ expect(subject.submit(params).to_h).to eq(
success: false,
- errors: { name: [I18n.t(
- 'errors.webauthn_setup.general_error_html',
- link_html: I18n.t('errors.webauthn_setup.additional_methods_link'),
- )] },
- error_details: { name: { attestation_error: true } },
+ errors: {
+ attestation_object: [
+ I18n.t(
+ 'errors.webauthn_setup.general_error_html',
+ link_html: I18n.t('errors.webauthn_setup.additional_methods_link'),
+ ),
+ ],
+ },
+ error_details: { attestation_object: { invalid: true } },
**extra_attributes,
)
end
@@ -234,7 +243,7 @@
user
end
it 'checks for unique device on a webauthn device' do
- result = subject.submit(protocol, params)
+ result = subject.submit(params)
expect(result.extra[:multi_factor_auth_method]).to eq 'webauthn'
expect(result.errors[:name]).to eq(
[I18n.t(
@@ -263,7 +272,7 @@
end
it 'adds a new platform device with the same existing name and appends a (1)' do
- result = subject.submit(protocol, params)
+ result = subject.submit(params)
expect(result.extra[:multi_factor_auth_method]).to eq 'webauthn_platform'
expect(user.webauthn_configurations.platform_authenticators.count).to eq(2)
expect(
@@ -289,7 +298,7 @@
end
it 'adds a second new platform device with the same existing name and appends a (2)' do
- result = subject.submit(protocol, params)
+ result = subject.submit(params)
expect(result.success?).to eq(true)
expect(user.webauthn_configurations.platform_authenticators.count).to eq(3)
diff --git a/spec/javascript/packages/document-capture/components/acuant-capture-canvas-spec.jsx b/spec/javascript/packages/document-capture/components/acuant-capture-canvas-spec.jsx
index 3eaa8b4f8e9..d50fa33d75d 100644
--- a/spec/javascript/packages/document-capture/components/acuant-capture-canvas-spec.jsx
+++ b/spec/javascript/packages/document-capture/components/acuant-capture-canvas-spec.jsx
@@ -1,5 +1,6 @@
import sinon from 'sinon';
import userEvent from '@testing-library/user-event';
+import { act } from '@testing-library/react';
import { AcuantContextProvider, DeviceContext } from '@18f/identity-document-capture';
import AcuantCaptureCanvas from '@18f/identity-document-capture/components/acuant-capture-canvas';
import { render, useAcuant } from '../../../support/document-capture';
@@ -16,9 +17,10 @@ describe('document-capture/components/acuant-capture-canvas', () => {
,
);
- initialize();
- window.AcuantCameraUI.start();
-
+ act(() => {
+ initialize();
+ window.AcuantCameraUI.start();
+ });
const button = getByRole('button', { name: 'doc_auth.buttons.take_picture' });
expect(button.disabled).to.be.true();
diff --git a/spec/javascript/packages/document-capture/higher-order/observable-property-spec.tsx b/spec/javascript/packages/document-capture/hooks/use-observable-property-spec.tsx
similarity index 56%
rename from spec/javascript/packages/document-capture/higher-order/observable-property-spec.tsx
rename to spec/javascript/packages/document-capture/hooks/use-observable-property-spec.tsx
index 0e0f66a56e6..c07f5e19fda 100644
--- a/spec/javascript/packages/document-capture/higher-order/observable-property-spec.tsx
+++ b/spec/javascript/packages/document-capture/hooks/use-observable-property-spec.tsx
@@ -1,14 +1,14 @@
import sinon from 'sinon';
-import {
- defineObservableProperty,
- stopObservingProperty,
-} from '@18f/identity-document-capture/higher-order/observable-property';
+import { useObservableProperty } from '@18f/identity-document-capture/hooks/use-observable-property';
+import { renderHook } from '@testing-library/react-hooks';
-describe('document-capture/higher-order/observable-property', () => {
- describe('defineObservableProperty', () => {
+describe('document-capture/hooks/use-observable-property', () => {
+ describe('useObservableProperty', () => {
it('behaves like an object', () => {
const object = {} as { key?: string };
- defineObservableProperty(object, 'key', () => {});
+
+ renderHook(() => useObservableProperty(object, 'key', () => {}));
+
object.key = 'value';
expect(object.key).to.equal('value');
@@ -17,22 +17,21 @@ describe('document-capture/higher-order/observable-property', () => {
it('calls the callback on changes, with the changed value', () => {
const callback = sinon.spy();
const object = {} as { key?: string };
- defineObservableProperty(object, 'key', callback);
+
+ renderHook(() => useObservableProperty(object, 'key', callback));
object.key = 'value';
expect(callback).to.have.been.calledOnceWithExactly('value');
});
- });
- describe('stopObservingProperty', () => {
- it('removes the defined property and set the last value as a plain value', () => {
+ it('returns a cleanup function that removes the observer', () => {
const object = {} as { key?: string };
const callback = sinon.spy();
- defineObservableProperty(object, 'key', callback);
+ const { unmount } = renderHook(() => useObservableProperty(object, 'key', callback));
object.key = 'value';
- stopObservingProperty(object, 'key');
+ unmount();
expect(object.key).to.equal('value');
object.key = 'second_value';
diff --git a/spec/jobs/reports/drop_off_report_spec.rb b/spec/jobs/reports/drop_off_report_spec.rb
index 9d9b03c8cab..c961b8fcebc 100644
--- a/spec/jobs/reports/drop_off_report_spec.rb
+++ b/spec/jobs/reports/drop_off_report_spec.rb
@@ -2,9 +2,10 @@
RSpec.describe Reports::DropOffReport do
let(:report_date) { Date.new(2023, 12, 12).in_time_zone('UTC') }
+ # This is in S3 as a string that gets parsed via identity_config.rb
let(:report_config) do
- '[{"emails":["ursula@example.com"],
- "issuers":"urn:gov:gsa:openidconnect.profiles:sp:sso:agency_name:app_name"}]'
+ JSON.parse '[{"emails":["ursula@example.com"],
+ "issuers":["urn:gov:gsa:openidconnect.profiles:sp:sso:agency_name:app_name"]}]'
end
before do
diff --git a/spec/jobs/risc_delivery_job_spec.rb b/spec/jobs/risc_delivery_job_spec.rb
index 75b938183d8..ba832a7352d 100644
--- a/spec/jobs/risc_delivery_job_spec.rb
+++ b/spec/jobs/risc_delivery_job_spec.rb
@@ -23,7 +23,6 @@
event_type: event_type,
status: nil,
success: false,
- transport: 'direct',
}
end
@@ -39,6 +38,8 @@
before do
allow(job).to receive(:analytics).and_return(job_analytics)
+ allow(job).to receive(:queue_adapter).
+ and_return(ActiveJob::QueueAdapters::GoodJobAdapter.new)
end
it 'POSTs the jwt to the given URL' do
@@ -68,43 +69,24 @@
stub_request(:post, push_notification_url).to_raise(Faraday::SSLError)
end
- context 'when performed inline' do
- it 'logs an event' do
- expect { perform }.to_not raise_error
-
- expect(job_analytics).to have_logged_event(
- :risc_security_event_pushed,
- risc_event_payload.merge(error: 'Exception from WebMock'),
- )
- end
+ it 'raises and retries via ActiveJob' do
+ expect { perform }.to raise_error(Faraday::SSLError)
end
- context 'when performed in a worker' do
+ context 'it has already failed twice' do
before do
- allow(job).to receive(:queue_adapter).
- and_return(ActiveJob::QueueAdapters::GoodJobAdapter.new)
+ allow(job).to receive(:executions).and_return 2
end
- it 'raises and retries via ActiveJob' do
- expect { perform }.to raise_error(Faraday::SSLError)
- end
+ it 'logs an event' do
+ expect { perform }.to_not raise_error
- context 'it has already failed twice' do
- before do
- allow(job).to receive(:executions).and_return 2
- end
-
- it 'logs an event' do
- expect { perform }.to_not raise_error
-
- expect(job_analytics).to have_logged_event(
- :risc_security_event_pushed,
- risc_event_payload.merge(
- error: 'Exception from WebMock',
- transport: 'async',
- ),
- )
- end
+ expect(job_analytics).to have_logged_event(
+ :risc_security_event_pushed,
+ risc_event_payload.merge(
+ error: 'Exception from WebMock',
+ ),
+ )
end
end
end
@@ -116,42 +98,24 @@
expect(job.faraday).to receive(:post).and_raise(Errno::ECONNREFUSED)
end
- context 'when performed inline' do
- it 'logs an event' do
- expect { perform }.to_not raise_error
- expect(job_analytics).to have_logged_event(
- :risc_security_event_pushed,
- risc_event_payload.merge(error: 'Connection refused'),
- )
- end
+ it 'raises and retries via ActiveJob' do
+ expect { perform }.to raise_error(Errno::ECONNREFUSED)
end
- context 'when performed in a worker' do
+ context 'it has already failed twice' do
before do
- allow(job).to receive(:queue_adapter).
- and_return(ActiveJob::QueueAdapters::GoodJobAdapter.new)
+ allow(job).to receive(:executions).and_return 2
end
- it 'raises and retries via ActiveJob' do
- expect { perform }.to raise_error(Errno::ECONNREFUSED)
- end
+ it 'logs an event' do
+ expect { perform }.to_not raise_error
- context 'it has already failed twice' do
- before do
- allow(job).to receive(:executions).and_return 2
- end
-
- it 'logs an event' do
- expect { perform }.to_not raise_error
-
- expect(job_analytics).to have_logged_event(
- :risc_security_event_pushed,
- risc_event_payload.merge(
- error: 'Connection refused',
- transport: 'async',
- ),
- )
- end
+ expect(job_analytics).to have_logged_event(
+ :risc_security_event_pushed,
+ risc_event_payload.merge(
+ error: 'Connection refused',
+ ),
+ )
end
end
end
@@ -161,55 +125,33 @@
stub_request(:post, push_notification_url).to_return(status: 403)
end
- context 'when performed inline' do
- it 'logs an event' do
- expect { perform }.to_not raise_error
- expect(job_analytics).to have_logged_event(
- :risc_security_event_pushed,
- risc_event_payload.merge(
- error: 'http_push_error',
- status: 403,
- ),
- )
- end
+ it 'logs an event' do
+ expect { perform }.to_not raise_error
+ expect(job_analytics).to have_logged_event(
+ :risc_security_event_pushed,
+ risc_event_payload.merge(
+ error: 'http_push_error',
+ status: 403,
+ ),
+ )
end
- context 'when performed in a worker' do
+ context 'it has already failed twice' do
before do
- allow(job).to receive(:queue_adapter).
- and_return(ActiveJob::QueueAdapters::GoodJobAdapter.new)
+ allow(job).to receive(:executions).and_return 2
end
it 'logs an event' do
expect { perform }.to_not raise_error
+
expect(job_analytics).to have_logged_event(
:risc_security_event_pushed,
risc_event_payload.merge(
error: 'http_push_error',
status: 403,
- transport: 'async',
),
)
end
-
- context 'it has already failed twice' do
- before do
- allow(job).to receive(:executions).and_return 2
- end
-
- it 'logs an event' do
- expect { perform }.to_not raise_error
-
- expect(job_analytics).to have_logged_event(
- :risc_security_event_pushed,
- risc_event_payload.merge(
- error: 'http_push_error',
- status: 403,
- transport: 'async',
- ),
- )
- end
- end
end
end
@@ -218,9 +160,18 @@
stub_request(:post, push_notification_url).to_timeout
end
- context 'when performed inline' do
+ it 'raises and retries via ActiveJob' do
+ expect { perform }.to raise_error(Faraday::ConnectionFailed)
+ end
+
+ context 'it has already failed twice' do
+ before do
+ allow(job).to receive(:executions).and_return 2
+ end
+
it 'logs an event' do
expect { perform }.to_not raise_error
+
expect(job_analytics).to have_logged_event(
:risc_security_event_pushed,
risc_event_payload.merge(
@@ -229,35 +180,6 @@
)
end
end
-
- context 'when performed in a worker' do
- before do
- allow(job).to receive(:queue_adapter).
- and_return(ActiveJob::QueueAdapters::GoodJobAdapter.new)
- end
-
- it 'raises and retries via ActiveJob' do
- expect { perform }.to raise_error(Faraday::ConnectionFailed)
- end
-
- context 'it has already failed twice' do
- before do
- allow(job).to receive(:executions).and_return 2
- end
-
- it 'logs an event' do
- expect { perform }.to_not raise_error
-
- expect(job_analytics).to have_logged_event(
- :risc_security_event_pushed,
- risc_event_payload.merge(
- error: 'execution expired',
- transport: 'async',
- ),
- )
- end
- end
- end
end
context 'rate limiting' do
@@ -267,9 +189,18 @@
end
end
- context 'when performed inline' do
- it 'logs an event on limit hit' do
+ it 'raises on rate limit errors (and retries via ActiveJob)' do
+ expect { perform }.to raise_error(RedisRateLimiter::LimitError)
+ end
+
+ context 'it has already failed ten times' do
+ before do
+ allow(job).to receive(:executions).and_return 10
+ end
+
+ it 'logs an event' do
expect { perform }.to_not raise_error
+
expect(job_analytics).to have_logged_event(
:risc_security_event_pushed,
risc_event_payload.merge(
@@ -279,35 +210,6 @@
end
end
- context 'when performed in a worker' do
- before do
- allow(job).to receive(:queue_adapter).
- and_return(ActiveJob::QueueAdapters::GoodJobAdapter.new)
- end
-
- it 'raises on rate limit errors (and retries via ActiveJob)' do
- expect { perform }.to raise_error(RedisRateLimiter::LimitError)
- end
-
- context 'it has already failed ten times' do
- before do
- allow(job).to receive(:executions).and_return 10
- end
-
- it 'logs an event' do
- expect { perform }.to_not raise_error
-
- expect(job_analytics).to have_logged_event(
- :risc_security_event_pushed,
- risc_event_payload.merge(
- error: 'rate limit for push-notification-https://push.example.gov has maxed out',
- transport: 'async',
- ),
- )
- end
- end
- end
-
context 'when the rate limit is overridden' do
before do
allow(IdentityConfig.store).to receive(:risc_notifications_rate_limit_overrides).
@@ -324,7 +226,6 @@
risc_event_payload.merge(
success: true,
status: 200,
- transport: 'direct',
),
)
end
diff --git a/spec/lib/feature_management_spec.rb b/spec/lib/feature_management_spec.rb
index dea0fb9fc10..a1f35529f9c 100644
--- a/spec/lib/feature_management_spec.rb
+++ b/spec/lib/feature_management_spec.rb
@@ -376,57 +376,102 @@
end
end
- describe '.phone_recaptcha_enabled?' do
+ describe '.recaptcha_enabled?' do
let(:recaptcha_site_key) { '' }
let(:recaptcha_secret_key) { '' }
let(:recaptcha_enterprise_api_key) { '' }
let(:recaptcha_enterprise_project_id) { '' }
- let(:phone_recaptcha_score_threshold) { 0.0 }
- subject(:phone_recaptcha_enabled) { FeatureManagement.phone_recaptcha_enabled? }
+ subject(:recaptcha_enabled) { FeatureManagement.recaptcha_enabled? }
before do
allow(IdentityConfig.store).to receive(:recaptcha_site_key).
and_return(recaptcha_site_key)
allow(IdentityConfig.store).to receive(:recaptcha_secret_key).
and_return(recaptcha_secret_key)
- allow(IdentityConfig.store).to receive(:phone_recaptcha_score_threshold).
- and_return(phone_recaptcha_score_threshold)
allow(IdentityConfig.store).to receive(:recaptcha_enterprise_api_key).
and_return(recaptcha_enterprise_api_key)
allow(IdentityConfig.store).to receive(:recaptcha_enterprise_project_id).
and_return(recaptcha_enterprise_project_id)
end
- it { expect(phone_recaptcha_enabled).to eq(false) }
+ it { is_expected.to eq(false) }
context 'with configured recaptcha site key' do
let(:recaptcha_site_key) { 'key' }
- it { expect(phone_recaptcha_enabled).to eq(false) }
+ it { is_expected.to eq(false) }
- context 'with configured default success rate threshold greater than 0' do
- let(:phone_recaptcha_score_threshold) { 1.0 }
+ context 'with configured recaptcha secret key' do
+ let(:recaptcha_secret_key) { 'key' }
- it { expect(phone_recaptcha_enabled).to eq(false) }
+ it { is_expected.to eq(true) }
+ end
+
+ context 'with configured recaptcha enterprise api key' do
+ let(:recaptcha_enterprise_api_key) { 'key' }
+
+ it { is_expected.to eq(false) }
- context 'with configured recaptcha secret key' do
- let(:recaptcha_secret_key) { 'key' }
+ context 'with configured recaptcha enterprise project id' do
+ let(:recaptcha_enterprise_project_id) { 'project-id' }
- it { expect(phone_recaptcha_enabled).to eq(true) }
+ it { is_expected.to eq(true) }
end
+ end
+ end
+ end
- context 'with configured recaptcha enterprise api key' do
- let(:recaptcha_enterprise_api_key) { 'key' }
+ describe '.phone_recaptcha_enabled?' do
+ let(:recaptcha_enabled) { false }
+ let(:phone_recaptcha_score_threshold) { 0.0 }
- it { expect(phone_recaptcha_enabled).to eq(false) }
+ subject(:phone_recaptcha_enabled) { FeatureManagement.phone_recaptcha_enabled? }
- context 'with configured recaptcha enterprise project id' do
- let(:recaptcha_enterprise_project_id) { 'project-id' }
+ before do
+ allow(FeatureManagement).to receive(:recaptcha_enabled?).and_return(recaptcha_enabled)
+ allow(IdentityConfig.store).to receive(:phone_recaptcha_score_threshold).
+ and_return(phone_recaptcha_score_threshold)
+ end
- it { expect(phone_recaptcha_enabled).to eq(true) }
- end
- end
+ it { is_expected.to eq(false) }
+
+ context 'with configured default success rate threshold greater than 0' do
+ let(:phone_recaptcha_score_threshold) { 1.0 }
+
+ it { is_expected.to eq(false) }
+
+ context 'with recaptcha enabled' do
+ let(:recaptcha_enabled) { true }
+
+ it { is_expected.to eq(true) }
+ end
+ end
+ end
+
+ describe '.sign_in_recaptcha_enabled?' do
+ let(:recaptcha_enabled) { false }
+ let(:sign_in_recaptcha_score_threshold) { 0.0 }
+
+ subject(:sign_in_recaptcha_enabled) { FeatureManagement.sign_in_recaptcha_enabled? }
+
+ before do
+ allow(FeatureManagement).to receive(:recaptcha_enabled?).and_return(recaptcha_enabled)
+ allow(IdentityConfig.store).to receive(:sign_in_recaptcha_score_threshold).
+ and_return(sign_in_recaptcha_score_threshold)
+ end
+
+ it { is_expected.to eq(false) }
+
+ context 'with configured default success rate threshold greater than 0' do
+ let(:sign_in_recaptcha_score_threshold) { 1.0 }
+
+ it { is_expected.to eq(false) }
+
+ context 'with recaptcha enabled' do
+ let(:recaptcha_enabled) { true }
+
+ it { is_expected.to eq(true) }
end
end
end
diff --git a/spec/lib/reporting/cloudwatch_client_spec.rb b/spec/lib/reporting/cloudwatch_client_spec.rb
index 6a6f1c48e49..66986b08b2e 100644
--- a/spec/lib/reporting/cloudwatch_client_spec.rb
+++ b/spec/lib/reporting/cloudwatch_client_spec.rb
@@ -221,6 +221,14 @@ def stub_single_page
expect(results.size).to eq(999)
end
+
+ context 'query is missing a limit' do
+ let(:query) { 'fields @message | stats count(*) by bin(1d)' }
+
+ it 'raises' do
+ expect { fetch }.to raise_error(ArgumentError, /query is missing '| limit 10000'/)
+ end
+ end
end
context 'query is before Cloudwatch Insights Availability and AWS errors' do
diff --git a/spec/services/push_notification/http_push_spec.rb b/spec/services/push_notification/http_push_spec.rb
index 6e3e08b2c8b..6a854c044b4 100644
--- a/spec/services/push_notification/http_push_spec.rb
+++ b/spec/services/push_notification/http_push_spec.rb
@@ -22,87 +22,55 @@
)
end
let(:now) { Time.zone.now }
- let(:risc_notifications_active_job_enabled) { false }
let(:push_notifications_enabled) { true }
- let(:job_analytics) { FakeAnalytics.new }
- let(:risc_event_payload) do
- {
- client_id: sp_with_push_url.issuer,
- error: nil,
- event_type: event.event_type,
- status: nil,
- success: false,
- transport: 'direct',
- }
- end
subject(:http_push) { PushNotification::HttpPush.new(event, now: now) }
before do
- allow(IdentityConfig.store).to receive(:risc_notifications_active_job_enabled).
- and_return(risc_notifications_active_job_enabled)
+ ActiveJob::Base.queue_adapter = :test
allow(Identity::Hostdata).to receive(:env).and_return('dev')
allow(IdentityConfig.store).to receive(:push_notifications_enabled).
and_return(push_notifications_enabled)
- allow(Analytics).to receive(:new).and_return(job_analytics)
end
describe '#deliver' do
subject(:deliver) { http_push.deliver }
- context 'when push_notifications_enabled is disabled' do
- let(:push_notifications_enabled) { false }
-
- it 'does not deliver any notifications' do
- expect(http_push).to_not receive(:deliver_one)
-
- deliver
- end
+ it 'enqueues a background job to deliver a notification' do
+ expect { deliver }.to have_enqueued_job(RiscDeliveryJob).once
end
- context 'when risc_notifications_active_job_enabled is enabled' do
- let(:risc_notifications_active_job_enabled) { true }
+ it 'enqueues a background job with the correct arguments' do
+ expect { deliver }.to have_enqueued_job(RiscDeliveryJob).with { |args|
+ expect(args[:push_notification_url]).to eq sp_with_push_url.push_notification_url
+ expect(args[:event_type]).to eq event.event_type
+ expect(args[:issuer]).to eq sp_with_push_url.issuer
+
+ jwt_payload, headers = JWT.decode(
+ args[:jwt],
+ AppArtifacts.store.oidc_public_key,
+ true,
+ algorithm: 'RS256',
+ kid: JWT::JWK.new(AppArtifacts.store.oidc_private_key).kid,
+ )
- it 'delivers a notification via background job' do
- expect(RiscDeliveryJob).to receive(:perform_later)
+ expect(headers['typ']).to eq('secevent+jwt')
+ expect(headers['kid']).to eq(JWT::JWK.new(AppArtifacts.store.oidc_private_key).kid)
- deliver
- end
+ expect(jwt_payload['iss']).to eq(root_url)
+ expect(jwt_payload['iat']).to eq(now.to_i)
+ expect(jwt_payload['exp']).to eq((now + 12.hours).to_i)
+ expect(jwt_payload['aud']).to eq(sp_with_push_url.push_notification_url)
+ expect(jwt_payload['events']).to eq(event.event_type => event.payload.as_json)
+ }
end
- it 'makes an HTTP post to service providers with a push_notification_url' do
- stub_request(:post, sp_with_push_url.push_notification_url).
- with do |request|
- expect(request.headers['Content-Type']).to eq('application/secevent+jwt')
- expect(request.headers['Accept']).to eq('application/json')
-
- payload, headers = JWT.decode(
- request.body,
- AppArtifacts.store.oidc_public_key,
- true,
- algorithm: 'RS256',
- kid: JWT::JWK.new(AppArtifacts.store.oidc_private_key).kid,
- )
+ context 'when push_notifications_enabled is false' do
+ let(:push_notifications_enabled) { false }
- expect(headers['typ']).to eq('secevent+jwt')
- expect(headers['kid']).to eq(JWT::JWK.new(AppArtifacts.store.oidc_private_key).kid)
-
- expect(payload['iss']).to eq(root_url)
- expect(payload['iat']).to eq(now.to_i)
- expect(payload['exp']).to eq((now + 12.hours).to_i)
- expect(payload['aud']).to eq(sp_with_push_url.push_notification_url)
- expect(payload['events']).to eq(event.event_type => event.payload.as_json)
- end
-
- deliver
-
- expect(job_analytics).to have_logged_event(
- :risc_security_event_pushed,
- risc_event_payload.merge(
- status: 200,
- success: true,
- ),
- )
+ it 'does not enqueue a RISC notification' do
+ expect { deliver }.not_to have_enqueued_job(RiscDeliveryJob)
+ end
end
context 'with an event that sends agency-specific iss_sub' do
@@ -111,97 +79,35 @@
let(:agency_uuid) { AgencyIdentityLinker.new(sp_with_push_url_identity).link_identity.uuid }
it 'sends the agency-specific uuid' do
- stub_request(:post, sp_with_push_url.push_notification_url).
- with do |request|
- payload, _headers = JWT.decode(
- request.body,
- AppArtifacts.store.oidc_public_key,
- true,
- algorithm: 'RS256',
- )
-
- expect(payload['events'][event.event_type]['subject']['sub']).to eq(agency_uuid)
- end
-
- deliver
- end
- end
-
- context 'with a timeout when posting to one url' do
- let(:third_sp) { create(:service_provider, active: true, push_notification_url: 'http://sp.url/push') }
-
- before do
- IdentityLinker.new(user, third_sp).link_identity
-
- stub_request(:post, sp_with_push_url.push_notification_url).to_timeout
- stub_request(:post, third_sp.push_notification_url).to_return(status: 200)
- end
-
- it 'still posts to the others' do
- deliver
-
- expect(WebMock).to have_requested(:post, third_sp.push_notification_url)
- end
-
- it 'logs both events' do
- deliver
-
- expect(job_analytics).to have_logged_event(
- :risc_security_event_pushed,
- risc_event_payload.merge(
- error: 'execution expired',
- ),
- )
- expect(job_analytics).to have_logged_event(
- :risc_security_event_pushed,
- risc_event_payload.merge(
- client_id: third_sp.issuer,
- status: 200,
- success: true,
- ),
- )
- end
- end
-
- context 'with a non-200 response from a push notification url' do
- before do
- stub_request(:post, sp_with_push_url.push_notification_url).
- to_return(status: 500)
- end
-
- it 'logs an event' do
- deliver
-
- expect(job_analytics).to have_logged_event(
- :risc_security_event_pushed,
- risc_event_payload.merge(
- error: 'http_push_error',
- status: 500,
- ),
- )
+ expect { deliver }.to have_enqueued_job(RiscDeliveryJob).with { |args|
+ jwt_payload, _headers = JWT.decode(
+ args[:jwt],
+ AppArtifacts.store.oidc_public_key,
+ true,
+ algorithm: 'RS256',
+ kid: JWT::JWK.new(AppArtifacts.store.oidc_private_key).kid,
+ )
+ expect(jwt_payload['events'][event.event_type]['subject']['sub']).to eq(agency_uuid)
+ }
end
end
context 'when a service provider is no longer active' do
before { sp_with_push_url.update!(active: false) }
- it 'does not notify that SP' do
- deliver
-
- expect(WebMock).not_to have_requested(:get, sp_with_push_url.push_notification_url)
+ it 'does not enqueue a RISC notification' do
+ expect { deliver }.not_to have_enqueued_job(RiscDeliveryJob)
end
end
- context 'when a user has revoked access to an SP' do
+ context 'when a user has revoked access to a service provider' do
before do
identity = user.identities.find_by(service_provider: sp_with_push_url.issuer)
RevokeServiceProviderConsent.new(identity).call
end
- it 'does not notify that SP' do
- deliver
-
- expect(WebMock).not_to have_requested(:get, sp_with_push_url.push_notification_url)
+ it 'does not enqueue a RISC notification' do
+ expect { deliver }.not_to have_enqueued_job(RiscDeliveryJob)
end
end
end
diff --git a/spec/views/accounts/show.html.erb_spec.rb b/spec/views/accounts/show.html.erb_spec.rb
index 1923dfb8e7e..0734dc6c0f5 100644
--- a/spec/views/accounts/show.html.erb_spec.rb
+++ b/spec/views/accounts/show.html.erb_spec.rb
@@ -182,4 +182,34 @@
)
end
end
+
+ describe 'email language' do
+ context 'without explicit user language preference' do
+ let(:user) { create(:user, :fully_registered, email_language: nil) }
+
+ before do
+ I18n.locale = :es
+ end
+
+ it 'renders email language with language of parts as English' do
+ # Ensure that non-English content in English page is annotated with language.
+ # See: https://www.w3.org/WAI/WCAG21/Understanding/language-of-parts
+ render
+
+ expect(rendered).to have_css('[lang=en]', text: t('account.email_language.name.en'))
+ end
+ end
+
+ context 'with user language preference' do
+ let(:user) { create(:user, :fully_registered, email_language: :es) }
+
+ it 'renders email language with language of parts as that language' do
+ # Ensure that non-English content in English page is annotated with language.
+ # See: https://www.w3.org/WAI/WCAG21/Understanding/language-of-parts
+ render
+
+ expect(rendered).to have_css('[lang=es]', text: t('account.email_language.name.es'))
+ end
+ end
+ end
end
diff --git a/spec/views/devise/sessions/new.html.erb_spec.rb b/spec/views/devise/sessions/new.html.erb_spec.rb
index 28a896f2d89..6bfa22d06a5 100644
--- a/spec/views/devise/sessions/new.html.erb_spec.rb
+++ b/spec/views/devise/sessions/new.html.erb_spec.rb
@@ -138,7 +138,10 @@
it 'does not have an sp alert for service providers without alert messages' do
render
- expect(rendered).to_not have_selector('.usa-alert')
+ expect(rendered).to_not have_selector(
+ '.usa-alert',
+ text: 'custom sign in help text for Awesome Application!',
+ )
end
end
end
@@ -204,4 +207,45 @@
end
end
end
+
+ describe 'submit button' do
+ let(:sign_in_recaptcha_enabled) { false }
+ let(:recaptcha_mock_validator) { false }
+
+ subject(:rendered) { render }
+
+ before do
+ allow(FeatureManagement).to receive(:sign_in_recaptcha_enabled?).
+ and_return(sign_in_recaptcha_enabled)
+ allow(IdentityConfig.store).to receive(:recaptcha_mock_validator).
+ and_return(recaptcha_mock_validator)
+ end
+
+ context 'recaptcha at sign in is disabled' do
+ let(:sign_in_recaptcha_enabled) { false }
+
+ it 'renders default sign-in submit button' do
+ expect(rendered).to have_button(t('links.sign_in'))
+ expect(rendered).not_to have_css('lg-captcha-submit-button')
+ end
+
+ context 'recaptcha mock validator is enabled' do
+ let(:recaptcha_mock_validator) { true }
+
+ it 'renders captcha sign-in submit button' do
+ expect(rendered).to have_button(t('links.sign_in'))
+ expect(rendered).to have_css('lg-captcha-submit-button')
+ end
+ end
+ end
+
+ context 'recaptcha at sign in is enabled' do
+ let(:sign_in_recaptcha_enabled) { true }
+
+ it 'renders captcha sign-in submit button' do
+ expect(rendered).to have_button(t('links.sign_in'))
+ expect(rendered).to have_css('lg-captcha-submit-button')
+ end
+ end
+ end
end
diff --git a/spec/views/layouts/base.html.erb_spec.rb b/spec/views/layouts/base.html.erb_spec.rb
new file mode 100644
index 00000000000..147eff67b07
--- /dev/null
+++ b/spec/views/layouts/base.html.erb_spec.rb
@@ -0,0 +1,13 @@
+require 'rails_helper'
+
+RSpec.describe 'layouts/base.html.erb' do
+ before do
+ view.title = 'Example'
+ end
+
+ it 'includes expected OpenGraph metadata' do
+ render
+
+ expect(rendered).to have_css('meta[name="og:site_name"][content~=""]', visible: false)
+ end
+end
diff --git a/yarn.lock b/yarn.lock
index 2c06bca13a3..24ae052d682 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1218,10 +1218,30 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
+"@jsonjoy.com/base64@^1.1.1":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@jsonjoy.com/base64/-/base64-1.1.2.tgz#cf8ea9dcb849b81c95f14fc0aaa151c6b54d2578"
+ integrity sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==
+
+"@jsonjoy.com/json-pack@^1.0.3":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz#ab59c642a2e5368e8bcfd815d817143d4f3035d0"
+ integrity sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==
+ dependencies:
+ "@jsonjoy.com/base64" "^1.1.1"
+ "@jsonjoy.com/util" "^1.1.2"
+ hyperdyperid "^1.2.0"
+ thingies "^1.20.0"
+
+"@jsonjoy.com/util@^1.1.2":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@jsonjoy.com/util/-/util-1.2.0.tgz#0fe9a92de72308c566ebcebe8b5a3f01d3149df2"
+ integrity sha512-4B8B+3vFsY4eo33DMKyJPlQ3sBMpPFUZK2dr3O3rXrOGKKbYG44J0XSFkDo1VOQiri5HFEhIeVvItjR2xcazmg==
+
"@leichtgewicht/ip-codec@^2.0.1":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b"
- integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz#4fc56c15c580b9adb7dc3c333a134e540b44bfb1"
+ integrity sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==
"@mswjs/cookies@^1.1.0":
version "1.1.0"
@@ -1477,9 +1497,9 @@
integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33":
- version "4.17.41"
- resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz#5077defa630c2e8d28aa9ffc2c01c157c305bef6"
- integrity sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==
+ version "4.19.5"
+ resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz#218064e321126fcf9048d1ca25dd2465da55d9c6"
+ integrity sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==
dependencies:
"@types/node" "*"
"@types/qs" "*"
@@ -1547,9 +1567,9 @@
"@types/sizzle" "*"
"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
- version "7.0.13"
- resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85"
- integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==
+ version "7.0.15"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
+ integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
"@types/json5@^0.0.29":
version "0.0.29"
@@ -1581,9 +1601,9 @@
"@types/node" "*"
"@types/node@*", "@types/node@^20.11.16", "@types/node@^20.2.5":
- version "20.11.19"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.19.tgz#b466de054e9cb5b3831bee38938de64ac7f81195"
- integrity sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==
+ version "20.14.7"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.7.tgz#342cada27f97509eb8eb2dbc003edf21ce8ab5a8"
+ integrity sha512-uTr2m2IbJJucF3KUxgnGOZvYbN0QgkGyWxG6973HCpMYFy2KfcgYuIwkJQMQkt1VbBMlvWRbpshFTLxnxCZjKQ==
dependencies:
undici-types "~5.26.4"
@@ -1593,9 +1613,9 @@
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
"@types/qs@*":
- version "6.9.11"
- resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.11.tgz#208d8a30bc507bd82e03ada29e4732ea46a6bbda"
- integrity sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==
+ version "6.9.15"
+ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.15.tgz#adde8a060ec9c305a82de1babc1056e73bd64dce"
+ integrity sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==
"@types/range-parser@*":
version "1.2.7"
@@ -1656,9 +1676,9 @@
"@types/express" "*"
"@types/serve-static@*", "@types/serve-static@^1.15.5":
- version "1.15.6"
- resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.6.tgz#9cacd9b0b0fc5183ff0d5b27c1b1cad398113673"
- integrity sha512-xkChxykiNb1X2YBevPIhQhNU9m9M7h9e2gDsmePAP2kNqhOvpKOrZWOCzq2ERQqfNFzlzHG2bdM0u3z5x+gQgg==
+ version "1.15.7"
+ resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714"
+ integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==
dependencies:
"@types/http-errors" "*"
"@types/node" "*"
@@ -2031,6 +2051,11 @@
resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
+"@yarnpkg/lockfile@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31"
+ integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==
+
abab@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
@@ -2096,14 +2121,14 @@ ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5:
uri-js "^4.2.2"
ajv@^8.0.0, ajv@^8.0.1, ajv@^8.9.0:
- version "8.12.0"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1"
- integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==
+ version "8.16.0"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.16.0.tgz#22e2a92b94f005f7e0f9c9d39652ef0b8f6f0cb4"
+ integrity sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==
dependencies:
- fast-deep-equal "^3.1.1"
+ fast-deep-equal "^3.1.3"
json-schema-traverse "^1.0.0"
require-from-string "^2.0.2"
- uri-js "^4.2.2"
+ uri-js "^4.4.1"
ansi-colors@4.1.1:
version "4.1.1"
@@ -2249,7 +2274,7 @@ astral-regex@^2.0.0:
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
- integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
+ integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
available-typed-arrays@^1.0.5:
version "1.0.5"
@@ -2391,7 +2416,7 @@ brace-expansion@^2.0.1:
dependencies:
balanced-match "^1.0.0"
-braces@^3.0.2, braces@^3.0.3, braces@~3.0.2:
+braces@^3.0.3, braces@~3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
@@ -2447,13 +2472,16 @@ bytes@3.1.2:
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
-call-bind@^1.0.0, call-bind@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
- integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
+call-bind@^1.0.2, call-bind@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
+ integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
dependencies:
- function-bind "^1.1.1"
- get-intrinsic "^1.0.2"
+ es-define-property "^1.0.0"
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.4"
+ set-function-length "^1.2.1"
callsites@^3.0.0:
version "3.1.0"
@@ -2879,7 +2907,14 @@ debug@2.6.9:
dependencies:
ms "2.0.0"
-debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
+debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
+ version "4.3.5"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e"
+ integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==
+ dependencies:
+ ms "2.1.2"
+
+debug@4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@@ -2958,6 +2993,15 @@ default-gateway@^6.0.3:
dependencies:
execa "^5.0.0"
+define-data-property@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
+ integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
+ dependencies:
+ es-define-property "^1.0.0"
+ es-errors "^1.3.0"
+ gopd "^1.0.1"
+
define-lazy-prop@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f"
@@ -2974,7 +3018,7 @@ define-properties@^1.1.3, define-properties@^1.1.4:
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
- integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
+ integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
depd@2.0.0:
version "2.0.0"
@@ -3191,6 +3235,18 @@ es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.5, es-abstract@^1.20
unbox-primitive "^1.0.2"
which-typed-array "^1.1.9"
+es-define-property@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
+ integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
+ dependencies:
+ get-intrinsic "^1.2.4"
+
+es-errors@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
+ integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
+
es-module-lexer@^1.2.1:
version "1.5.0"
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.0.tgz#4878fee3789ad99e065f975fdd3c645529ff0236"
@@ -3741,9 +3797,9 @@ for-each@^0.3.3:
is-callable "^1.1.3"
foreground-child@^3.1.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d"
- integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.2.1.tgz#767004ccf3a5b30df39bed90718bab43fe0a59f7"
+ integrity sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==
dependencies:
cross-spawn "^7.0.0"
signal-exit "^4.0.1"
@@ -3787,7 +3843,7 @@ fsevents@~2.3.2:
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
-function-bind@^1.1.1, function-bind@^1.1.2:
+function-bind@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
@@ -3822,14 +3878,16 @@ get-func-name@^2.0.0, get-func-name@^2.0.2:
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41"
integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==
-get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f"
- integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==
+get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.4:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
+ integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
dependencies:
- function-bind "^1.1.1"
- has "^1.0.3"
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+ has-proto "^1.0.1"
has-symbols "^1.0.3"
+ hasown "^2.0.0"
get-stream@^6.0.0, get-stream@^6.0.1:
version "6.0.1"
@@ -3875,15 +3933,16 @@ glob@8.1.0:
once "^1.3.0"
glob@^10.3.7:
- version "10.3.10"
- resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b"
- integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==
+ version "10.4.2"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.2.tgz#bed6b95dade5c1f80b4434daced233aee76160e5"
+ integrity sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==
dependencies:
foreground-child "^3.1.0"
- jackspeak "^2.3.5"
- minimatch "^9.0.1"
- minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
- path-scurry "^1.10.1"
+ jackspeak "^3.1.2"
+ minimatch "^9.0.4"
+ minipass "^7.1.2"
+ package-json-from-dist "^1.0.0"
+ path-scurry "^1.11.1"
glob@^7.1.3, glob@^7.2.0:
version "7.2.3"
@@ -3991,12 +4050,12 @@ has-flag@^4.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-has-property-descriptors@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861"
- integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==
+has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
+ integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
dependencies:
- get-intrinsic "^1.1.1"
+ es-define-property "^1.0.0"
has-proto@^1.0.1:
version "1.0.1"
@@ -4016,11 +4075,9 @@ has-tostringtag@^1.0.0:
has-symbols "^1.0.2"
has@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
- integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
- dependencies:
- function-bind "^1.1.1"
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6"
+ integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==
hasown@^2.0.0:
version "2.0.0"
@@ -4144,6 +4201,11 @@ human-signals@^4.3.0:
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2"
integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==
+hyperdyperid@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/hyperdyperid/-/hyperdyperid-1.2.0.tgz#59668d323ada92228d2a869d3e474d5a33b69e6b"
+ integrity sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==
+
iconv-lite@0.4.24:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@@ -4237,9 +4299,9 @@ ipaddr.js@1.9.1:
integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
ipaddr.js@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.1.0.tgz#2119bc447ff8c257753b196fc5f1ce08a4cdf39f"
- integrity sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8"
+ integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==
is-array-buffer@^3.0.1, is-array-buffer@^3.0.2:
version "3.0.2"
@@ -4478,17 +4540,17 @@ isarray@~1.0.0:
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
- integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+ integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
isobject@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
-jackspeak@^2.3.5:
- version "2.3.6"
- resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8"
- integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==
+jackspeak@^3.1.2:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.0.tgz#a75763ff36ad778ede6a156d8ee8b124de445b4a"
+ integrity sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==
dependencies:
"@isaacs/cliui" "^8.0.2"
optionalDependencies:
@@ -4639,9 +4701,9 @@ language-tags@^1.0.5:
language-subtag-registry "~0.3.2"
launch-editor@^2.6.1:
- version "2.6.1"
- resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.1.tgz#f259c9ef95cbc9425620bbbd14b468fcdb4ffe3c"
- integrity sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.8.0.tgz#7255d90bdba414448e2138faa770a74f28451305"
+ integrity sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==
dependencies:
picocolors "^1.0.0"
shell-quote "^1.8.1"
@@ -4812,6 +4874,11 @@ loupe@^2.3.6:
dependencies:
get-func-name "^2.0.0"
+lru-cache@^10.2.0:
+ version "10.2.2"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878"
+ integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==
+
lru-cache@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
@@ -4819,18 +4886,6 @@ lru-cache@^5.1.1:
dependencies:
yallist "^3.0.2"
-lru-cache@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
- integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
- dependencies:
- yallist "^4.0.0"
-
-"lru-cache@^9.1.1 || ^10.0.0":
- version "10.2.0"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3"
- integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==
-
lz-string@^1.4.4:
version "1.4.4"
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"
@@ -4877,10 +4932,13 @@ media-typer@0.3.0:
integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
memfs@^4.6.0:
- version "4.8.1"
- resolved "https://registry.yarnpkg.com/memfs/-/memfs-4.8.1.tgz#1e02c15c4397212a9a1b037fa4324c6f7dd45b47"
- integrity sha512-7q/AdPzf2WpwPlPL4v1kE2KsJsHl7EF4+hAeVzlyanr2+YnR21NVn9mDqo+7DEaKDRsQy8nvxPlKH4WqMtiO0w==
+ version "4.9.3"
+ resolved "https://registry.yarnpkg.com/memfs/-/memfs-4.9.3.tgz#41a3218065fe3911d9eba836250c8f4e43f816bc"
+ integrity sha512-bsYSSnirtYTWi1+OPMFb0M048evMKyUYe0EbtuGQgq6BVQM1g1W8/KIUJCCvjgI/El0j6Q4WsmMiBwLUBSw8LA==
dependencies:
+ "@jsonjoy.com/json-pack" "^1.0.3"
+ "@jsonjoy.com/util" "^1.1.2"
+ tree-dump "^1.0.1"
tslib "^2.0.0"
meow@^13.1.0:
@@ -4908,15 +4966,7 @@ methods@~1.1.2:
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
-micromatch@^4.0.2, micromatch@^4.0.5:
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
- integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
- dependencies:
- braces "^3.0.2"
- picomatch "^2.3.1"
-
-micromatch@^4.0.4:
+micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5:
version "4.0.7"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5"
integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==
@@ -4977,10 +5027,10 @@ minimatch@^5.0.1:
dependencies:
brace-expansion "^2.0.1"
-minimatch@^9.0.1:
- version "9.0.3"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825"
- integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
+minimatch@^9.0.4:
+ version "9.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51"
+ integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==
dependencies:
brace-expansion "^2.0.1"
@@ -4989,10 +5039,10 @@ minimist@1.2.6, minimist@^1.2.0, minimist@^1.2.6:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
-"minipass@^5.0.0 || ^6.0.2 || ^7.0.0":
- version "7.0.4"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c"
- integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==
+"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2:
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707"
+ integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==
mocha@^10.0.0:
version "10.4.0"
@@ -5149,19 +5199,19 @@ nth-check@^2.0.1:
boolbase "^1.0.0"
nwsapi@^2.2.4:
- version "2.2.5"
- resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.5.tgz#a52744c61b3889dd44b0a158687add39b8d935e2"
- integrity sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ==
+ version "2.2.10"
+ resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.10.tgz#0b77a68e21a0b483db70b11fad055906e867cda8"
+ integrity sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==
object-assign@4.1.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
-object-inspect@^1.12.3, object-inspect@^1.9.0:
- version "1.12.3"
- resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9"
- integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==
+object-inspect@^1.12.3, object-inspect@^1.13.1:
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
+ integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
object-keys@^1.1.1:
version "1.1.1"
@@ -5337,6 +5387,11 @@ p-try@^2.0.0:
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+package-json-from-dist@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00"
+ integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==
+
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
@@ -5396,12 +5451,12 @@ path-parse@^1.0.6, path-parse@^1.0.7:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
-path-scurry@^1.10.1:
- version "1.10.1"
- resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698"
- integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==
+path-scurry@^1.11.1:
+ version "1.11.1"
+ resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2"
+ integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==
dependencies:
- lru-cache "^9.1.1 || ^10.0.0"
+ lru-cache "^10.2.0"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
path-to-regexp@0.1.7:
@@ -5432,9 +5487,9 @@ pathval@^1.1.1:
integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==
picocolors@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
- integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1"
+ integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
version "2.3.1"
@@ -5568,14 +5623,14 @@ proxy-addr@~2.0.7:
ipaddr.js "1.9.1"
psl@^1.1.33:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
- integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
+ integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
- integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
+ integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
qs@6.11.0:
version "6.11.0"
@@ -5795,7 +5850,7 @@ require-from-string@^2.0.2:
requires-port@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
- integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+ integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==
resolve-cwd@^3.0.0:
version "3.0.0"
@@ -5854,9 +5909,9 @@ rimraf@^3.0.2:
glob "^7.1.3"
rimraf@^5.0.5:
- version "5.0.5"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.5.tgz#9be65d2d6e683447d2e9013da2bf451139a61ccf"
- integrity sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==
+ version "5.0.7"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.7.tgz#27bddf202e7d89cb2e0381656380d1734a854a74"
+ integrity sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==
dependencies:
glob "^10.3.7"
@@ -6086,12 +6141,10 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0, semver@^6.3.1:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
-semver@^7.3.7, semver@^7.5.4:
- version "7.5.4"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
- integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
- dependencies:
- lru-cache "^6.0.0"
+semver@^7.3.7, semver@^7.5.0, semver@^7.5.4:
+ version "7.6.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13"
+ integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==
send@0.18.0:
version "0.18.0"
@@ -6149,6 +6202,18 @@ serve-static@1.15.0:
parseurl "~1.3.3"
send "0.18.0"
+set-function-length@^1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
+ integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
+ dependencies:
+ define-data-property "^1.1.4"
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.4"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.2"
+
setprototypeof@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
@@ -6184,13 +6249,14 @@ shell-quote@^1.8.1:
integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==
side-channel@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
- integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
+ integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
dependencies:
- call-bind "^1.0.0"
- get-intrinsic "^1.0.2"
- object-inspect "^1.9.0"
+ call-bind "^1.0.7"
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.4"
+ object-inspect "^1.13.1"
signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
version "3.0.7"
@@ -6660,6 +6726,11 @@ text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+thingies@^1.20.0:
+ version "1.21.0"
+ resolved "https://registry.yarnpkg.com/thingies/-/thingies-1.21.0.tgz#e80fbe58fd6fdaaab8fad9b67bd0a5c943c445c1"
+ integrity sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==
+
thunky@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
@@ -6688,9 +6759,9 @@ toidentifier@1.0.1:
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
tough-cookie@^4.1.2:
- version "4.1.3"
- resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf"
- integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==
+ version "4.1.4"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36"
+ integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==
dependencies:
psl "^1.1.33"
punycode "^2.1.1"
@@ -6704,6 +6775,11 @@ tr46@^4.1.1:
dependencies:
punycode "^2.3.0"
+tree-dump@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/tree-dump/-/tree-dump-1.0.1.tgz#b448758da7495580e6b7830d6b7834fca4c45b96"
+ integrity sha512-WCkcRBVPSlHHq1dc/px9iOfqklvzCbdRwvlNfxGZsrHqf6aZttfPrd7DJTt6oR10dwUfpFFQeVTkPbBIZxX/YA==
+
tree-kill@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
@@ -6730,9 +6806,9 @@ tslib@^1.8.1:
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.0.0, tslib@^2.1.0, tslib@^2.5.0, tslib@^2.6.0:
- version "2.6.2"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
- integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
+ version "2.6.3"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0"
+ integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==
tsutils@^3.21.0:
version "3.21.0"
@@ -6851,7 +6927,7 @@ update-browserslist-db@^1.0.13:
escalade "^3.1.1"
picocolors "^1.0.0"
-uri-js@^4.2.2:
+uri-js@^4.2.2, uri-js@^4.4.1:
version "4.4.1"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
@@ -7185,9 +7261,9 @@ write-file-atomic@^5.0.1:
signal-exit "^4.0.1"
ws@^8.13.0, ws@^8.16.0:
- version "8.16.0"
- resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4"
- integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==
+ version "8.17.1"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b"
+ integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==
xml-name-validator@^4.0.0:
version "4.0.0"
@@ -7209,11 +7285,6 @@ yallist@^3.0.2:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
-yallist@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
- integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
-
yaml@^2.3.4:
version "2.3.4"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2"
@@ -7270,6 +7341,16 @@ yargs@^17.7.2:
y18n "^5.0.5"
yargs-parser "^21.1.1"
+yarn-deduplicate@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/yarn-deduplicate/-/yarn-deduplicate-6.0.2.tgz#63498d2d4c3a8567e992a994ce0ab51aa5681f2e"
+ integrity sha512-Efx4XEj82BgbRJe5gvQbZmEO7pU5DgHgxohYZp98/+GwPqdU90RXtzvHirb7hGlde0sQqk5G3J3Woyjai8hVqA==
+ dependencies:
+ "@yarnpkg/lockfile" "^1.1.0"
+ commander "^10.0.1"
+ semver "^7.5.0"
+ tslib "^2.5.0"
+
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
| | | |