diff --git a/app/assets/javascripts/behaviors/markdown/render_math.js b/app/assets/javascripts/behaviors/markdown/render_math.js index 7525fc76d169b410c3c8928d211a6fe40df229a6..4cba3eccb45a644e0b25fd6429d184c5ca91ce47 100644 --- a/app/assets/javascripts/behaviors/markdown/render_math.js +++ b/app/assets/javascripts/behaviors/markdown/render_math.js @@ -22,6 +22,31 @@ const waitForReflow = (fn) => { window.requestIdleCallback(fn); }; +const katexOptions = (el) => { + const options = { + displayMode: el.dataset.mathStyle === 'display', + throwOnError: true, + trust: (context) => + // this config option restores the KaTeX pre-v0.11.0 + // behavior of allowing certain commands and protocols + // eslint-disable-next-line @gitlab/require-i18n-strings + ['\\url', '\\href'].includes(context.command) && + ['http', 'https', 'mailto', '_relative'].includes(context.protocol), + }; + + if (gon.math_rendering_limits_enabled) { + options.maxSize = MAX_USER_SPECIFIED_EMS; + // See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111107 for + // reasoning behind this value + options.maxExpand = MAX_MACRO_EXPANSIONS; + } else { + // eslint-disable-next-line @gitlab/require-i18n-strings + options.maxExpand = 'Infinity'; + } + + return options; +}; + /** * Renders math blocks sequentially while protecting against DoS attacks. Math blocks have a maximum character limit of MAX_MATH_CHARS. If rendering math takes longer than MAX_RENDER_TIME_MS, all subsequent math blocks are skipped and an error message is shown. */ @@ -60,7 +85,10 @@ class SafeMathRenderer { } const el = chosenEl || this.queue.shift(); - const forceRender = Boolean(chosenEl) || unrestrictedPages.includes(this.pageName); + const forceRender = + Boolean(chosenEl) || + unrestrictedPages.includes(this.pageName) || + !gon.math_rendering_limits_enabled; const text = el.textContent; el.removeAttribute('style'); @@ -128,20 +156,7 @@ class SafeMathRenderer { } // eslint-disable-next-line no-unsanitized/property - displayContainer.innerHTML = this.katex.renderToString(text, { - displayMode: el.dataset.mathStyle === 'display', - throwOnError: true, - maxSize: MAX_USER_SPECIFIED_EMS, - // See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111107 for - // reasoning behind this value - maxExpand: MAX_MACRO_EXPANSIONS, - trust: (context) => - // this config option restores the KaTeX pre-v0.11.0 - // behavior of allowing certain commands and protocols - // eslint-disable-next-line @gitlab/require-i18n-strings - ['\\url', '\\href'].includes(context.command) && - ['http', 'https', 'mailto', '_relative'].includes(context.protocol), - }); + displayContainer.innerHTML = this.katex.renderToString(text, katexOptions(el)); } catch (e) { // Don't show a flash for now because it would override an existing flash message if (e.message.match(/Too many expansions/)) { diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 0fd232a60888988ce470aa9848e1e9c0bcf36ce8..89e77bde32529b4eedd40f38bf1cd7f7845ac498 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -314,6 +314,7 @@ def visible_attributes :jira_connect_application_key, :jira_connect_public_key_storage_enabled, :jira_connect_proxy_url, + :math_rendering_limits_enabled, :max_artifacts_size, :max_attachment_size, :max_export_size, diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 4e3c2028c546ca42eb7ad486b7548a069a96c892..4da3f0479360bd61d3e0133b44b5d65b266c44b8 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -830,6 +830,9 @@ def self.kroki_formats_attributes allow_nil: false, inclusion: { in: [true, false], message: N_('must be a boolean value') } + validates :math_rendering_limits_enabled, + inclusion: { in: [true, false], message: N_('must be a boolean value') } + before_validation :ensure_uuid! before_validation :coerce_repository_storages_weighted, if: :repository_storages_weighted_changed? before_validation :normalize_default_branch_name diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb index 18f1a53f8aaea763a01d51ce9fe1e31fd687c18c..e6d65a8b70598ac733a2b71ebaedac600d908860 100644 --- a/app/models/application_setting_implementation.rb +++ b/app/models/application_setting_implementation.rb @@ -118,6 +118,7 @@ def defaults # rubocop:disable Metrics/AbcSize login_recaptcha_protection_enabled: false, mailgun_signing_key: nil, mailgun_events_enabled: false, + math_rendering_limits_enabled: true, max_artifacts_size: Settings.artifacts['max_size'], max_attachment_size: Settings.gitlab['max_attachment_size'], max_export_size: 0, diff --git a/db/migrate/20230929151451_add_math_rendering_limits_enabled.rb b/db/migrate/20230929151451_add_math_rendering_limits_enabled.rb new file mode 100644 index 0000000000000000000000000000000000000000..d52019c41ed7dd8b70cd21ae0a9b6ebb087b68a0 --- /dev/null +++ b/db/migrate/20230929151451_add_math_rendering_limits_enabled.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddMathRenderingLimitsEnabled < Gitlab::Database::Migration[2.1] + enable_lock_retries! + + def change + add_column :application_settings, :math_rendering_limits_enabled, :boolean, default: true, null: false + end +end diff --git a/db/schema_migrations/20230929151451 b/db/schema_migrations/20230929151451 new file mode 100644 index 0000000000000000000000000000000000000000..fbc9c908c9160326afc9b46b1754cbe19dc4cb38 --- /dev/null +++ b/db/schema_migrations/20230929151451 @@ -0,0 +1 @@ +414442e7daf9e23bb33c8471f30c6465bcef6a19051d609888f5bbf88bb5306e \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 90dafad1dc7f785ae6caa5a420c5358ae078012e..78864f3810eca3d68220cd155842eb494c038145 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -11854,6 +11854,7 @@ CREATE TABLE application_settings ( encrypted_vertex_ai_access_token bytea, encrypted_vertex_ai_access_token_iv bytea, project_jobs_api_rate_limit integer DEFAULT 600 NOT NULL, + math_rendering_limits_enabled boolean DEFAULT true NOT NULL, CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)), CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)), diff --git a/doc/administration/instance_limits.md b/doc/administration/instance_limits.md index 377a3dba6c960469280f450480426c549471a495..8f03a2224ecc01b3ffb07236e63b9c315f6f8734 100644 --- a/doc/administration/instance_limits.md +++ b/doc/administration/instance_limits.md @@ -990,6 +990,31 @@ You can configure this limit for self-managed installations when you [enable Elasticsearch](../integration/advanced_search/elasticsearch.md#enable-advanced-search). Set the limit to `0` to disable it. +## Math rendering limits + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132939) in GitLab 16.5. + +GitLab imposes default limits when rendering math in Markdown fields. These limits provide better security and performance. + +The limits for issues, merge requests, wikis, and repositories: + +- Maximum number of nodes rendered: `50`. +- Maximum number of macro expansions: `1000`. +- Maximum user-specified size in em: `20`. + +The limits for issues and merge requests: + +- Maximum number of characters in a math block: `1000`. +- Maximum rendering time: `2000 ms`. + +You can disable these limits when running in a self-managed instance and you trust the user input. + +Use the [GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session): + +```ruby +ApplicationSetting.update(math_rendering_limits_enabled: false) +``` + ## Wiki limits - [Wiki page content size limit](wikis/index.md#wiki-page-content-size-limit). diff --git a/lib/banzai/filter/math_filter.rb b/lib/banzai/filter/math_filter.rb index e568f51652fef3cee31a41b201291fd54d2468f1..3161e030194e83ad1cad71c782fca8358c9daa22 100644 --- a/lib/banzai/filter/math_filter.rb +++ b/lib/banzai/filter/math_filter.rb @@ -47,7 +47,7 @@ def call # Add necessary classes to any existing math blocks def process_existing doc.xpath(XPATH_INLINE_CODE).each do |code| - break if @nodes_count >= RENDER_NODES_LIMIT + break if render_nodes_limit_reached?(@nodes_count) code[:class] = MATH_CLASSES @@ -58,7 +58,7 @@ def process_existing # Corresponds to the "$`...`$" syntax def process_dollar_backtick_inline doc.xpath(XPATH_CODE).each do |code| - break if @nodes_count >= RENDER_NODES_LIMIT + break if render_nodes_limit_reached?(@nodes_count) closing = code.next opening = code.previous @@ -87,6 +87,16 @@ def process_math_codeblock pre_node[:class] = TAG_CLASS end end + + def settings + Gitlab::CurrentSettings.current_application_settings + end + + def render_nodes_limit_reached?(count) + return false unless settings.math_rendering_limits_enabled? + + count >= RENDER_NODES_LIMIT + end end end end diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb index a7f8b93ee102dac5aa10247e6ba39e235e6b41cd..168f3aa4c597cd7982bd1172711e1951c0d5638a 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -7,15 +7,16 @@ module GonHelper include WebpackHelper def add_gon_variables - gon.api_version = 'v4' - gon.default_avatar_url = default_avatar_url - gon.max_file_size = Gitlab::CurrentSettings.max_attachment_size - gon.asset_host = ActionController::Base.asset_host - gon.webpack_public_path = webpack_public_path - gon.relative_url_root = Gitlab.config.gitlab.relative_url_root - gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class - gon.markdown_surround_selection = current_user&.markdown_surround_selection - gon.markdown_automatic_lists = current_user&.markdown_automatic_lists + gon.api_version = 'v4' + gon.default_avatar_url = default_avatar_url + gon.max_file_size = Gitlab::CurrentSettings.max_attachment_size + gon.asset_host = ActionController::Base.asset_host + gon.webpack_public_path = webpack_public_path + gon.relative_url_root = Gitlab.config.gitlab.relative_url_root + gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class + gon.markdown_surround_selection = current_user&.markdown_surround_selection + gon.markdown_automatic_lists = current_user&.markdown_automatic_lists + gon.math_rendering_limits_enabled = Gitlab::CurrentSettings.math_rendering_limits_enabled add_browsersdk_tracking diff --git a/spec/features/markdown/math_spec.rb b/spec/features/markdown/math_spec.rb index 0bc8f2146e9b6c79a5821a2b6409561a0df099fa..0d12aade80786640b13f75fb7d27f5577aa80058 100644 --- a/spec/features/markdown/math_spec.rb +++ b/spec/features/markdown/math_spec.rb @@ -48,47 +48,92 @@ end end - it 'renders lazy load button' do - description = <<~MATH - ```math - \Huge \sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} - ``` - MATH - - create_and_visit_issue_with_description(description) + describe 'applying limits on math rendering' do + let(:lazy_load_description) do + <<~MATH + ```math + \Huge \sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} + ``` + MATH + end - page.within '.description > .md' do - expect(page).to have_selector('.js-lazy-render-math-container', text: /math block exceeds 1000 characters/) + let(:excessive_expansion_description) do + <<~MATH + ```math + #{'\\mod e ' * 150} + ``` + MATH end - end - it 'allows many expansions', :js do - description = <<~MATH - ```math - #{'\\mod e ' * 100} - ``` - MATH + context 'when limits should be applied (default)' do + it 'renders lazy load button' do + create_and_visit_issue_with_description(lazy_load_description) - create_and_visit_issue_with_description(description) + page.within '.description > .md' do + expect(page).to have_selector('.js-lazy-render-math-container', text: /math block exceeds 1000 characters/) + end + end - page.within '.description > .md' do - expect(page).not_to have_selector('.katex-error') + it 'allows many expansions', :js do + description = <<~MATH + ```math + #{'\\mod e ' * 100} + ``` + MATH + + create_and_visit_issue_with_description(description) + + page.within '.description > .md' do + expect(page).not_to have_selector('.katex-error') + end + end + + it 'shows error message when too many expansions', :js do + create_and_visit_issue_with_description(excessive_expansion_description) + + page.within '.description > .md' do + click_button 'Display anyway' + + expect(page).to have_selector('.katex-error', text: /Too many expansions/) + end + end + + it 'renders without any limits on wiki page', :js do + wiki_page = build(:wiki_page, { container: project, content: lazy_load_description }) + wiki_page.create message: 'math test commit' # rubocop:disable Rails/SaveBang + wiki_page = project.wiki.find_page(wiki_page.slug) + + visit project_wiki_path(project, wiki_page) + + wait_for_requests + + page.within '.js-wiki-page-content' do + expect(page).not_to have_selector('.js-lazy-render-math') + end + end end - end - it 'shows error message when too many expansions', :js do - description = <<~MATH - ```math - #{'\\mod e ' * 150} - ``` - MATH + context 'when limits are disabled' do + before do + stub_application_setting(math_rendering_limits_enabled: false) + end - create_and_visit_issue_with_description(description) + it 'does not render lazy load button' do + create_and_visit_issue_with_description(lazy_load_description) - page.within '.description > .md' do - click_button 'Display anyway' + page.within '.description > .md' do + expect(page) + .not_to have_selector('.js-lazy-render-math-container', text: /math block exceeds 1000 characters/) + end + end - expect(page).to have_selector('.katex-error', text: /Too many expansions/) + it 'does not show error message when too many expansions', :js do + create_and_visit_issue_with_description(excessive_expansion_description) + + page.within '.description > .md' do + expect(page).not_to have_selector('.katex-error', text: /Too many expansions/) + end + end end end @@ -121,26 +166,6 @@ end end - it 'renders without any limits on wiki page', :js do - description = <<~MATH - ```math - \Huge \sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} - ``` - MATH - - wiki_page = build(:wiki_page, { container: project, content: description }) - wiki_page.create message: 'math test commit' # rubocop:disable Rails/SaveBang - wiki_page = project.wiki.find_page(wiki_page.slug) - - visit project_wiki_path(project, wiki_page) - - wait_for_requests - - page.within '.js-wiki-page-content' do - expect(page).not_to have_selector('.js-lazy-render-math') - end - end - it 'uses math-content-display for display math', :js do description = <<~MATH ```math diff --git a/spec/lib/banzai/filter/math_filter_spec.rb b/spec/lib/banzai/filter/math_filter_spec.rb index e4ebebc0fdebf5bf715058dc28ececa058a0df14..3fa0f9028e8c1576708279ed6e8f22c8be6aaffc 100644 --- a/spec/lib/banzai/filter/math_filter_spec.rb +++ b/spec/lib/banzai/filter/math_filter_spec.rb @@ -207,12 +207,21 @@ expect(doc.search('[data-math-style="display"]').count).to eq(1) end - it 'limits how many elements can be marked as math' do - stub_const('Banzai::Filter::MathFilter::RENDER_NODES_LIMIT', 2) + context 'when limiting how many elements can be marked as math' do + subject { pipeline_filter('$`2+2`$ + $3+3$ + $$4+4$$') } - doc = pipeline_filter('$`2+2`$ + $3+3$ + $$4+4$$') + it 'enforces limits by default' do + stub_const('Banzai::Filter::MathFilter::RENDER_NODES_LIMIT', 2) + + expect(subject.search('.js-render-math').count).to eq(2) + end - expect(doc.search('.js-render-math').count).to eq(2) + it 'does not limit when math_rendering_limits_enabled is false' do + stub_application_setting(math_rendering_limits_enabled: false) + stub_const('Banzai::Filter::MathFilter::RENDER_NODES_LIMIT', 2) + + expect(subject.search('.js-render-math').count).to eq(3) + end end it 'protects against malicious backtracking' do diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index ac07755e29c183b8999a1fa5318fe41127fa55c1..1d9e0db259e6f9633fc4fcf4f996f2ae80ec2c2c 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -297,6 +297,9 @@ def many_usernames(num = 100) it { is_expected.to validate_inclusion_of(:package_registry_allow_anyone_to_pull_option).in_array([true, false]) } + it { is_expected.to allow_value([true, false]).for(:math_rendering_limits_enabled) } + it { is_expected.not_to allow_value(nil).for(:math_rendering_limits_enabled) } + context 'when deactivate_dormant_users is enabled' do before do stub_application_setting(deactivate_dormant_users: true)