Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-01-04 12:10:44 +00:00
parent ef863c1f85
commit 9d0b65f4b8
36 changed files with 324 additions and 67 deletions

View file

@ -2,6 +2,7 @@
import CodeOutput from '../code/index.vue';
import HtmlOutput from './html.vue';
import ImageOutput from './image.vue';
import LatexOutput from './latex.vue';
export default {
props: {
@ -35,6 +36,8 @@ export default {
return 'image/jpeg';
} else if (output.data['text/html']) {
return 'text/html';
} else if (output.data['text/latex']) {
return 'text/latex';
} else if (output.data['image/svg+xml']) {
return 'image/svg+xml';
}
@ -59,6 +62,8 @@ export default {
return ImageOutput;
} else if (output.data['text/html']) {
return HtmlOutput;
} else if (output.data['text/latex']) {
return LatexOutput;
} else if (output.data['image/svg+xml']) {
return HtmlOutput;
}

View file

@ -0,0 +1,45 @@
<script>
import 'mathjax/es5/tex-svg';
import Prompt from '../prompt.vue';
export default {
name: 'LatexOutput',
components: {
Prompt,
},
props: {
count: {
type: Number,
required: true,
},
rawCode: {
type: String,
required: true,
},
index: {
type: Number,
required: true,
},
},
computed: {
code() {
// MathJax will not parse out the inline delimeters "$$" correctly
// so we remove them from the raw code itself
const parsedCode = this.rawCode.replace(/\$\$/g, '');
const svg = window.MathJax.tex2svg(parsedCode);
// NOTE: This is used with `v-html` and not `v-safe-html` due to an
// issue with dompurify stripping out xlink attributes from use tags
return svg.outerHTML;
},
},
};
</script>
<template>
<div class="output">
<prompt type="Out" :count="count" :show-output="index === 0" />
<!-- eslint-disable -->
<div ref="maths" v-html="code"></div>
</div>
</template>

View file

@ -68,7 +68,7 @@ $avatar-sizes: (
);
$identicon-backgrounds: $identicon-red, $identicon-purple, $identicon-indigo, $identicon-blue, $identicon-teal,
$identicon-orange, $gray-darker;
$identicon-orange, $identicon-gray;
%avatar-circle {
float: left;
@ -125,8 +125,8 @@ $identicon-backgrounds: $identicon-red, $identicon-purple, $identicon-indigo, $i
.identicon {
text-align: center;
vertical-align: top;
color: $gray-700;
background-color: $gray-darker;
color: $identicon-text-color;
background-color: $identicon-gray;
// Sizes
@each $size, $size-config in $avatar-sizes {

View file

@ -629,12 +629,14 @@ $note-icon-gutter-width: 55px;
/*
* Identicon
*/
$identicon-text-color: #525252 !default;
$identicon-red: #ffebee !default;
$identicon-purple: #f3e5f5 !default;
$identicon-indigo: #e8eaf6 !default;
$identicon-blue: #e3f2fd !default;
$identicon-teal: #e0f2f1 !default;
$identicon-orange: #fbe9e7 !default;
$identicon-gray: #eee !default;
/*
* Calendar

View file

@ -103,18 +103,13 @@ module Repositories
end
def upload_headers
headers = {
{
Authorization: authorization_header,
# git-lfs v2.5.0 sets the Content-Type based on the uploaded file. This
# ensures that Workhorse can intercept the request.
'Content-Type': LFS_TRANSFER_CONTENT_TYPE
'Content-Type': LFS_TRANSFER_CONTENT_TYPE,
'Transfer-Encoding': 'chunked'
}
if Feature.enabled?(:lfs_chunked_encoding, project, default_enabled: true)
headers['Transfer-Encoding'] = 'chunked'
end
headers
end
def lfs_check_batch_operation!

View file

@ -335,7 +335,8 @@ module ApplicationSettingsHelper
:group_export_limit,
:group_download_export_limit,
:wiki_page_max_content_bytes,
:container_registry_delete_tags_service_timeout
:container_registry_delete_tags_service_timeout,
:rate_limiting_response_text
]
end

View file

@ -400,6 +400,10 @@ class ApplicationSetting < ApplicationRecord
validates :ci_jwt_signing_key,
rsa_key: true, allow_nil: true
validates :rate_limiting_response_text,
length: { maximum: 255, message: _('is too long (maximum is %{count} characters)') },
allow_blank: true
attr_encrypted :asset_proxy_secret_key,
mode: :per_attribute_iv,
key: Settings.attr_encrypted_db_key_base_truncated,

View file

@ -172,7 +172,8 @@ module ApplicationSettingImplementation
container_registry_delete_tags_service_timeout: 250,
container_registry_expiration_policies_worker_capacity: 0,
kroki_enabled: false,
kroki_url: nil
kroki_url: nil,
rate_limiting_response_text: nil
}
end

View file

@ -49,5 +49,12 @@
.form-group
= f.label :throttle_authenticated_web_period_in_seconds, 'Authenticated web rate limit period in seconds', class: 'label-bold'
= f.number_field :throttle_authenticated_web_period_in_seconds, class: 'form-control'
%hr
%h5
= _('Response text')
.form-group
= f.label :rate_limiting_response_text, class: 'label-bold' do
= _('A plain-text response to show to clients that hit the rate limit.')
= f.text_area :rate_limiting_response_text, placeholder: ::Gitlab::Throttle::DEFAULT_RATE_LIMITING_RESPONSE_TEXT, class: 'form-control', rows: 5
= f.submit 'Save changes', class: "gl-button btn btn-success", data: { qa_selector: 'save_changes_button' }

View file

@ -0,0 +1,5 @@
---
title: Allow custom response to be set when rate limits are exceeded
merge_request: 50693
author:
type: added

View file

@ -0,0 +1,5 @@
---
title: Fix identicon text color in dark mode
merge_request: 49785
author: "@yo"
type: fixed

View file

@ -0,0 +1,5 @@
---
title: Add LaTeX support for Jupyter Notebooks
merge_request: 49497
author:
type: fixed

View file

@ -0,0 +1,5 @@
---
title: Remove lfs_chunked_encoding feature flag
merge_request: 50557
author:
type: changed

View file

@ -1,8 +0,0 @@
---
name: lfs_chunked_encoding
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/48269
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/285581
milestone: '13.6'
type: development
group:
default_enabled: true

View file

@ -0,0 +1,12 @@
# frozen_string_literal: true
class AddRateLimitingResponseTextToApplicationSettings < ActiveRecord::Migration[6.0]
DOWNTIME = false
# rubocop:disable Migration/AddLimitToTextColumns
# limit is added in 20210101110640_set_limit_for_rate_limiting_response_text
def change
add_column :application_settings, :rate_limiting_response_text, :text
end
# rubocop:enable Migration/AddLimitToTextColumns
end

View file

@ -0,0 +1,16 @@
# frozen_string_literal: true
class SetLimitForRateLimitingResponseText < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_text_limit :application_settings, :rate_limiting_response_text, 255
end
def down
remove_text_limit :application_settings, :rate_limiting_response_text
end
end

View file

@ -0,0 +1 @@
b3fcc73c6b61469d770e9eb9a14c88bb86398db4ab4b6dc5283718a147db0ac0

View file

@ -0,0 +1 @@
8aac4108b658a7a0646ec230dc2568cb51fea0535b13dfba8b8c9e6edb401d07

View file

@ -9376,12 +9376,14 @@ CREATE TABLE application_settings (
cloud_license_enabled boolean DEFAULT false NOT NULL,
disable_feed_token boolean DEFAULT false NOT NULL,
personal_access_token_prefix text,
rate_limiting_response_text text,
CONSTRAINT app_settings_registry_exp_policies_worker_capacity_positive CHECK ((container_registry_expiration_policies_worker_capacity >= 0)),
CONSTRAINT check_17d9558205 CHECK ((char_length((kroki_url)::text) <= 1024)),
CONSTRAINT check_2dba05b802 CHECK ((char_length(gitpod_url) <= 255)),
CONSTRAINT check_51700b31b5 CHECK ((char_length(default_branch_name) <= 255)),
CONSTRAINT check_57123c9593 CHECK ((char_length(help_page_documentation_base_url) <= 255)),
CONSTRAINT check_718b4458ae CHECK ((char_length(personal_access_token_prefix) <= 20)),
CONSTRAINT check_7227fad848 CHECK ((char_length(rate_limiting_response_text) <= 255)),
CONSTRAINT check_85a39b68ff CHECK ((char_length(encrypted_ci_jwt_signing_key_iv) <= 255)),
CONSTRAINT check_9a719834eb CHECK ((char_length(secret_detection_token_revocation_url) <= 255)),
CONSTRAINT check_9c6c447a13 CHECK ((char_length(maintenance_mode_message) <= 255)),

View file

@ -83,7 +83,8 @@ Example response:
"raw_blob_request_limit": 300,
"wiki_page_max_content_bytes": 52428800,
"require_admin_approval_after_user_signup": false,
"personal_access_token_prefix": "GL-"
"personal_access_token_prefix": "GL-",
"rate_limiting_response_text": null
}
```
@ -176,7 +177,8 @@ Example response:
"raw_blob_request_limit": 300,
"wiki_page_max_content_bytes": 52428800,
"require_admin_approval_after_user_signup": false,
"personal_access_token_prefix": "GL-"
"personal_access_token_prefix": "GL-",
"rate_limiting_response_text": null
}
```
@ -330,6 +332,7 @@ listed in the descriptions of the relevant settings.
| `pseudonymizer_enabled` | boolean | no | **(PREMIUM)** When enabled, GitLab runs a background job that produces pseudonymized CSVs of the GitLab database to upload to your configured object storage directory.
| `push_event_activities_limit` | integer | no | Number of changes (branches or tags) in a single push to determine whether individual push events or bulk push events are created. [Bulk push events are created](../user/admin_area/settings/push_event_activities_limit.md) if it surpasses that value. |
| `push_event_hooks_limit` | integer | no | Number of changes (branches or tags) in a single push to determine whether webhooks and services fire or not. Webhooks and services aren't submitted if it surpasses that value. |
| `rate_limiting_response_text` | string | no | When rate limiting is enabled via the `throttle_*` settings, send this plain text response when a rate limit is exceeded. 'Retry later' is sent if this is blank. |
| `raw_blob_request_limit` | integer | no | Max number of requests per minute for each raw path. Default: 300. To disable throttling set to 0.|
| `recaptcha_enabled` | boolean | no | (**If enabled, requires:** `recaptcha_private_key` and `recaptcha_site_key`) Enable reCAPTCHA. |
| `recaptcha_private_key` | string | required by: `recaptcha_enabled` | Private key for reCAPTCHA. |

View file

@ -79,9 +79,10 @@ package.
## Installing GitLab from source
If the Omnibus GitLab package is not available in your distribution, you can
install GitLab from source: Useful for unsupported systems like \*BSD. For an
overview of the directory structure, read the [structure documentation](installation.md#gitlab-directory-structure).
If the Omnibus GitLab package isn't available for your distribution, you can
install GitLab from source. This can be useful with unsupported systems, like
\*BSD. For an overview of the directory structure, see the
[structure documentation](installation.md#gitlab-directory-structure).
[**> Install GitLab from source.**](installation.md)

View file

@ -16,7 +16,7 @@ as the hardware requirements that are needed to install and use GitLab.
- Ubuntu (16.04/18.04/20.04)
- Debian (9/10)
- CentOS (6/7/8)
- CentOS (7/8)
- openSUSE (Leap 15.1/Enterprise Server 12.2)
- Red Hat Enterprise Linux (please use the CentOS packages and instructions)
- Scientific Linux (please use the CentOS packages and instructions)
@ -35,6 +35,9 @@ For the installation options, see [the main installation page](README.md).
Installation of GitLab on these operating systems is possible, but not supported.
Please see the [installation from source guide](installation.md) and the [installation guides](https://about.gitlab.com/install/) for more information.
Please see [OS versions that are no longer supported](https://docs.gitlab.com/omnibus/package-information/deprecated_os.html) for Omnibus installs page
for a list of supported and unsupported OS versions as well as the last support GitLab version for that OS.
### Microsoft Windows
GitLab is developed for Linux-based operating systems.
@ -163,11 +166,11 @@ Support for [PostgreSQL 9.6 and 10 has been removed in GitLab 13.0](https://abou
#### Additional requirements for GitLab Geo
If you're using [GitLab Geo](../administration/geo/index.md):
- We strongly recommend running Omnibus-managed instances as they are actively
developed and tested. We aim to be compatible with most external (not managed
by Omnibus) databases (for example, [AWS Relational Database Service (RDS)](https://aws.amazon.com/rds/)) but we don't guarantee compatibility.
If you're using [GitLab Geo](../administration/geo/index.md), we strongly
recommend running Omnibus GitLab-managed instances, as we actively develop and
test based on those. We try to be compatible with most external (not managed by
Omnibus GitLab) databases (for example, [AWS Relational Database Service (RDS)](https://aws.amazon.com/rds/)),
but we can't guarantee compatibility.
## Puma settings

View file

@ -25,6 +25,17 @@ By default, all Git operations are first tried unathenticated. Because of this,
![user-and-ip-rate-limits](img/user_and_ip_rate_limits.png)
## Response text
A request that exceeds a rate limit will get a 429 response code and a
plain-text body, which by default is:
```plaintext
Retry later
```
It is possible to customize this response text in the admin area.
## Use an HTTP header to bypass rate limiting
> [Introduced](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/622) in GitLab 13.6.

View file

@ -10,8 +10,17 @@ module Gitlab
def self.configure(rack_attack)
# This adds some methods used by our throttles to the `Rack::Request`
rack_attack::Request.include(Gitlab::RackAttack::Request)
# Send the Retry-After header so clients (e.g. python-gitlab) can make good choices about delays
Rack::Attack.throttled_response_retry_after_header = true
# This is Rack::Attack::DEFAULT_THROTTLED_RESPONSE, modified to allow a custom response
Rack::Attack.throttled_response = lambda do |env|
# Send the Retry-After header so clients (e.g. python-gitlab) can make good choices about delays
match_data = env['rack.attack.match_data']
now = match_data[:epoch_time]
retry_after = match_data[:period] - (now % match_data[:period])
[429, { 'Content-Type' => 'text/plain', 'Retry-After' => retry_after.to_s }, [Gitlab::Throttle.rate_limiting_response_text]]
end
# Configure the throttles
configure_throttles(rack_attack)

View file

@ -2,6 +2,8 @@
module Gitlab
class Throttle
DEFAULT_RATE_LIMITING_RESPONSE_TEXT = 'Retry later'
def self.settings
Gitlab::CurrentSettings.current_application_settings
end
@ -46,5 +48,9 @@ module Gitlab
{ limit: limit_proc, period: period_proc }
end
def self.rate_limiting_response_text
(settings.rate_limiting_response_text.presence || DEFAULT_RATE_LIMITING_RESPONSE_TEXT) + "\n"
end
end
end

View file

@ -1304,6 +1304,9 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
msgid "A plain-text response to show to clients that hit the rate limit."
msgstr ""
msgid "A platform value can be web, mob or app."
msgstr ""
@ -23928,6 +23931,9 @@ msgstr ""
msgid "Response metrics (NGINX)"
msgstr ""
msgid "Response text"
msgstr ""
msgid "Restart Terminal"
msgstr ""

View file

@ -108,6 +108,7 @@
"katex": "^0.10.0",
"lodash": "^4.17.20",
"marked": "^0.3.12",
"mathjax": "3",
"mermaid": "^8.5.2",
"mersenne-twister": "1.1.0",
"minimatch": "^3.0.4",

View file

@ -1,6 +1,9 @@
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import httpStatus from '~/lib/utils/http_status';
import createDiffsStore from '~/diffs/store/modules';
import createNotesStore from '~/notes/stores/modules';
import diffFileMockDataReadable from '../mock_data/diff_file';
@ -118,14 +121,17 @@ const changeViewerType = (store, newType, index = 0) =>
describe('DiffFile', () => {
let wrapper;
let store;
let axiosMock;
beforeEach(() => {
axiosMock = new MockAdapter(axios);
({ wrapper, store } = createComponent({ file: getReadableFile() }));
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
axiosMock.restore();
});
describe('bus events', () => {
@ -353,8 +359,10 @@ describe('DiffFile', () => {
describe('loading', () => {
it('should have loading icon while loading a collapsed diffs', async () => {
const { load_collapsed_diff_url } = store.state.diffs.diffFiles[0];
axiosMock.onGet(load_collapsed_diff_url).reply(httpStatus.OK, getReadableFile());
makeFileAutomaticallyCollapsed(store);
wrapper.vm.isLoadingCollapsedDiff = true;
wrapper.vm.requestDiff();
await wrapper.vm.$nextTick();

View file

@ -18,12 +18,14 @@ describe('Output component', () => {
};
beforeEach(() => {
// This is the output after rendering a jupyter notebook
json = getJSONFixture('blob/notebook/basic.json');
});
describe('text output', () => {
beforeEach((done) => {
createComponent(json.cells[2].outputs[0]);
const textType = json.cells[2];
createComponent(textType.outputs[0]);
setImmediate(() => {
done();
@ -41,7 +43,8 @@ describe('Output component', () => {
describe('image output', () => {
beforeEach((done) => {
createComponent(json.cells[3].outputs[0]);
const imageType = json.cells[3];
createComponent(imageType.outputs[0]);
setImmediate(() => {
done();
@ -55,23 +58,42 @@ describe('Output component', () => {
describe('html output', () => {
it('renders raw HTML', () => {
createComponent(json.cells[4].outputs[0]);
const htmlType = json.cells[4];
createComponent(htmlType.outputs[0]);
expect(vm.$el.querySelector('p')).not.toBeNull();
expect(vm.$el.querySelectorAll('p').length).toBe(1);
expect(vm.$el.querySelectorAll('p')).toHaveLength(1);
expect(vm.$el.textContent.trim()).toContain('test');
});
it('renders multiple raw HTML outputs', () => {
createComponent([json.cells[4].outputs[0], json.cells[4].outputs[0]]);
const htmlType = json.cells[4];
createComponent([htmlType.outputs[0], htmlType.outputs[0]]);
expect(vm.$el.querySelectorAll('p').length).toBe(2);
expect(vm.$el.querySelectorAll('p')).toHaveLength(2);
});
});
describe('LaTeX output', () => {
it('renders LaTeX', () => {
const output = {
data: {
'text/latex': ['$$F(k) = \\int_{-\\infty}^{\\infty} f(x) e^{2\\pi i k} dx$$'],
'text/plain': ['<IPython.core.display.Latex object>'],
},
metadata: {},
output_type: 'display_data',
};
createComponent(output);
expect(vm.$el.querySelector('.MathJax')).not.toBeNull();
});
});
describe('svg output', () => {
beforeEach((done) => {
createComponent(json.cells[5].outputs[0]);
const svgType = json.cells[5];
createComponent(svgType.outputs[0]);
setImmediate(() => {
done();
@ -85,7 +107,8 @@ describe('Output component', () => {
describe('default to plain text', () => {
beforeEach((done) => {
createComponent(json.cells[6].outputs[0]);
const unknownType = json.cells[6];
createComponent(unknownType.outputs[0]);
setImmediate(() => {
done();
@ -102,7 +125,8 @@ describe('Output component', () => {
});
it("renders as plain text when doesn't recognise other types", (done) => {
createComponent(json.cells[7].outputs[0]);
const unknownType = json.cells[7];
createComponent(unknownType.outputs[0]);
setImmediate(() => {
expect(vm.$el.querySelector('pre')).not.toBeNull();

View file

@ -0,0 +1,40 @@
import { shallowMount } from '@vue/test-utils';
import LatexOutput from '~/notebook/cells/output/latex.vue';
import Prompt from '~/notebook/cells/prompt.vue';
describe('LaTeX output cell', () => {
beforeEach(() => {
window.MathJax = {
tex2svg: jest.fn((code) => ({ outerHTML: code })),
};
});
const inlineLatex = '$$F(k) = \\int_{-\\infty}^{\\infty} f(x) e^{2\\pi i k} dx$$';
const count = 12345;
const createComponent = (rawCode, index) =>
shallowMount(LatexOutput, {
propsData: {
count,
index,
rawCode,
},
});
it.each`
index | expectation
${0} | ${true}
${1} | ${false}
`('sets `Prompt.show-output` to $expectation when index is $index', ({ index, expectation }) => {
const wrapper = createComponent(inlineLatex, index);
const prompt = wrapper.find(Prompt);
expect(prompt.props().count).toEqual(count);
expect(prompt.props().showOutput).toEqual(expectation);
});
it('strips the `$$` delimter from LaTeX', () => {
createComponent(inlineLatex, 0);
expect(window.MathJax.tex2svg).toHaveBeenCalledWith(expect.not.stringContaining('$$'));
});
});

View file

@ -22,8 +22,7 @@ RSpec.describe Gitlab::RackAttack, :aggregate_failures do
stub_const("Rack::Attack", fake_rack_attack)
stub_const("Rack::Attack::Request", fake_rack_attack_request)
# Expect rather than just allow, because this is actually fairly important functionality
expect(fake_rack_attack).to receive(:throttled_response_retry_after_header=).with(true)
allow(fake_rack_attack).to receive(:throttled_response=)
allow(fake_rack_attack).to receive(:throttle)
allow(fake_rack_attack).to receive(:track)
allow(fake_rack_attack).to receive(:safelist)
@ -36,6 +35,12 @@ RSpec.describe Gitlab::RackAttack, :aggregate_failures do
expect(fake_rack_attack_request).to include(described_class::Request)
end
it 'configures the throttle response' do
described_class.configure(fake_rack_attack)
expect(fake_rack_attack).to have_received(:throttled_response=).with(an_instance_of(Proc))
end
it 'configures the safelist' do
described_class.configure(fake_rack_attack)

View file

@ -30,4 +30,32 @@ RSpec.describe Gitlab::Throttle do
end
end
end
describe '.rate_limiting_response_text' do
subject { described_class.rate_limiting_response_text }
context 'when the setting is not present' do
before do
stub_application_setting(rate_limiting_response_text: '')
end
it 'returns the default value with a trailing newline' do
expect(subject).to eq(described_class::DEFAULT_RATE_LIMITING_RESPONSE_TEXT + "\n")
end
end
context 'when the setting is present' do
let(:response_text) do
'Rate limit exceeded; see https://docs.gitlab.com/ee/user/gitlab_com/#gitlabcom-specific-rate-limits for more details'
end
before do
stub_application_setting(rate_limiting_response_text: response_text)
end
it 'returns the default value with a trailing newline' do
expect(subject).to eq(response_text + "\n")
end
end
end
end

View file

@ -193,10 +193,8 @@ RSpec.describe 'Git LFS API and storage' do
subject(:request) { post_lfs_json batch_url(project), body, headers }
let(:response) { request && super() }
let(:lfs_chunked_encoding) { true }
before do
stub_feature_flags(lfs_chunked_encoding: lfs_chunked_encoding)
project.lfs_objects << lfs_object
end
@ -480,20 +478,6 @@ RSpec.describe 'Git LFS API and storage' do
expect(headers['Transfer-Encoding']).to eq('chunked')
end
context 'when lfs_chunked_encoding feature is disabled' do
let(:lfs_chunked_encoding) { false }
it 'responds with upload hypermedia link' do
expect(json_response['objects']).to be_kind_of(Array)
expect(json_response['objects'].first).to include(sample_object)
expect(json_response['objects'].first['actions']['upload']['href']).to eq(objects_url(project, sample_oid, sample_size))
headers = json_response['objects'].first['actions']['upload']['header']
expect(headers['Content-Type']).to eq('application/octet-stream')
expect(headers['Transfer-Encoding']).to be_nil
end
end
it_behaves_like 'process authorization header', renew_authorization: renew_authorization
end

View file

@ -60,6 +60,24 @@ RSpec.describe 'Rack Attack global throttles' do
expect_rejection { get url_that_does_not_require_authentication }
end
context 'with custom response text' do
before do
stub_application_setting(rate_limiting_response_text: 'Custom response')
end
it 'rejects requests over the rate limit' do
# At first, allow requests under the rate limit.
requests_per_period.times do
get url_that_does_not_require_authentication
expect(response).to have_gitlab_http_status(:ok)
end
# the last straw
expect_rejection { get url_that_does_not_require_authentication }
expect(response.body).to eq("Custom response\n")
end
end
it 'allows requests after throttling and then waiting for the next period' do
requests_per_period.times do
get url_that_does_not_require_authentication

View file

@ -25,6 +25,7 @@ module RackAttackSpecHelpers
yield
expect(response).to have_gitlab_http_status(:too_many_requests)
expect(response).to have_header('Retry-After')
end
def expect_ok(&block)

View file

@ -3057,7 +3057,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies:
delayed-stream "~1.0.0"
commander@2, commander@^2.10.0, commander@^2.16.0, commander@^2.18.0, commander@^2.19.0, commander@^2.20.0, commander@~2.20.0:
commander@2, commander@^2.10.0, commander@^2.18.0, commander@^2.19.0, commander@^2.20.0, commander@~2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
@ -7476,11 +7476,11 @@ karma@^4.2.0:
useragent "2.3.0"
katex@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/katex/-/katex-0.10.0.tgz#da562e5d0d5cc3aa602e27af8a9b8710bfbce765"
integrity sha512-/WRvx+L1eVBrLwX7QzKU1dQuaGnE7E8hDvx3VWfZh9HbMiCfsKWJNnYZ0S8ZMDAfAyDSofdyXIrH/hujF1fYXg==
version "0.10.2"
resolved "https://registry.yarnpkg.com/katex/-/katex-0.10.2.tgz#39973edbb65eda5b6f9e7f41648781e557dd4932"
integrity sha512-cQOmyIRoMloCoSIOZ1+gEwsksdJZ1EW4SWm3QzxSza/QsnZr6D4U1V9S4q+B/OLm2OQ8TCBecQ8MaIfnScI7cw==
dependencies:
commander "^2.16.0"
commander "^2.19.0"
keyv@^3.0.0:
version "3.1.0"
@ -8054,6 +8054,11 @@ marked@^0.3.12, marked@~0.3.6:
resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.19.tgz#5d47f709c4c9fc3c216b6d46127280f40b39d790"
integrity sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==
mathjax@3:
version "3.1.2"
resolved "https://registry.yarnpkg.com/mathjax/-/mathjax-3.1.2.tgz#95c0d45ce2330ef7b6a815cebe7d61ecc26bbabd"
integrity sha512-BojKspBv4nNWzO1wC6VEI+g9gHDOhkaGHGgLxXkasdU4pwjdO5AXD5M/wcLPkXYPjZ/N+6sU8rjQTlyvN2cWiQ==
mathml-tag-names@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.1.tgz#6dff66c99d55ecf739ca53c492e626f1d12a33cc"