Commit 78fe72d1 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 88797b99
......@@ -361,18 +361,33 @@ module ApplicationSettingImplementation
def separate_whitelists(string_array)
string_array.reduce([[], []]) do |(ip_whitelist, domain_whitelist), string|
ip_obj = Gitlab::Utils.string_to_ip_object(string)
address, port = parse_addr_and_port(string)
ip_obj = Gitlab::Utils.string_to_ip_object(address)
if ip_obj
ip_whitelist << ip_obj
ip_whitelist << Gitlab::UrlBlockers::IpWhitelistEntry.new(ip_obj, port: port)
else
domain_whitelist << string
domain_whitelist << Gitlab::UrlBlockers::DomainWhitelistEntry.new(address, port: port)
end
[ip_whitelist, domain_whitelist]
end
end
def parse_addr_and_port(str)
case str
when /\A\[(?<address> .* )\]:(?<port> \d+ )\z/x # string like "[::1]:80"
address, port = $~[:address], $~[:port]
when /\A(?<address> [^:]+ ):(?<port> \d+ )\z/x # string like "127.0.0.1:80"
address, port = $~[:address], $~[:port]
else # string with no port number
address, port = str, nil
end
[address, port&.to_i]
end
def array_to_string(arr)
arr&.join("\n")
end
......
# frozen_string_literal: true
# Ensure that uploaded files are what they say they are for security and
# handling purposes. The checks are not 100% reliable so we err on the side of
# caution and allow by default, and deny when we're confident of a fail state.
#
# Include this concern, then call `check_upload_type` to check all
# uploads. Attach a `mime_type` or `extensions` parameter to only check
# specific upload types. Both parameters will be normalized to a MIME type and
# checked against the inferred MIME type of the upload content and filename
# extension.
#
# class YourUploader
# include UploadTypeCheck::Concern
# check_upload_type mime_types: ['image/png', /image\/jpe?g/]
#
# # or...
#
# check_upload_type extensions: ['png', 'jpg', 'jpeg']
# end
#
# The mime_types parameter can accept `NilClass`, `String`, `Regexp`,
# `Array[String, Regexp]`. This matches the CarrierWave `extension_whitelist`
# and `content_type_whitelist` family of behavior.
#
# The extensions parameter can accept `NilClass`, `String`, `Array[String]`.
module UploadTypeCheck
module Concern
extend ActiveSupport::Concern
class_methods do
def check_upload_type(mime_types: nil, extensions: nil)
define_method :check_upload_type_callback do |file|
magic_file = MagicFile.new(file.to_file)
# Map file extensions back to mime types.
if extensions
mime_types = Array(mime_types) +
Array(extensions).map { |e| MimeMagic::EXTENSIONS[e] }
end
if mime_types.nil? || magic_file.matches_mime_types?(mime_types)
check_content_matches_extension!(magic_file)
end
end
before :cache, :check_upload_type_callback
end
end
def check_content_matches_extension!(magic_file)
return if magic_file.ambiguous_type?
if magic_file.magic_type != magic_file.ext_type
raise CarrierWave::IntegrityError, 'Content type does not match file extension'
end
end
end
# Convenience class to wrap MagicMime objects.
class MagicFile
attr_reader :file
def initialize(file)
@file = file
end
def magic_type
@magic_type ||= MimeMagic.by_magic(file)
end
def ext_type
@ext_type ||= MimeMagic.by_path(file.path)
end
def magic_type_type
magic_type&.type
end
def ext_type_type
ext_type&.type
end
def matches_mime_types?(mime_types)
Array(mime_types).any? do |mt|
magic_type_type =~ /\A#{mt}\z/ || ext_type_type =~ /\A#{mt}\z/
end
end
# - Both types unknown or text/plain.
# - Ambiguous magic type with text extension. Plain text file.
# - Text magic type with ambiguous extension. TeX file missing extension.
def ambiguous_type?
(ext_type.to_s.blank? && magic_type.to_s.blank?) ||
(magic_type.to_s.blank? && ext_type_type == 'text/plain') ||
(ext_type.to_s.blank? && magic_type_type == 'text/plain')
end
end
end
---
title: Include snippet description as part of snippet title search (when Elasticsearch is not enabled)
title: Include snippet description as part of snippet title search (basic search).
merge_request: 25961
author:
type: added
---
title: Add ability to whitelist ports
merge_request: 27025
author:
type: added
......@@ -65,7 +65,7 @@ maximum memory threshold (in bytes) for the Unicorn worker killer by
setting the following values `/etc/gitlab/gitlab.rb`:
- For GitLab **12.7** and newer:
```ruby
unicorn['worker_memory_limit_min'] = "1024 * 1 << 20"
unicorn['worker_memory_limit_max'] = "1280 * 1 << 20"
......
......@@ -118,10 +118,10 @@ upload packages:
#'path_style' => false # If true, use 'host/bucket_name/object' instead of 'bucket_name.host/object'.
}
```
NOTE: **Note:**
Some build tools, like Gradle, must make `HEAD` requests to Amazon S3 to pull a dependency’s metadata. The `gitlab_rails['packages_object_store_proxy_download']` property must be set to `true`. Without this setting, GitLab won't act as a proxy to the Amazon S3 service, and will instead return the signed URL. This will cause a `HTTP 403 Forbidden` response, since Amazon S3 expects a signed URL.
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure)
for the changes to take effect.
......
# Here's the script I'll use to demonstrate - it just loops forever:
$ cat test.rb
$ cat test.rb
#!/usr/bin/env ruby
loop do
......@@ -75,7 +75,7 @@ Thread 1 (Thread 0xb74d76c0 (LWP 1343)):
at eval.c:5778
#5 rb_call0 (klass=3075304600, recv=3075299660, id=9393, oid=9393, argc=1, argv=0xbf85f490, body=0xb74c85a8, flags=2)
at eval.c:5928
#6 0x0805e35d in rb_call (klass=3075304600, recv=3075299660, mid=9393, argc=1, argv=0xbf85f490, scope=1,
#6 0x0805e35d in rb_call (klass=3075304600, recv=3075299660, mid=9393, argc=1, argv=0xbf85f490, scope=1,
self=<optimized out>) at eval.c:6176
#7 0x080651ec in rb_eval (self=3075299660, n=0xb74c4e1c) at eval.c:3521
#8 0x0805c31c in rb_yield_0 (val=6, self=3075299660, klass=<optimized out>, flags=0, avalue=0) at eval.c:5095
......@@ -139,4 +139,4 @@ A debugging session is active.
Quit anyway? (y or n) y
Detaching from program: /opt/vagrant_ruby/bin/ruby, process 1343
$
$
......@@ -77,11 +77,11 @@ and they will assist you with any issues you are having.
```shell
kubectl get cronjobs
```
When one configures [cron-based backups](https://docs.gitlab.com/charts/backup-restore/backup.html#cron-based-backup),
you will be able to see the new schedule here. Some details about the schedules can be found
in [Running Automated Tasks with a CronJob](https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/#creating-a-cron-job)
## GitLab-specific Kubernetes information
- Minimal config that can be used to test a Kubernetes Helm chart can be found
......@@ -167,7 +167,7 @@ and they will assist you with any issues you are having.
```shell
kubectl exec -it <task-runner-pod-name> -- /srv/gitlab/bin/rails dbconsole -p
```
- How to get info about Helm installation status:
```shell
......
......@@ -149,12 +149,12 @@ import { mockTracking, triggerEvent } from 'spec/helpers/tracking_helper';
describe('my component', () => {
let trackingSpy;
beforeEach(() => {
const vm = mountComponent(MyComponent);
trackingSpy = mockTracking('_category_', vm.$el, spyOn);
});
it('tracks an event when toggled', () => {
triggerEvent('a.toggle');
......
......@@ -195,17 +195,17 @@ module Gitlab
The [current version history](../user/project/settings/import_export.md) also displays the equivalent GitLab version
and it is useful for knowing which versions won't be compatible between them.
| Exporting GitLab version | Importing GitLab version |
| -------------------------- | -------------------------- |
| 11.7 to current | 11.7 to current |
| 11.1 to 11.6 | 11.1 to 11.6 |
| 10.8 to 11.0 | 10.8 to 11.0 |
| 10.4 to 10.7 | 10.4 to 10.7 |
| ... | ... |
| 8.10.3 to 8.11 | 8.10.3 to 8.11 |
| 8.10.0 to 8.10.2 | 8.10.0 to 8.10.2 |
| 8.9.5 to 8.9.11 | 8.9.5 to 8.9.11 |
| 8.9.0 to 8.9.4 | 8.9.0 to 8.9.4 |
| Exporting GitLab version | Importing GitLab version |
| -------------------------- | -------------------------- |
| 11.7 to current | 11.7 to current |
| 11.1 to 11.6 | 11.1 to 11.6 |
| 10.8 to 11.0 | 10.8 to 11.0 |
| 10.4 to 10.7 | 10.4 to 10.7 |
| ... | ... |
| 8.10.3 to 8.11 | 8.10.3 to 8.11 |
| 8.10.0 to 8.10.2 | 8.10.0 to 8.10.2 |
| 8.9.5 to 8.9.11 | 8.9.5 to 8.9.11 |
| 8.9.0 to 8.9.4 | 8.9.0 to 8.9.4 |
### When to bump the version up
......
......@@ -278,7 +278,7 @@ and where the `message` repeats the `location` field:
It takes around 50k characters to block for 2 seconds making this a low severity issue."
}
```
The `description` might explain how the vulnerability works or give context about the exploit.
It should not repeat the other fields of the vulnerability object.
In particular, the `description` should not repeat the `location` (what is affected)
......
......@@ -43,7 +43,7 @@ Subclasses of `AbstractReferenceFilter` generally do not override `#call`; inste
a minimum implementation of `AbstractReferenceFilter` should define:
- `.reference_type`: The type of domain object.
This is usually a keyword, and is used to set the `data-reference-type` attribute
on the generated link, and is an important part of the interaction with the
corresponding `ReferenceParser` (see below).
......
......@@ -6,8 +6,10 @@ This is a partial list of the [RSpec metadata](https://relishapp.com/rspec/rspec
<!-- Please keep the tags in alphabetical order -->
| Tag | Description |
|-|-|
| `:elasticsearch` | The test requires an Elasticsearch service. It is used by the [instance-level scenario](https://gitlab.com/gitlab-org/gitlab-qa#definitions) [`Test::Integration::Elasticsearch`](https://gitlab.com/gitlab-org/gitlab/-/blob/72b62b51bdf513e2936301cb6c7c91ec27c35b4d/qa/qa/ee/scenario/test/integration/elasticsearch.rb) to include only tests that require Elasticsearch. |
| `:orchestrated` | The GitLab instance under test may be [configured by `gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/what_tests_can_be_run.md#orchestrated-tests) to be different to the default GitLab configuration, or `gitlab-qa` may launch additional services in separate docker containers, or both. Tests tagged with `:orchestrated` are excluded when testing environments where we can't dynamically modify GitLab's configuration (for example, Staging). |
| `:quarantine` | The test has been [quarantined](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#quarantining-tests), will run in a separate job that only includes quarantined tests, and is allowed to fail. The test will be skipped in its regular job so that if it fails it will not hold up the pipeline. |
|-----|-------------|
| `:elasticsearch` | The test requires an Elasticsearch service. It is used by the [instance-level scenario](https://gitlab.com/gitlab-org/gitlab-qa#definitions) [`Test::Integration::Elasticsearch`](https://gitlab.com/gitlab-org/gitlab/-/blob/72b62b51bdf513e2936301cb6c7c91ec27c35b4d/qa/qa/ee/scenario/test/integration/elasticsearch.rb) to include only tests that require Elasticsearch. |
| `:kubernetes` | The test includes a GitLab instance that is configured to be run behind an SSH tunnel, allowing a TLS-accessible GitLab. This test will also include provisioning of at least one Kubernetes cluster to test against. *This tag is often be paired with `:orchestrated`.* |
| `:orchestrated` | The GitLab instance under test may be [configured by `gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/what_tests_can_be_run.md#orchestrated-tests) to be different to the default GitLab configuration, or `gitlab-qa` may launch additional services in separate docker containers, or both. Tests tagged with `:orchestrated` are excluded when testing environments where we can't dynamically modify GitLab's configuration (for example, Staging). |
| `:quarantine` | The test has been [quarantined](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#quarantining-tests), will run in a separate job that only includes quarantined tests, and is allowed to fail. The test will be skipped in its regular job so that if it fails it will not hold up the pipeline. |
| `:reliable` | The test has been [promoted to a reliable test](https://about.gitlab.com/handbook/engineering/quality/guidelines/reliable-tests/#promoting-an-existing-test-to-reliable) meaning it passes consistently in all pipelines, including merge requests. |
| `:requires_admin` | The test requires an admin account. Tests with the tag are excluded when run against Canary and Production environments. |
......@@ -543,7 +543,7 @@ If everything looks good, you should be able to reach GitLab in your browser.
### Setting up Gitaly
CAUTION: **Caution:** In this architecture, having a single Gitaly server creates a single point of failure. This limitation will be removed once [Gitaly HA](https://gitlab.com/groups/gitlab-org/-/epics/842) is released.
CAUTION: **Caution:** In this architecture, having a single Gitaly server creates a single point of failure. This limitation will be removed once [Gitaly HA](https://gitlab.com/groups/gitlab-org/-/epics/842) is released.
Gitaly is a service that provides high-level RPC access to Git repositories.
It should be enabled and configured on a separate EC2 instance in one of the
......
......@@ -54,7 +54,7 @@ The way you install the Go indexer depends on your version of GitLab:
### GitLab Omnibus
Since GitLab 11.8 the Go indexer is included in GitLab Omnibus.
Since GitLab 11.8 the Go indexer is included in GitLab Omnibus.
The former Ruby-based indexer was removed in [GitLab 12.3](https://gitlab.com/gitlab-org/gitlab/issues/6481).
### From source
......
......@@ -21,7 +21,7 @@ You accept and agree to the following terms and conditions for Your present and
- **Contributions:**
You represent that each of Your Contributions is Your original creation.
Should You wish to submit work that is not Your original creation, You may submit it to GitLab B.V. separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: (named here)".
You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
......
......@@ -71,16 +71,24 @@ use IDNA encoding.
The whitelist can hold a maximum of 1000 entries. Each entry can be a maximum of
255 characters.
You can whitelist a particular port by specifying it in the whitelist entry.
For example `127.0.0.1:8080` will only allow connections to port 8080 on `127.0.0.1`.
If no port is mentioned, all ports on that IP/domain are whitelisted. An IP range
will whitelist all ports on all IPs in that range.
Example:
```text
example.com;gitlab.example.com
127.0.0.1,1:0:0:0:0:0:0:1
127.0.0.0/8 1:0:0:0:0:0:0:0/124
[1:0:0:0:0:0:0:1]:8080
127.0.0.1:8080
example.com:8080
```
NOTE: **Note:**
Wildcards (`*.example.com`) and ports (`127.0.0.1:3000`) are not currently supported.
Wildcards (`*.example.com`) are not currently supported.
<!-- ## Troubleshooting
......
......@@ -389,7 +389,7 @@ To purchase additional minutes for your personal namespace:
1. Click your avatar, then go to **Settings > Pipeline quota**.
1. Locate the subscription card that's linked to your personal namespace on GitLab.com, click **Buy more CI minutes**, and complete the details about the transaction. Once we have processed your payment, the extra CI minutes will be synced to your Group.
1. To confirm the available CI minutes for your personal projects, click your avatar, then go to **Settings > Pipeline quota**.
1. To confirm the available CI minutes for your personal projects, click your avatar, then go to **Settings > Pipeline quota**.
The **Additional minutes** displayed now includes the purchased additional CI minutes, plus any minutes rolled over from last month.
Be aware that:
......
......@@ -253,7 +253,7 @@ In our example we will end up with commit `B`, that introduced bug/error. We hav
- Undo changes on a single file or directory from commit `B`, but retain them in the unstaged state:
```shell
git reset commit-B-id <file>
git reset commit-B-id <file>
```
- There is one command we also must not forget: **creating a new branch**
......@@ -487,8 +487,8 @@ git filter-branch --tree-filter 'rm filename' HEAD
Since `git filter-branch` command might be slow on big repositories, there are
tools that can use some of Git specifics to enable faster execution of common
tasks (which is exactly what removing sensitive information file is about).
An alternative is the open source community-maintained tool [BFG][bfg-repo-cleaner].
Keep in mind that these tools are faster because they do not provide the same
An alternative is the open source community-maintained tool [BFG][bfg-repo-cleaner].
Keep in mind that these tools are faster because they do not provide the same
feature set as `git filter-branch` does, but focus on specific use cases.
## Conclusion
......
......@@ -180,18 +180,6 @@ These are shortcuts to your last 4 visited boards.
When you're revisiting an issue board in a project or group with multiple boards,
GitLab will automatically load the last board you visited.
### Multi-select Issue Cards
As the name suggest, multi-select issue cards allows more than one issue card
to be dragged and dropped across different lists. This becomes helpful while
moving and grooming a lot of issues at once.
You can multi-select an issue card by pressing `CTRL` + `Left mouse click` on
Windows or `CMD` + `Left mouse click` on MacOS. Once done, start by dragging one
of the issue card you have selected and drop it in the new list you want.
![Multi-select Issue Cards](img/issue_boards_multi_select.png)
### Configurable Issue Boards **(STARTER)**
> Introduced in [GitLab Starter Edition 10.2](https://about.gitlab.com/releases/2017/11/22/gitlab-10-2-released/#issue-boards-configuration).
......@@ -467,6 +455,19 @@ When dragging issues between lists, different behavior occurs depending on the s
| From label `A` list | `A` removed | Issue closed | `A` removed<br/>`B` added | `Bob` assigned |
| From assignee `Alice` list | `Alice` unassigned | Issue closed | `B` added | `Alice` unassigned<br/>`Bob` assigned |
### Multi-select issue cards
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/18954) in GitLab 12.4.
You can select multiple issue cards, then drag the group to another position within the list, or to another list. This makes it faster to reorder many issues at once.
To select and move multiple cards:
1. Select each card with <kbd>Ctrl</kbd>+`Click` on Windows or Linux, or <kbd>Cmd</kbd>+`Click` on MacOS.
1. Drag one of the selected cards to another position or list and all selected cards will be moved.
![Multi-select Issue Cards](img/issue_boards_multi_select_v12_4.png)
## Tips
A few things to remember:
......
......@@ -19,7 +19,7 @@ Unfortunately, it's not so easy and that workflow won't work. Deleting files in
a commit doesn't actually reduce the size of the repo since the earlier commits
and blobs are still around. What you need to do is rewrite history with Git's
[`filter-branch` option](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#The-Nuclear-Option:-filter-branch),
or an open source community-maintained tool like the
or an open source community-maintained tool like the
[BFG](https://rtyley.github.io/bfg-repo-cleaner/).
Note that even with that method, until `git gc` runs on the GitLab side, the
......
......@@ -49,7 +49,7 @@ module Gitlab
return [uri, nil] unless address_info
ip_address = ip_address(address_info)
return [uri, nil] if domain_whitelisted?(uri) || ip_whitelisted?(ip_address)
return [uri, nil] if domain_whitelisted?(uri) || ip_whitelisted?(ip_address, port: get_port(uri))
protected_uri_with_hostname = enforce_uri_hostname(ip_address, uri, dns_rebind_protection)
......@@ -254,11 +254,11 @@ module Gitlab
end
def domain_whitelisted?(uri)
Gitlab::UrlBlockers::UrlWhitelist.domain_whitelisted?(uri.normalized_host)
Gitlab::UrlBlockers::UrlWhitelist.domain_whitelisted?(uri.normalized_host, port: get_port(uri))
end
def ip_whitelisted?(ip_address)
Gitlab::UrlBlockers::UrlWhitelist.ip_whitelisted?(ip_address)
def ip_whitelisted?(ip_address, port: nil)
Gitlab::UrlBlockers::UrlWhitelist.ip_whitelisted?(ip_address, port: port)
end
def config
......
# frozen_string_literal: true
module Gitlab
module UrlBlockers
class DomainWhitelistEntry
attr_reader :domain, :port
def initialize(domain, port: nil)
@domain = domain
@port = port
end
def match?(requested_domain, requested_port = nil)
return false unless domain == requested_domain
return true if port.nil?
port == requested_port
end
end
end
end
# frozen_string_literal: true
module Gitlab
module UrlBlockers
class IpWhitelistEntry
attr_reader :ip, :port
# Argument ip should be an IPAddr object
def initialize(ip, port: nil)
@ip = ip
@port = port
end
def match?(requested_ip, requested_port = nil)
return false unless ip.include?(requested_ip)
return true if port.nil?
port == requested_port
end
end
end
end
......@@ -4,21 +4,25 @@ module Gitlab
module UrlBlockers
class UrlWhitelist
class << self
def ip_whitelisted?(ip_string)
def ip_whitelisted?(ip_string, port: nil)
return false if ip_string.blank?
ip_whitelist, _ = outbound_local_requests_whitelist_arrays
ip_obj = Gitlab::Utils.string_to_ip_object(ip_string)
ip_whitelist.any? { |ip| ip.include?(ip_obj) }
ip_whitelist.any? do |ip_whitelist_entry|
ip_whitelist_entry.match?(ip_obj, port)
end
end
def domain_whitelisted?(domain_string)
def domain_whitelisted?(domain_string, port: nil)
return false if domain_string.blank?
_, domain_whitelist = outbound_local_requests_whitelist_arrays
domain_whitelist.include?(domain_string)
domain_whitelist.any? do |domain_whitelist_entry|
domain_whitelist_entry.match?(domain_string, port)
end
end
private
......
......@@ -501,6 +501,18 @@ describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
it_behaves_like 'dns rebinding checks'
end
end
context 'with ports' do
let(:whitelist) do
["127.0.0.1:2000"]
end
it 'allows domain with port when resolved ip has port whitelisted' do
stub_domain_resolv("www.resolve-domain.com", '127.0.0.1') do
expect(described_class).not_to be_blocked_url("http://www.resolve-domain.com:2000", url_blocker_attributes)
end
end
end
end
end
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::UrlBlockers::DomainWhitelistEntry do
let(:domain) { 'www.example.com' }
describe '#initialize' do
it 'initializes without port' do
domain_whitelist_entry = described_class.new(domain)
expect(domain_whitelist_entry.domain).to eq(domain)
expect(domain_whitelist_entry.port).to be(nil)
end
it 'initializes with port' do
port = 8080
domain_whitelist_entry = described_class.new(domain, port: port)
expect(domain_whitelist_entry.domain).to eq(domain)
expect(domain_whitelist_entry.port).to eq(port)
end
end
describe '#match?' do
it 'matches when domain and port are equal' do
port = 8080
domain_whitelist_entry = described_class.new(domain, port: port)
expect(domain_whitelist_entry).to be_match(domain, port)
end
it 'matches any port when port is nil' do
domain_whitelist_entry = described_class.new(domain)
expect(domain_whitelist_entry).to be_match(domain, 8080)
expect(domain_whitelist_entry).to be_match(domain, 9090)
end
it 'does not match when port is present but requested_port is nil' do
domain_whitelist_entry = described_class.new(domain, port: 8080)
expect(domain_whitelist_entry).not_to be_match(domain, nil)
end
it 'matches when port and requested_port are nil' do
domain_whitelist_entry = described_class.new(domain)
expect(domain_whitelist_entry).to be_match(domain)
end
it 'does not match if domain is not equal' do
domain_whitelist_entry = described_class.new(domain)
expect(domain_whitelist_entry).not_to be_match('www.gitlab.com', 8080)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::UrlBlockers::IpWhitelistEntry do
let(:ipv4) { IPAddr.new('192.168.1.1') }
describe '#initialize' do
it 'initializes without port' do
ip_whitelist_entry = described_class.new(ipv4)
expect(ip_whitelist_entry.ip).to eq(ipv4)
expect(ip_whitelist_entry.port).to be(nil)
end
it 'initializes with port' do
port = 8080
ip_whitelist_entry = described_class.new(ipv4, port: port)
expect(ip_whitelist_entry.ip).to eq(ipv4)
expect(ip_whitelist_entry.port).to eq(port)
end
end
describe '#match?' do
it 'matches with equivalent IP and port' do
port = 8080
ip_whitelist_entry = described_class.new(ipv4, port: port)
expect(ip_whitelist_entry).to be_match(ipv4.to_s, port)
end
it 'matches any port when port is nil' do
ip_whitelist_entry = described_class.new(ipv4)
expect(ip_whitelist_entry).to be_match(ipv4.to_s, 8080)
expect(ip_whitelist_entry).to be_match(ipv4.to_s, 9090)
end
it 'does not match when port is present but requested_port is nil' do
ip_whitelist_entry = described_class.new(ipv4, port: 8080)
expect(ip_whitelist_entry).not_to be_match(ipv4.to_s, nil)
end
it 'matches when port and requested_port are nil' do
ip_whitelist_entry = described_class.new(ipv4)
expect(ip_whitelist_entry).to be_match(ipv4.to_s)
end
it 'works with ipv6' do
ipv6 = IPAddr.new('fe80::c800:eff:fe74:8')
ip_whitelist_entry = described_class.new(ipv6)
expect(ip_whitelist_entry).to be_match(ipv6.to_s, 8080)
end
it 'matches ipv4 within IPv4 range' do
ipv4_range = IPAddr.new('127.0.0.0/28')
ip_whitelist_entry = described_class.new(ipv4_range)
expect(ip_whitelist_entry).to be_match(ipv4_range.to_range.last.to_s, 8080)
expect(ip_whitelist_entry).not_to be_match('127.0.1.1', 8080)
end
it 'matches IPv6 within IPv6 range' do
ipv6_range = IPAddr.new('fd84:6d02:f6d8:c89e::/124')
ip_whitelist_entry = described_class.new(ipv6_range)
expect(ip_whitelist_entry).to be_match(ipv6_range.to_range.last.to_s, 8080)
expect(ip_whitelist_entry).not_to be_match('fd84:6d02:f6d8:f::f', 8080)
end
end
end
......@@ -13,20 +13,17 @@ describe Gitlab::UrlBlockers::UrlWhitelist do
end
describe '#domain_whitelisted?' do
let(:whitelist) do
[
'www.example.com',
'example.com'
]
end
let(:whitelist) { ['www.example.com', 'example.com'] }
it 'returns true if domains present in whitelist' do
not_whitelisted = ['subdomain.example.com', 'example.org']
aggregate_failures do
whitelist.each do |domain|
expect(described_class).to be_domain_whitelisted(domain)
end
['subdomain.example.com', 'example.org'].each do |domain|
not_whitelisted.each do |domain|
expect(described_class).not_to be_domain_whitelisted(domain)
end
end
......@@ -35,6 +32,28 @@ describe Gitlab::UrlBlockers::UrlWhitelist do
it 'returns false when domain is blank' do
expect(described_class).not_to be_domain_whitelisted(nil)
end
context 'with ports' do
let(:whitelist) { ['example.io:3000'] }
it 'returns true if domain and ports present in whitelist' do
parsed_whitelist = [['example.io', { port: 3000 }]]
not_whitelisted = [
'example.io',
['example.io', { port: 3001 }]
]
aggregate_failures do
parsed_whitelist.each do |domain_and_port|
expect(described_class).to be_domain_whitelisted(*domain_and_port)
end
not_whitelisted.each do |domain_and_port|
expect(described_class).not_to be_domain_whitelisted(*domain_and_port)
end
end
end
end
end
describe '#ip_whitelisted?' do
......@@ -114,5 +133,32 @@ describe Gitlab::UrlBlockers::UrlWhitelist do
expect(described_class).not_to be_ip_whitelisted("127.0.1.15")
end
end
context 'with ports' do
let(:whitelist) { ['127.0.0.9:3000', '[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443'] }
it 'returns true if ip and ports present in whitelist' do
parsed_whitelist = [
['127.0.0.9', { port: 3000 }],
['[2001:db8:85a3:8d3:1319:8a2e:370:7348]', { port: 443 }]
]
not_whitelisted = [
'127.0.0.9',
['127.0.0.9', { port: 3001 }],
'[2001:db8:85a3:8d3:1319:8a2e:370:7348]',
['[2001:db8:85a3:8d3:1319:8a2e:370:7348]', { port: 3001 }]
]
aggregate_failures do
parsed_whitelist.each do |ip_and_port|
expect(described_class).to be_ip_whitelisted(*ip_and_port)
end
not_whitelisted.each do |ip_and_port|
expect(described_class).not_to be_ip_whitelisted(*ip_and_port)
end
end
end
end
end
end
......@@ -2,37 +2,6 @@
# Construct an `uploader` variable that is configured to `check_upload_type`
# with `mime_types` and `extensions`.
RSpec.shared_context 'uploader with type check' do
let(:uploader_class) do
Class.new(GitlabUploader) do
include UploadTypeCheck::Concern
storage :file
end
end
let(:mime_types) { nil }
let(:extensions) { nil }
let(:uploader) do
uploader_class.class_exec(mime_types, extensions) do |mime_types, extensions|
check_upload_type mime_types: mime_types, extensions: extensions
end
uploader_class.new(build_stubbed(:user))
end
end
# This works with the UploadTypeCheck::Concern
RSpec.shared_context 'stubbed MimeMagic mime type detection' do
let(:mime_type) { '' }
let(:magic_mime) { mime_type }
let(:ext_mime) { mime_type }
before do
magic_mime_obj = MimeMagic.new(magic_mime)
ext_mime_obj = MimeMagic.new(ext_mime)
allow(MimeMagic).to receive(:by_magic).with(anything).and_return(magic_mime_obj)
allow(MimeMagic).to receive(:by_path).with(anything).and_return(ext_mime_obj)
end
end
# @param uploader [CarrierWave::Uploader::Base] uploader with extension_whitelist method.
RSpec.shared_context 'ignore extension whitelist check' do
before do
......
......@@ -68,12 +68,12 @@ RSpec.shared_examples 'application settings examples' do
setting.outbound_local_requests_whitelist_raw = 'example.com'
expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(
[], ['example.com']
[], [an_object_having_attributes(domain: 'example.com')]
)
setting.outbound_local_requests_whitelist_raw = 'gitlab.com'
expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(
[], ['gitlab.com']
[], [an_object_having_attributes(domain: 'gitlab.com')]
)
end
end
......@@ -81,15 +81,42 @@ RSpec.shared_examples 'application settings examples' do
context 'outbound_local_requests_whitelist_arrays' do
it 'separates the IPs and domains' do
setting.outbound_local_requests_whitelist = [
'192.168.1.1', '127.0.0.0/28', 'www.example.com', 'example.com',
'::ffff:a00:2', '1:0:0:0:0:0:0:0/124', 'subdomain.example.com'
'192.168.1.1',
'127.0.0.0/28',
'::ffff:a00:2',
'1:0:0:0:0:0:0:0/124',
'example.com',
'subdomain.example.com',
'www.example.com',
'::',
'1::',
'::1',
'1:2:3:4:5::7:8',
'[1:2:3:4:5::7:8]',
'[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443',
'www.example2.com:8080',
'example.com:8080'
]
ip_whitelist = [
IPAddr.new('192.168.1.1'), IPAddr.new('127.0.0.0/8'),
IPAddr.new('::ffff:a00:2'), IPAddr.new('1:0:0:0:0:0:0:0/124')
an_object_having_attributes(ip: IPAddr.new('192.168.1.1')),
an_object_having_attributes(ip: IPAddr.new('127.0.0.0/8')),
an_object_having_attributes(ip: IPAddr.new('::ffff:a00:2')),
an_object_having_attributes(ip: IPAddr.new('1:0:0:0:0:0:0:0/124')),
an_object_having_attributes(ip: IPAddr.new('::')),
an_object_having_attributes(ip: IPAddr.new('1::')),
an_object_having_attributes(ip: IPAddr.new('::1')),
an_object_having_attributes(ip: IPAddr.new('1:2:3:4:5::7:8')),
an_object_having_attributes(ip: IPAddr.new('[1:2:3:4:5::7:8]')),
an_object_having_attributes(ip: IPAddr.new('[2001:db8:85a3:8d3:1319:8a2e:370:7348]'), port: 443)
]
domain_whitelist = [
an_object_having_attributes(domain: 'example.com'),
an_object_having_attributes(domain: 'subdomain.example.com'),
an_object_having_attributes(domain: 'www.example.com'),
an_object_having_attributes(domain: 'www.example2.com', port: 8080),
an_object_having_attributes(domain: 'example.com', port: 8080)
]
domain_whitelist = ['www.example.com', 'example.com', 'subdomain.example.com']
expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(
ip_whitelist, domain_whitelist
......@@ -117,7 +144,7 @@ RSpec.shared_examples 'application settings examples' do
expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(
[],
['example.com']
[an_object_having_attributes(domain: 'example.com')]
)
setting.add_to_outbound_local_requests_whitelist(
......@@ -126,7 +153,7 @@ RSpec.shared_examples 'application settings examples' do
expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(
[],
['example.com', 'gitlab.com']
[an_object_having_attributes(domain: 'example.com'), an_object_having_attributes(domain: 'gitlab.com')]
)
end
......@@ -137,7 +164,7 @@ RSpec.shared_examples 'application settings examples' do
expect(setting.outbound_local_requests_whitelist).to contain_exactly('gitlab.com')
expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(
[], ['gitlab.com']
[], [an_object_having_attributes(domain: 'gitlab.com')]
)
end
......
......@@ -26,67 +26,3 @@ shared_examples 'accepted carrierwave upload' do
expect { uploader.cache!(fixture_file) }.to change { uploader.file }.from(nil).to(kind_of(CarrierWave::SanitizedFile))
end
end
def check_content_matches_extension!(file = double(read: nil, path: ''))
magic_file = UploadTypeCheck::MagicFile.new(file)
uploader.check_content_matches_extension!(magic_file)
end
RSpec.shared_examples 'upload passes content type check' do
it 'does not raise error' do
expect { check_content_matches_extension! }.not_to raise_error
end
end
RSpec.shared_examples 'upload fails content type check' do
it 'raises error' do
expect { check_content_matches_extension! }.to raise_error(CarrierWave::IntegrityError)
end
end
def upload_type_checked_filenames(filenames)
Array(filenames).each do |filename|
# Feed the uploader "some" content.
path = File.join('spec', 'fixtures', 'dk.png')
file = File.new(path, 'r')
# Rename the file with what we want.
allow(file).to receive(:path).and_return(filename)
# Force the content type to match the extension type.
mime_type = MimeMagic.by_path(filename)
allow(MimeMagic).to receive(:by_magic).and_return(mime_type)
uploaded_file = Rack::Test::UploadedFile.new(file, original_filename: filename)
uploader.cache!(uploaded_file)
end
end
def upload_type_checked_fixtures(upload_fixtures)
upload_fixtures = Array(upload_fixtures)
upload_fixtures.each do |upload_fixture|
path = File.join('spec', 'fixtures', upload_fixture)
uploader.cache!(fixture_file_upload(path))
end
end
RSpec.shared_examples 'type checked uploads' do |upload_fixtures = nil, filenames: nil|
it 'check type' do
upload_fixtures = Array(upload_fixtures)
filenames = Array(filenames)
times = upload_fixtures.length + filenames.length
expect(uploader).to receive(:check_content_matches_extension!).exactly(times).times
upload_type_checked_fixtures(upload_fixtures) unless upload_fixtures.empty?
upload_type_checked_filenames(filenames) unless filenames.empty?
end
end
RSpec.shared_examples 'skipped type checked uploads' do |upload_fixtures = nil, filenames: nil|
it 'skip type check' do
expect(uploader).not_to receive(:check_content_matches_extension!)
upload_type_checked_fixtures(upload_fixtures) if upload_fixtures
upload_type_checked_filenames(filenames) if filenames
end
end
# frozen_string_literal: true
require 'spec_helper'
describe UploadTypeCheck do
include_context 'uploader with type check'
def upload_fixture(filename)
fixture_file_upload(File.join('spec', 'fixtures', filename))
end
describe '#check_content_matches_extension! callback using file upload' do
context 'when extension matches contents' do
it 'not raise error on upload' do
expect { uploader.cache!(upload_fixture('banana_sample.gif')) }.not_to raise_error
end
end
context 'when extension does not match contents' do
it 'raise error' do
expect { uploader.cache!(upload_fixture('not_a_png.png')) }.to raise_error(CarrierWave::IntegrityError)
end
end
end
describe '#check_content_matches_extension! callback using stubs' do
include_context 'stubbed MimeMagic mime type detection'
context 'when no extension and with ambiguous/text content' do
let(:magic_mime) { '' }
let(:ext_mime) { '' }
it_behaves_like 'upload passes content type check'
end
context 'when no extension and with non-text content' do
let(:magic_mime) { 'image/gif' }
let(:ext_mime) { '' }
it_behaves_like 'upload fails content type check'
end
# Most text files will exhibit this behaviour.
context 'when ambiguous content with text extension' do
let(:magic_mime) { '' }
let(:ext_mime) { 'text/plain' }
it_behaves_like 'upload passes content type check'
end
context 'when text content with text extension' do
let(:magic_mime) { 'text/plain' }
let(:ext_mime) { 'text/plain' }
it_behaves_like 'upload passes content type check'
end
context 'when ambiguous content with non-text extension' do
let(:magic_mime) { '' }
let(:ext_mime) { 'application/zip' }
it_behaves_like 'upload fails content type check'
end
# These are the types when uploading a .dmg
context 'when content and extension do not match' do
let(:magic_mime) { 'application/x-bzip' }
let(:ext_mime) { 'application/x-apple-diskimage' }
it_behaves_like 'upload fails content type check'
end
end
describe '#check_content_matches_extension! mime_type filtering' do
context 'without mime types' do
let(:mime_types) { nil }
it_behaves_like 'type checked uploads', %w[doc_sample.txt rails_sample.jpg]
end
context 'with mime types string' do
let(:mime_types) { 'text/plain' }
it_behaves_like 'type checked uploads', %w[doc_sample.txt]
it_behaves_like 'skipped type checked uploads', %w[dk.png]
end
context 'with mime types regex' do
let(:mime_types) { [/image\/(gif|png)/] }
it_behaves_like 'type checked uploads', %w[banana_sample.gif dk.png]
it_behaves_like 'skipped type checked uploads', %w[doc_sample.txt]
end
context 'with mime types array' do
let(:mime_types) { ['text/plain', /image\/png/] }
it_behaves_like 'type checked uploads', %w[doc_sample.txt dk.png]
it_behaves_like 'skipped type checked uploads', %w[audio_sample.wav]
end
end
describe '#check_content_matches_extension! extensions filtering' do
context 'without extensions' do
let(:extensions) { nil }
it_behaves_like 'type checked uploads', %w[doc_sample.txt dk.png]
end
context 'with extensions string' do
let(:extensions) { 'txt' }
it_behaves_like 'type checked uploads', %w[doc_sample.txt]
it_behaves_like 'skipped type checked uploads', %w[rails_sample.jpg]
end
context 'with extensions array of strings' do
let(:extensions) { %w[txt png] }
it_behaves_like 'type checked uploads', %w[doc_sample.txt dk.png]
it_behaves_like 'skipped type checked uploads', %w[audio_sample.wav]
end
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