Commit b2cc230c authored by Bob Van Landuyt's avatar Bob Van Landuyt

Merge branch 'fj-31133-snippet-content-size-limit' into 'master'

Add limit to snippet content size

See merge request gitlab-org/gitlab!20346
parents b2546576 c02587ed
......@@ -301,7 +301,8 @@ module ApplicationSettingsHelper
:snowplow_iglu_registry_url,
:push_event_hooks_limit,
:push_event_activities_limit,
:custom_http_clone_url_root
:custom_http_clone_url_root,
:snippet_size_limit
]
end
......
......@@ -226,6 +226,8 @@ class ApplicationSetting < ApplicationRecord
validates :push_event_activities_limit,
numericality: { greater_than_or_equal_to: 0 }
validates :snippet_size_limit, numericality: { only_integer: true, greater_than: 0 }
SUPPORTED_KEY_TYPES.each do |type|
validates :"#{type}_key_restriction", presence: true, key_restriction: { type: type }
end
......
......@@ -139,7 +139,8 @@ module ApplicationSettingImplementation
snowplow_app_id: nil,
snowplow_iglu_registry_url: nil,
custom_http_clone_url_root: nil,
productivity_analytics_start_date: Time.now
productivity_analytics_start_date: Time.now,
snippet_size_limit: 50.megabytes
}
end
......
......@@ -46,6 +46,18 @@ class Snippet < ApplicationRecord
length: { maximum: 255 }
validates :content, presence: true
validates :content,
length: {
maximum: ->(_) { Gitlab::CurrentSettings.snippet_size_limit },
message: -> (_, data) do
current_value = ActiveSupport::NumberHelper.number_to_human_size(data[:value].size)
max_size = ActiveSupport::NumberHelper.number_to_human_size(Gitlab::CurrentSettings.snippet_size_limit)
_("is too long (%{current_value}). The maximum size is %{max_size}.") % { current_value: current_value, max_size: max_size }
end
},
if: :content_changed?
validates :visibility_level, inclusion: { in: Gitlab::VisibilityLevel.values }
# Scopes
......
---
title: Add limit for snippet content size
merge_request: 20346
author:
type: performance
# frozen_string_literal: true
class AddSnippetSizeLimitToApplicationSettings < ActiveRecord::Migration[5.2]
DOWNTIME = false
def up
add_column :application_settings, :snippet_size_limit, :bigint, default: 50.megabytes, null: false
end
def down
remove_column :application_settings, :snippet_size_limit
end
end
......@@ -361,6 +361,7 @@ ActiveRecord::Schema.define(version: 2019_11_25_140458) do
t.string "encrypted_slack_app_secret_iv", limit: 255
t.text "encrypted_slack_app_verification_token"
t.string "encrypted_slack_app_verification_token_iv", limit: 255
t.bigint "snippet_size_limit", default: 52428800, null: false
t.index ["custom_project_templates_group_id"], name: "index_application_settings_on_custom_project_templates_group_id"
t.index ["file_template_project_id"], name: "index_application_settings_on_file_template_project_id"
t.index ["instance_administration_project_id"], name: "index_applicationsettings_on_instance_administration_project_id"
......
......@@ -158,6 +158,10 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Shared Runners pipelines quota](../user/admin_area/settings/continuous_integration.md#shared-runners-pipeline-minutes-quota-starter-only): Limit the usage of pipeline minutes for Shared Runners. **(STARTER ONLY)**
- [Enable/disable Auto DevOps](../topics/autodevops/index.md#enablingdisabling-auto-devops): Enable or disable Auto DevOps for your instance.
## Snippet settings
- [Setting snippet content size limit](snippets/index.md): Set a maximum size limit for snippets' content.
## Git configuration options
- [Custom Git hooks](custom_hooks.md): Custom Git hooks (on the filesystem) for when webhooks aren't enough.
......
---
type: reference, howto
---
# Snippets settings **(CORE ONLY)**
Adjust the snippets' settings of your GitLab instance.
## Snippets content size limit
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/31133) in GitLab 12.6.
You can set a content size max limit in snippets. This limit can prevent
abuses of the feature. The default content size limit is **52428800 Bytes** (50MB).
### How does it work?
The content size limit will be applied when a snippet is created or
updated. Nevertheless, in order not to break any existing snippet,
the limit will only be enforced in stored snippets when the content
is updated.
### Snippets size limit configuration
This setting is not available through the [Admin Area settings](../../user/admin_area/settings/index.md).
In order to configure this setting, use either the Rails console
or the [Application settings API](../../api/settings.md).
NOTE: **IMPORTANT:**
The value of the limit **must** be in Bytes.
#### Through the Rails console
The steps to configure this setting through the Rails console are:
1. Start the Rails console:
```bash
# For Omnibus installations
sudo gitlab-rails console
# For installations from source
sudo -u git -H bundle exec rails console production
```
1. Update the snippets maximum file size:
```ruby
ApplicationSetting.first.update!(snippet_size_limit: 50.megabytes)
```
To retrieve the current value, start the Rails console and run:
```ruby
Gitlab::CurrentSettings.snippet_size_limit
```
#### Through the API
The process to set the snippets size limit through the Application Settings API is
exactly the same as you would do to [update any other setting](../../api/settings.md#change-application-settings).
```bash
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/application/settings?snippet_size_limit=52428800
```
You can also use the API to [retrieve the current value](../../api/settings.md#get-current-application-settings).
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/application/settings
```
......@@ -350,3 +350,4 @@ are listed in the descriptions of the relevant settings.
| `user_show_add_ssh_key_message` | boolean | no | When set to `false` disable the "You won't be able to pull or push project code via SSH" warning shown to users with no uploaded SSH key. |
| `version_check_enabled` | boolean | no | Let GitLab inform you when an update is available. |
| `web_ide_clientside_preview_enabled` | boolean | no | Client side evaluation (allow live previews of JavaScript projects in the Web IDE using CodeSandbox client side evaluation). |
| `snippet_size_limit` | integer | no | Max snippet content size in **bytes**. Default: 52428800 Bytes (50MB).|
......@@ -20937,6 +20937,9 @@ msgstr ""
msgid "is not an email you own"
msgstr ""
msgid "is too long (%{current_value}). The maximum size is %{max_size}."
msgstr ""
msgid "is too long (maximum is 100 entries)"
msgstr ""
......
......@@ -66,6 +66,8 @@ describe ApplicationSetting do
it { is_expected.not_to allow_value('three').for(:push_event_activities_limit) }
it { is_expected.not_to allow_value(nil).for(:push_event_activities_limit) }
it { is_expected.to validate_numericality_of(:snippet_size_limit).only_integer.is_greater_than(0) }
context 'when snowplow is enabled' do
before do
setting.snowplow_enabled = true
......
......@@ -31,6 +31,62 @@ describe Snippet do
it { is_expected.to validate_presence_of(:content) }
it { is_expected.to validate_inclusion_of(:visibility_level).in_array(Gitlab::VisibilityLevel.values) }
it do
allow(Gitlab::CurrentSettings).to receive(:snippet_size_limit).and_return(1)
is_expected
.to validate_length_of(:content)
.is_at_most(Gitlab::CurrentSettings.snippet_size_limit)
.with_message("is too long (2 Bytes). The maximum size is 1 Byte.")
end
context 'content validations' do
context 'with existing snippets' do
let(:snippet) { create(:personal_snippet, content: 'This is a valid content at the time of creation') }
before do
expect(snippet).to be_valid
stub_application_setting(snippet_size_limit: 2)
end
it 'does not raise a validation error if the content is not changed' do
snippet.title = 'new title'
expect(snippet).to be_valid
end
it 'raises and error if the content is changed and the size is bigger than limit' do
snippet.content = snippet.content + "test"
expect(snippet).not_to be_valid
end
end
context 'with new snippets' do
let(:limit) { 15 }
before do
stub_application_setting(snippet_size_limit: limit)
end
it 'is valid when content is smaller than the limit' do
snippet = build(:personal_snippet, content: 'Valid Content')
expect(snippet).to be_valid
end
it 'raises error when content is bigger than setting limit' do
snippet = build(:personal_snippet, content: 'This is an invalid content')
aggregate_failures do
expect(snippet).not_to be_valid
expect(snippet.errors[:content]).to include("is too long (#{snippet.content.size} Bytes). The maximum size is #{limit} Bytes.")
end
end
end
end
end
describe '#to_reference' do
......
......@@ -36,6 +36,7 @@ describe API::Settings, 'Settings' do
expect(json_response['allow_local_requests_from_system_hooks']).to be(true)
expect(json_response).not_to have_key('performance_bar_allowed_group_path')
expect(json_response).not_to have_key('performance_bar_enabled')
expect(json_response['snippet_size_limit']).to eq(50.megabytes)
end
end
......@@ -85,7 +86,8 @@ describe API::Settings, 'Settings' do
allow_local_requests_from_web_hooks_and_services: true,
allow_local_requests_from_system_hooks: false,
push_event_hooks_limit: 2,
push_event_activities_limit: 2
push_event_activities_limit: 2,
snippet_size_limit: 5
}
expect(response).to have_gitlab_http_status(200)
......@@ -121,6 +123,7 @@ describe API::Settings, 'Settings' do
expect(json_response['allow_local_requests_from_system_hooks']).to eq(false)
expect(json_response['push_event_hooks_limit']).to eq(2)
expect(json_response['push_event_activities_limit']).to eq(2)
expect(json_response['snippet_size_limit']).to eq(5)
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment