New upstream version 15.6.8+ds1
This commit is contained in:
parent
aef0f23401
commit
13ea837db1
36 changed files with 846 additions and 432 deletions
|
@ -77,6 +77,8 @@ workflow:
|
||||||
when: never
|
when: never
|
||||||
# For stable, auto-deploy, and security branches, create a pipeline.
|
# For stable, auto-deploy, and security branches, create a pipeline.
|
||||||
- if: '$CI_COMMIT_BRANCH =~ /^[\d-]+-stable(-ee)?$/'
|
- if: '$CI_COMMIT_BRANCH =~ /^[\d-]+-stable(-ee)?$/'
|
||||||
|
variables:
|
||||||
|
NOTIFY_PIPELINE_FAILURE_CHANNEL: "releases"
|
||||||
- if: '$CI_COMMIT_BRANCH =~ /^\d+-\d+-auto-deploy-\d+$/'
|
- if: '$CI_COMMIT_BRANCH =~ /^\d+-\d+-auto-deploy-\d+$/'
|
||||||
- if: '$CI_COMMIT_BRANCH =~ /^security\//'
|
- if: '$CI_COMMIT_BRANCH =~ /^security\//'
|
||||||
|
|
||||||
|
|
19
CHANGELOG.md
19
CHANGELOG.md
|
@ -2,6 +2,25 @@
|
||||||
documentation](doc/development/changelog.md) for instructions on adding your own
|
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||||
entry.
|
entry.
|
||||||
|
|
||||||
|
## 15.6.8 (2023-02-10)
|
||||||
|
|
||||||
|
No changes.
|
||||||
|
|
||||||
|
## 15.6.7 (2023-01-30)
|
||||||
|
|
||||||
|
### Fixed (2 changes)
|
||||||
|
|
||||||
|
- [Clear DuplicateJobs cookies from post-deployment migration](gitlab-org/security/gitlab@9071bc623c81f4ecbccb63bcfc78d6d503421e2b)
|
||||||
|
- [Geo: Container Repository push events don't work](gitlab-org/security/gitlab@00ca7dd923444da0b19afa7d72d5e3b505889290)
|
||||||
|
|
||||||
|
### Security (5 changes)
|
||||||
|
|
||||||
|
- [Quarantine features/users/login_spec line 292 [15.6]](gitlab-org/security/gitlab@d202f35e1cac8df0bcbb5d40d42cea2312c09762) ([merge request](gitlab-org/security/gitlab!3025))
|
||||||
|
- [Add size validation for Chart.yaml during file extraction](gitlab-org/security/gitlab@59df02bf2658468f9f254c34ed009a6414d6c6b3) ([merge request](gitlab-org/security/gitlab!3020))
|
||||||
|
- [Prevent default branches from storing paths](gitlab-org/security/gitlab@b7b402a0a37bb839b601569a035a62fe79febe72) ([merge request](gitlab-org/security/gitlab!3013))
|
||||||
|
- [Validate Issuable description max length on update](gitlab-org/security/gitlab@fa68365e853a5701b217ccafea9885705d4a4133) ([merge request](gitlab-org/security/gitlab!3002))
|
||||||
|
- [Security fix dynamic child pipeline zip extraction](gitlab-org/security/gitlab@2285d716f10f33d8dbea5112de95d9d7e5cd8b00) ([merge request](gitlab-org/security/gitlab!2981))
|
||||||
|
|
||||||
## 15.6.6 (2023-01-12)
|
## 15.6.6 (2023-01-12)
|
||||||
|
|
||||||
No changes.
|
No changes.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
15.6.6
|
15.6.8
|
|
@ -1 +1 @@
|
||||||
15.6.6
|
15.6.8
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
15.6.6
|
15.6.8
|
|
@ -92,10 +92,9 @@ module Issuable
|
||||||
|
|
||||||
validates :author, presence: true
|
validates :author, presence: true
|
||||||
validates :title, presence: true, length: { maximum: TITLE_LENGTH_MAX }
|
validates :title, presence: true, length: { maximum: TITLE_LENGTH_MAX }
|
||||||
# we validate the description against DESCRIPTION_LENGTH_MAX only for Issuables being created
|
# we validate the description against DESCRIPTION_LENGTH_MAX only for Issuables being created and on updates if
|
||||||
# to avoid breaking the existing Issuables which may have their descriptions longer
|
# the description changes to avoid breaking the existing Issuables which may have their descriptions longer
|
||||||
validates :description, length: { maximum: DESCRIPTION_LENGTH_MAX }, allow_blank: true, on: :create
|
validates :description, bytesize: { maximum: -> { DESCRIPTION_LENGTH_MAX } }, if: :validate_description_length?
|
||||||
validate :description_max_length_for_new_records_is_valid, on: :update
|
|
||||||
validate :validate_assignee_size_length, unless: :importing?
|
validate :validate_assignee_size_length, unless: :importing?
|
||||||
|
|
||||||
before_validation :truncate_description_on_import!
|
before_validation :truncate_description_on_import!
|
||||||
|
@ -229,10 +228,14 @@ module Issuable
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def description_max_length_for_new_records_is_valid
|
def validate_description_length?
|
||||||
if new_record? && description.length > Issuable::DESCRIPTION_LENGTH_MAX
|
return false unless description_changed?
|
||||||
errors.add(:description, :too_long, count: Issuable::DESCRIPTION_LENGTH_MAX)
|
|
||||||
end
|
previous_description = changes['description'].first
|
||||||
|
# previous_description will be nil for new records
|
||||||
|
return true if previous_description.blank?
|
||||||
|
|
||||||
|
previous_description.bytesize <= DESCRIPTION_LENGTH_MAX
|
||||||
end
|
end
|
||||||
|
|
||||||
def truncate_description_on_import!
|
def truncate_description_on_import!
|
||||||
|
|
|
@ -45,6 +45,15 @@ module Sanitizable
|
||||||
unless input.to_s == CGI.unescapeHTML(input.to_s)
|
unless input.to_s == CGI.unescapeHTML(input.to_s)
|
||||||
record.errors.add(attr, 'cannot contain escaped HTML entities')
|
record.errors.add(attr, 'cannot contain escaped HTML entities')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This method raises an exception on failure so perform this
|
||||||
|
# last if multiple errors should be returned.
|
||||||
|
Gitlab::Utils.check_path_traversal!(input.to_s)
|
||||||
|
|
||||||
|
rescue Gitlab::Utils::DoubleEncodingError
|
||||||
|
record.errors.add(attr, 'cannot contain escaped components')
|
||||||
|
rescue Gitlab::Utils::PathTraversalAttackError
|
||||||
|
record.errors.add(attr, "cannot contain a path traversal component")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,10 +14,11 @@ class NamespaceSetting < ApplicationRecord
|
||||||
|
|
||||||
validates :enabled_git_access_protocol, inclusion: { in: enabled_git_access_protocols.keys }
|
validates :enabled_git_access_protocol, inclusion: { in: enabled_git_access_protocols.keys }
|
||||||
|
|
||||||
validate :default_branch_name_content
|
|
||||||
validate :allow_mfa_for_group
|
validate :allow_mfa_for_group
|
||||||
validate :allow_resource_access_token_creation_for_group
|
validate :allow_resource_access_token_creation_for_group
|
||||||
|
|
||||||
|
sanitizes! :default_branch_name
|
||||||
|
|
||||||
before_validation :normalize_default_branch_name
|
before_validation :normalize_default_branch_name
|
||||||
|
|
||||||
chronic_duration_attr :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval
|
chronic_duration_attr :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval
|
||||||
|
@ -45,8 +46,6 @@ class NamespaceSetting < ApplicationRecord
|
||||||
NAMESPACE_SETTINGS_PARAMS
|
NAMESPACE_SETTINGS_PARAMS
|
||||||
end
|
end
|
||||||
|
|
||||||
sanitizes! :default_branch_name
|
|
||||||
|
|
||||||
def prevent_sharing_groups_outside_hierarchy
|
def prevent_sharing_groups_outside_hierarchy
|
||||||
return super if namespace.root?
|
return super if namespace.root?
|
||||||
|
|
||||||
|
@ -69,14 +68,6 @@ class NamespaceSetting < ApplicationRecord
|
||||||
self.default_branch_name = default_branch_name.presence
|
self.default_branch_name = default_branch_name.presence
|
||||||
end
|
end
|
||||||
|
|
||||||
def default_branch_name_content
|
|
||||||
return if default_branch_name.nil?
|
|
||||||
|
|
||||||
if default_branch_name.blank?
|
|
||||||
errors.add(:default_branch_name, "can not be an empty string")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def allow_mfa_for_group
|
def allow_mfa_for_group
|
||||||
if namespace&.subgroup? && allow_mfa_for_subgroups == false
|
if namespace&.subgroup? && allow_mfa_for_subgroups == false
|
||||||
errors.add(:allow_mfa_for_subgroups, _('is not allowed since the group is not top-level group.'))
|
errors.add(:allow_mfa_for_subgroups, _('is not allowed since the group is not top-level group.'))
|
||||||
|
|
|
@ -7,6 +7,10 @@ module Packages
|
||||||
class ExtractFileMetadataService
|
class ExtractFileMetadataService
|
||||||
ExtractionError = Class.new(StandardError)
|
ExtractionError = Class.new(StandardError)
|
||||||
|
|
||||||
|
# Charts must be smaller than 1M because of the storage limitations of Kubernetes objects.
|
||||||
|
# based on https://helm.sh/docs/chart_template_guide/accessing_files/
|
||||||
|
MAX_FILE_SIZE = 1.megabytes.freeze
|
||||||
|
|
||||||
def initialize(package_file)
|
def initialize(package_file)
|
||||||
@package_file = package_file
|
@package_file = package_file
|
||||||
end
|
end
|
||||||
|
@ -42,6 +46,7 @@ module Packages
|
||||||
end
|
end
|
||||||
|
|
||||||
raise ExtractionError, 'Chart.yaml not found within a directory' unless chart_yaml
|
raise ExtractionError, 'Chart.yaml not found within a directory' unless chart_yaml
|
||||||
|
raise ExtractionError, 'Chart.yaml too big' if chart_yaml.size > MAX_FILE_SIZE
|
||||||
|
|
||||||
chart_yaml.read
|
chart_yaml.read
|
||||||
ensure
|
ensure
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# This is workaround for
|
||||||
|
# https://gitlab.com/gitlab-org/gitlab/-/issues/388253. During a
|
||||||
|
# zero-downtime upgrade, duplicate jobs cookies can fail to get deleted.
|
||||||
|
# This post-deployment migration deletes all such cookies. This can
|
||||||
|
# cause some jobs that normally would have been deduplicated to twice
|
||||||
|
# instead of once.
|
||||||
|
class ClearDuplicateJobsCookies < Gitlab::Database::Migration[2.0]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||||
|
|
||||||
|
def up
|
||||||
|
Gitlab::Redis::Queues.with do |redis| # rubocop:disable Cop/RedisQueueUsage
|
||||||
|
redis.scan_each(match: "resque:gitlab:duplicate:*:cookie:v2").each_slice(100) do |keys|
|
||||||
|
redis.del(keys)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down; end
|
||||||
|
end
|
1
db/schema_migrations/20230117114739
Normal file
1
db/schema_migrations/20230117114739
Normal file
|
@ -0,0 +1 @@
|
||||||
|
f4ba0d1de73da2b7a912c06ca458898f3404235025089efc74aee9fc4caa511a
|
|
@ -441,13 +441,27 @@ def default_min_key_size(name)
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
## Nightly Omnibus FIPS builds
|
## Omnibus FIPS packages
|
||||||
|
|
||||||
The Distribution team has created [nightly FIPS Omnibus builds](https://packages.gitlab.com/gitlab/nightly-fips-builds). These
|
GitLab has a dedicated repository
|
||||||
GitLab builds are compiled to use the system OpenSSL instead of the Omnibus-embedded version of OpenSSL.
|
([`gitlab/gitlab-fips`](https://packages.gitlab.com/gitlab/gitlab-fips))
|
||||||
|
for builds of the Omnibus GitLab which are built with FIPS compliance.
|
||||||
|
These GitLab builds are compiled to use the system OpenSSL, instead of
|
||||||
|
the Omnibus-embedded version of OpenSSL. These packages are built for:
|
||||||
|
|
||||||
|
- RHEL 8 (and compatible)
|
||||||
|
- AmazonLinux 2
|
||||||
|
- Ubuntu
|
||||||
|
|
||||||
|
These are [consumed by the GitLab Environment Toolkit](#install-gitlab-with-fips-compliance) (GET).
|
||||||
|
|
||||||
See [the section on how FIPS builds are created](#how-fips-builds-are-created).
|
See [the section on how FIPS builds are created](#how-fips-builds-are-created).
|
||||||
|
|
||||||
|
### Nightly Omnibus FIPS builds
|
||||||
|
|
||||||
|
The Distribution team has created [nightly FIPS Omnibus builds](https://packages.gitlab.com/gitlab/nightly-fips-builds),
|
||||||
|
which can be used for *testing* purposes. These should never be used for production environments.
|
||||||
|
|
||||||
## Runner
|
## Runner
|
||||||
|
|
||||||
See the [documentation on installing a FIPS-compliant GitLab Runner](https://docs.gitlab.com/runner/install/#fips-compliant-gitlab-runner).
|
See the [documentation on installing a FIPS-compliant GitLab Runner](https://docs.gitlab.com/runner/install/#fips-compliant-gitlab-runner).
|
||||||
|
|
|
@ -29,8 +29,8 @@ module API
|
||||||
end
|
end
|
||||||
params do
|
params do
|
||||||
requires :events, type: Array, desc: 'Event notifications' do
|
requires :events, type: Array, desc: 'Event notifications' do
|
||||||
requires :action, type: String, desc: 'The action to perform, `push`, `delete`',
|
requires :action, type: String, desc: 'The action to perform, `push`, `delete`, `pull`',
|
||||||
values: %w[push delete].freeze
|
values: %w[push delete pull].freeze
|
||||||
optional :target, type: Hash, desc: 'The target of the action' do
|
optional :target, type: Hash, desc: 'The target of the action' do
|
||||||
optional :tag, type: String, desc: 'The target tag'
|
optional :tag, type: String, desc: 'The target tag'
|
||||||
optional :repository, type: String, desc: 'The target repository'
|
optional :repository, type: String, desc: 'The target repository'
|
||||||
|
|
|
@ -9,6 +9,7 @@ module Gitlab
|
||||||
Error = Class.new(StandardError)
|
Error = Class.new(StandardError)
|
||||||
|
|
||||||
MAX_ARCHIVE_SIZE = 5.megabytes
|
MAX_ARCHIVE_SIZE = 5.megabytes
|
||||||
|
TMP_ARTIFACT_EXTRACTION_DIR = "extracted_artifacts_job_%{id}"
|
||||||
|
|
||||||
def initialize(job)
|
def initialize(job)
|
||||||
@job = job
|
@job = job
|
||||||
|
@ -45,20 +46,20 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def read_zip_file!(file_path)
|
def read_zip_file!(file_path)
|
||||||
job.artifacts_file.use_open_file do |file|
|
dir_name = format(TMP_ARTIFACT_EXTRACTION_DIR, id: job.id.to_i)
|
||||||
zip_file = Zip::File.new(file, false, true)
|
|
||||||
entry = zip_file.find_entry(file_path)
|
|
||||||
|
|
||||||
unless entry
|
job.artifacts_file.use_open_file(unlink_early: false) do |tmp_open_file|
|
||||||
raise Error, "Path `#{file_path}` does not exist inside the `#{job.name}` artifacts archive!"
|
Dir.mktmpdir(dir_name) do |tmp_dir|
|
||||||
|
SafeZip::Extract.new(tmp_open_file.file_path).extract(files: [file_path], to: tmp_dir)
|
||||||
|
File.read(File.join(tmp_dir, file_path))
|
||||||
end
|
end
|
||||||
|
|
||||||
if entry.name_is_directory?
|
|
||||||
raise Error, "Path `#{file_path}` was expected to be a file but it was a directory!"
|
|
||||||
end
|
|
||||||
|
|
||||||
zip_file.read(entry)
|
|
||||||
end
|
end
|
||||||
|
rescue SafeZip::Extract::NoMatchingError
|
||||||
|
raise Error, "Path `#{file_path}` does not exist inside the `#{job.name}` artifacts archive!"
|
||||||
|
rescue SafeZip::Extract::EntrySizeError
|
||||||
|
raise Error, "Path `#{file_path}` has invalid size in the zip!"
|
||||||
|
rescue Errno::EISDIR
|
||||||
|
raise Error, "Path `#{file_path}` was expected to be a file but it was a directory!"
|
||||||
end
|
end
|
||||||
|
|
||||||
def max_archive_size_in_mb
|
def max_archive_size_in_mb
|
||||||
|
|
|
@ -4,6 +4,7 @@ module Gitlab
|
||||||
module Utils
|
module Utils
|
||||||
extend self
|
extend self
|
||||||
PathTraversalAttackError ||= Class.new(StandardError)
|
PathTraversalAttackError ||= Class.new(StandardError)
|
||||||
|
DoubleEncodingError ||= Class.new(StandardError)
|
||||||
|
|
||||||
private_class_method def logger
|
private_class_method def logger
|
||||||
@logger ||= Gitlab::AppLogger
|
@logger ||= Gitlab::AppLogger
|
||||||
|
@ -55,7 +56,7 @@ module Gitlab
|
||||||
def decode_path(encoded_path)
|
def decode_path(encoded_path)
|
||||||
decoded = CGI.unescape(encoded_path)
|
decoded = CGI.unescape(encoded_path)
|
||||||
if decoded != CGI.unescape(decoded)
|
if decoded != CGI.unescape(decoded)
|
||||||
raise StandardError, "path #{encoded_path} is not allowed"
|
raise DoubleEncodingError, "path #{encoded_path} is not allowed"
|
||||||
end
|
end
|
||||||
|
|
||||||
decoded
|
decoded
|
||||||
|
|
|
@ -25,8 +25,8 @@ module SafeZip
|
||||||
end
|
end
|
||||||
|
|
||||||
def extract
|
def extract
|
||||||
# do not extract if file is not part of target directory
|
# do not extract if file is not part of target directory or target file
|
||||||
return false unless matching_target_directory
|
return false unless matching_target_directory || matching_target_file
|
||||||
|
|
||||||
# do not overwrite existing file
|
# do not overwrite existing file
|
||||||
raise SafeZip::Extract::AlreadyExistsError, "File already exists #{zip_entry.name}" if exist?
|
raise SafeZip::Extract::AlreadyExistsError, "File already exists #{zip_entry.name}" if exist?
|
||||||
|
@ -44,6 +44,8 @@ module SafeZip
|
||||||
end
|
end
|
||||||
rescue SafeZip::Extract::Error
|
rescue SafeZip::Extract::Error
|
||||||
raise
|
raise
|
||||||
|
rescue Zip::EntrySizeError => e
|
||||||
|
raise SafeZip::Extract::EntrySizeError, e.message
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
raise SafeZip::Extract::ExtractError, e.message
|
raise SafeZip::Extract::ExtractError, e.message
|
||||||
end
|
end
|
||||||
|
@ -84,6 +86,10 @@ module SafeZip
|
||||||
params.matching_target_directory(path)
|
params.matching_target_directory(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def matching_target_file
|
||||||
|
params.matching_target_file(path)
|
||||||
|
end
|
||||||
|
|
||||||
def read_symlink
|
def read_symlink
|
||||||
zip_archive.read(zip_entry)
|
zip_archive.read(zip_entry)
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,6 +6,7 @@ module SafeZip
|
||||||
PermissionDeniedError = Class.new(Error)
|
PermissionDeniedError = Class.new(Error)
|
||||||
SymlinkSourceDoesNotExistError = Class.new(Error)
|
SymlinkSourceDoesNotExistError = Class.new(Error)
|
||||||
UnsupportedEntryError = Class.new(Error)
|
UnsupportedEntryError = Class.new(Error)
|
||||||
|
EntrySizeError = Class.new(Error)
|
||||||
AlreadyExistsError = Class.new(Error)
|
AlreadyExistsError = Class.new(Error)
|
||||||
NoMatchingError = Class.new(Error)
|
NoMatchingError = Class.new(Error)
|
||||||
ExtractError = Class.new(Error)
|
ExtractError = Class.new(Error)
|
||||||
|
|
|
@ -4,11 +4,13 @@ module SafeZip
|
||||||
class ExtractParams
|
class ExtractParams
|
||||||
include Gitlab::Utils::StrongMemoize
|
include Gitlab::Utils::StrongMemoize
|
||||||
|
|
||||||
attr_reader :directories, :extract_path
|
attr_reader :directories, :files, :extract_path
|
||||||
|
|
||||||
def initialize(directories:, to:)
|
def initialize(to:, directories: [], files: [])
|
||||||
@directories = directories
|
@directories = directories
|
||||||
|
@files = files
|
||||||
@extract_path = ::File.realpath(to)
|
@extract_path = ::File.realpath(to)
|
||||||
|
validate!
|
||||||
end
|
end
|
||||||
|
|
||||||
def matching_target_directory(path)
|
def matching_target_directory(path)
|
||||||
|
@ -32,5 +34,23 @@ module SafeZip
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def matching_target_file(path)
|
||||||
|
target_files.include?(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def target_files
|
||||||
|
strong_memoize(:target_files) do
|
||||||
|
files.map do |file|
|
||||||
|
::File.join(extract_path, file)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate!
|
||||||
|
raise ArgumentError, 'Either directories or files are required' if directories.empty? && files.empty?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -926,7 +926,8 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions do
|
||||||
stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config])
|
stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config])
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'asks the user to accept the terms before setting an email' do
|
it 'asks the user to accept the terms before setting an email',
|
||||||
|
quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/388049', type: :flaky } do
|
||||||
expect(authentication_metrics)
|
expect(authentication_metrics)
|
||||||
.to increment(:user_authenticated_counter)
|
.to increment(:user_authenticated_counter)
|
||||||
|
|
||||||
|
|
588
spec/fixtures/emails/valid_reply_signed_smime.eml
vendored
588
spec/fixtures/emails/valid_reply_signed_smime.eml
vendored
|
@ -1,294 +1,294 @@
|
||||||
User-Agent: Microsoft-MacOutlook/10.22.0.200209
|
User-Agent: Microsoft-MacOutlook/10.22.0.200209
|
||||||
Date: Mon, 17 Feb 2020 22:56:47 +0100
|
Date: Mon, 17 Feb 2020 22:56:47 +0100
|
||||||
Subject: Re: htmltest | test issue (#1)
|
Subject: Re: htmltest | test issue (#1)
|
||||||
From: "Louzan Martinez, Diego (ext) (SI BP R&D ZG)"
|
From: "Louzan Martinez, Diego (ext) (SI BP R&D ZG)"
|
||||||
<diego.louzan.ext@siemens.com>
|
<diego.louzan.ext@siemens.com>
|
||||||
To: Administrator / htmltest
|
To: Administrator / htmltest
|
||||||
<dlouzan.dummy+c034670b1623e617e15a3df64223d363@gmail.com>
|
<dlouzan.dummy+c034670b1623e617e15a3df64223d363@gmail.com>
|
||||||
Message-ID: <012E37D9-2A3F-4AC8-B79A-871F42914D86@siemens.com>
|
Message-ID: <012E37D9-2A3F-4AC8-B79A-871F42914D86@siemens.com>
|
||||||
Thread-Topic: htmltest | test issue (#1)
|
Thread-Topic: htmltest | test issue (#1)
|
||||||
References: <reply-c034670b1623e617e15a3df64223d363@169.254.169.254>
|
References: <reply-c034670b1623e617e15a3df64223d363@169.254.169.254>
|
||||||
<issue_451@169.254.169.254>
|
<issue_451@169.254.169.254>
|
||||||
<note_1797@169.254.169.254>
|
<note_1797@169.254.169.254>
|
||||||
In-Reply-To: <note_1797@169.254.169.254>
|
In-Reply-To: <note_1797@169.254.169.254>
|
||||||
Content-type: multipart/signed;
|
Content-type: multipart/signed;
|
||||||
protocol="application/pkcs7-signature";
|
protocol="application/pkcs7-signature";
|
||||||
micalg=sha256;
|
micalg=sha256;
|
||||||
boundary="B_3664825007_1904734766"
|
boundary="B_3664825007_1904734766"
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
|
|
||||||
--B_3664825007_1904734766
|
--B_3664825007_1904734766
|
||||||
Content-type: multipart/mixed;
|
Content-type: multipart/mixed;
|
||||||
boundary="B_3664825007_384940722"
|
boundary="B_3664825007_384940722"
|
||||||
|
|
||||||
|
|
||||||
--B_3664825007_384940722
|
--B_3664825007_384940722
|
||||||
Content-type: multipart/alternative;
|
Content-type: multipart/alternative;
|
||||||
boundary="B_3664825007_1519466360"
|
boundary="B_3664825007_1519466360"
|
||||||
|
|
||||||
|
|
||||||
--B_3664825007_1519466360
|
--B_3664825007_1519466360
|
||||||
Content-type: text/plain;
|
Content-type: text/plain;
|
||||||
charset="UTF-8"
|
charset="UTF-8"
|
||||||
Content-transfer-encoding: quoted-printable
|
Content-transfer-encoding: quoted-printable
|
||||||
|
|
||||||
Me too, with an attachment
|
Me too, with an attachment
|
||||||
|
|
||||||
=20
|
=20
|
||||||
|
|
||||||
From: Administrator <dlouzan.dummy@gmail.com>
|
From: Administrator <dlouzan.dummy@gmail.com>
|
||||||
Reply to: Administrator / htmltest <dlouzan.dummy+c034670b1623e617e15a3df64=
|
Reply to: Administrator / htmltest <dlouzan.dummy+c034670b1623e617e15a3df64=
|
||||||
223d363@gmail.com>
|
223d363@gmail.com>
|
||||||
Date: Monday, 17 February 2020 at 22:55
|
Date: Monday, 17 February 2020 at 22:55
|
||||||
To: "Louzan Martinez, Diego (ext) (SOP IT STG XS)" <diego.louzan.ext@siemen=
|
To: "Louzan Martinez, Diego (ext) (SOP IT STG XS)" <diego.louzan.ext@siemen=
|
||||||
s.com>
|
s.com>
|
||||||
Subject: Re: htmltest | test issue (#1)
|
Subject: Re: htmltest | test issue (#1)
|
||||||
|
|
||||||
=20
|
=20
|
||||||
|
|
||||||
Administrator commented:=20
|
Administrator commented:=20
|
||||||
|
|
||||||
I pity the foo !!!
|
I pity the foo !!!
|
||||||
|
|
||||||
=E2=80=94=20
|
=E2=80=94=20
|
||||||
Reply to this email directly or view it on GitLab.=20
|
Reply to this email directly or view it on GitLab.=20
|
||||||
You're receiving this email because of your account on 169.254.169.254. If =
|
You're receiving this email because of your account on 169.254.169.254. If =
|
||||||
you'd like to receive fewer emails, you can unsubscribe from this thread or =
|
you'd like to receive fewer emails, you can unsubscribe from this thread or =
|
||||||
adjust your notification settings.=20
|
adjust your notification settings.=20
|
||||||
|
|
||||||
|
|
||||||
--B_3664825007_1519466360
|
--B_3664825007_1519466360
|
||||||
Content-type: text/html;
|
Content-type: text/html;
|
||||||
charset="UTF-8"
|
charset="UTF-8"
|
||||||
Content-transfer-encoding: quoted-printable
|
Content-transfer-encoding: quoted-printable
|
||||||
|
|
||||||
<html xmlns:o=3D"urn:schemas-microsoft-com:office:office" xmlns:w=3D"urn:schema=
|
<html xmlns:o=3D"urn:schemas-microsoft-com:office:office" xmlns:w=3D"urn:schema=
|
||||||
s-microsoft-com:office:word" xmlns:m=3D"http://schemas.microsoft.com/office/20=
|
s-microsoft-com:office:word" xmlns:m=3D"http://schemas.microsoft.com/office/20=
|
||||||
04/12/omml" xmlns=3D"http://www.w3.org/TR/REC-html40"><head><meta http-equiv=3DC=
|
04/12/omml" xmlns=3D"http://www.w3.org/TR/REC-html40"><head><meta http-equiv=3DC=
|
||||||
ontent-Type content=3D"text/html; charset=3Dutf-8"><meta name=3DGenerator content=3D=
|
ontent-Type content=3D"text/html; charset=3Dutf-8"><meta name=3DGenerator content=3D=
|
||||||
"Microsoft Word 15 (filtered medium)"><title>GitLab</title><style><!--
|
"Microsoft Word 15 (filtered medium)"><title>GitLab</title><style><!--
|
||||||
/* Font Definitions */
|
/* Font Definitions */
|
||||||
@font-face
|
@font-face
|
||||||
{font-family:"Cambria Math";
|
{font-family:"Cambria Math";
|
||||||
panose-1:2 4 5 3 5 4 6 3 2 4;}
|
panose-1:2 4 5 3 5 4 6 3 2 4;}
|
||||||
@font-face
|
@font-face
|
||||||
{font-family:Calibri;
|
{font-family:Calibri;
|
||||||
panose-1:2 15 5 2 2 2 4 3 2 4;}
|
panose-1:2 15 5 2 2 2 4 3 2 4;}
|
||||||
/* Style Definitions */
|
/* Style Definitions */
|
||||||
p.MsoNormal, li.MsoNormal, div.MsoNormal
|
p.MsoNormal, li.MsoNormal, div.MsoNormal
|
||||||
{margin:0cm;
|
{margin:0cm;
|
||||||
margin-bottom:.0001pt;
|
margin-bottom:.0001pt;
|
||||||
font-size:11.0pt;
|
font-size:11.0pt;
|
||||||
font-family:"Calibri",sans-serif;}
|
font-family:"Calibri",sans-serif;}
|
||||||
a:link, span.MsoHyperlink
|
a:link, span.MsoHyperlink
|
||||||
{mso-style-priority:99;
|
{mso-style-priority:99;
|
||||||
color:blue;
|
color:blue;
|
||||||
text-decoration:underline;}
|
text-decoration:underline;}
|
||||||
span.EmailStyle19
|
span.EmailStyle19
|
||||||
{mso-style-type:personal-reply;
|
{mso-style-type:personal-reply;
|
||||||
font-family:"Calibri",sans-serif;
|
font-family:"Calibri",sans-serif;
|
||||||
color:windowtext;}
|
color:windowtext;}
|
||||||
.MsoChpDefault
|
.MsoChpDefault
|
||||||
{mso-style-type:export-only;
|
{mso-style-type:export-only;
|
||||||
font-size:10.0pt;}
|
font-size:10.0pt;}
|
||||||
@page WordSection1
|
@page WordSection1
|
||||||
{size:612.0pt 792.0pt;
|
{size:612.0pt 792.0pt;
|
||||||
margin:72.0pt 72.0pt 72.0pt 72.0pt;}
|
margin:72.0pt 72.0pt 72.0pt 72.0pt;}
|
||||||
div.WordSection1
|
div.WordSection1
|
||||||
{page:WordSection1;}
|
{page:WordSection1;}
|
||||||
--></style></head><body lang=3Den-ES link=3Dblue vlink=3Dpurple><div class=3DWordSe=
|
--></style></head><body lang=3Den-ES link=3Dblue vlink=3Dpurple><div class=3DWordSe=
|
||||||
ction1><p class=3DMsoNormal><span lang=3DEN-US style=3D'mso-fareast-language:EN-US=
|
ction1><p class=3DMsoNormal><span lang=3DEN-US style=3D'mso-fareast-language:EN-US=
|
||||||
'>Me too, with an attachment<o:p></o:p></span></p><p class=3DMsoNormal><span s=
|
'>Me too, with an attachment<o:p></o:p></span></p><p class=3DMsoNormal><span s=
|
||||||
tyle=3D'mso-fareast-language:EN-US'><o:p> </o:p></span></p><div style=3D'bo=
|
tyle=3D'mso-fareast-language:EN-US'><o:p> </o:p></span></p><div style=3D'bo=
|
||||||
rder:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0cm 0cm 0cm'><p class=
|
rder:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0cm 0cm 0cm'><p class=
|
||||||
=3DMsoNormal><b><span style=3D'font-size:12.0pt;color:black'>From: </span></b><s=
|
=3DMsoNormal><b><span style=3D'font-size:12.0pt;color:black'>From: </span></b><s=
|
||||||
pan style=3D'font-size:12.0pt;color:black'>Administrator <dlouzan.dummy@gma=
|
pan style=3D'font-size:12.0pt;color:black'>Administrator <dlouzan.dummy@gma=
|
||||||
il.com><br><b>Reply to: </b>Administrator / htmltest <dlouzan.dummy+c0=
|
il.com><br><b>Reply to: </b>Administrator / htmltest <dlouzan.dummy+c0=
|
||||||
34670b1623e617e15a3df64223d363@gmail.com><br><b>Date: </b>Monday, 17 Febr=
|
34670b1623e617e15a3df64223d363@gmail.com><br><b>Date: </b>Monday, 17 Febr=
|
||||||
uary 2020 at 22:55<br><b>To: </b>"Louzan Martinez, Diego (ext) (SOP IT =
|
uary 2020 at 22:55<br><b>To: </b>"Louzan Martinez, Diego (ext) (SOP IT =
|
||||||
STG XS)" <diego.louzan.ext@siemens.com><br><b>Subject: </b>Re: ht=
|
STG XS)" <diego.louzan.ext@siemens.com><br><b>Subject: </b>Re: ht=
|
||||||
mltest | test issue (#1)<o:p></o:p></span></p></div><div><p class=3DMsoNormal>=
|
mltest | test issue (#1)<o:p></o:p></span></p></div><div><p class=3DMsoNormal>=
|
||||||
<o:p> </o:p></p></div><div><p><span style=3D'color:#777777'><a href=3D"http=
|
<o:p> </o:p></p></div><div><p><span style=3D'color:#777777'><a href=3D"http=
|
||||||
://localhost:3000/root">Administrator</a> commented: <o:p></o:p></span></p><=
|
://localhost:3000/root">Administrator</a> commented: <o:p></o:p></span></p><=
|
||||||
div><p>I pity the foo !!!<o:p></o:p></p></div></div><div style=3D'margin-top:7=
|
div><p>I pity the foo !!!<o:p></o:p></p></div></div><div style=3D'margin-top:7=
|
||||||
.5pt'><p><span style=3D'font-size:12.0pt;color:#777777'>=E2=80=94 <br>Reply to this =
|
.5pt'><p><span style=3D'font-size:12.0pt;color:#777777'>=E2=80=94 <br>Reply to this =
|
||||||
email directly or <a href=3D"http://localhost:3000/root/htmltest/issues/1#note=
|
email directly or <a href=3D"http://localhost:3000/root/htmltest/issues/1#note=
|
||||||
_1797">view it on GitLab</a>. <br>You're receiving this email because of you=
|
_1797">view it on GitLab</a>. <br>You're receiving this email because of you=
|
||||||
r account on 169.254.169.254. If you'd like to receive fewer emails, you can=
|
r account on 169.254.169.254. If you'd like to receive fewer emails, you can=
|
||||||
<a href=3D"http://localhost:3000/sent_notifications/c034670b1623e617e15a3df64=
|
<a href=3D"http://localhost:3000/sent_notifications/c034670b1623e617e15a3df64=
|
||||||
223d363/unsubscribe">unsubscribe</a> from this thread or adjust your notific=
|
223d363/unsubscribe">unsubscribe</a> from this thread or adjust your notific=
|
||||||
ation settings. <o:p></o:p></span></p></div></div></body></html>
|
ation settings. <o:p></o:p></span></p></div></div></body></html>
|
||||||
|
|
||||||
--B_3664825007_1519466360--
|
--B_3664825007_1519466360--
|
||||||
|
|
||||||
|
|
||||||
--B_3664825007_384940722
|
--B_3664825007_384940722
|
||||||
Content-type: image/png; name="gitlab_logo.png";
|
Content-type: image/png; name="gitlab_logo.png";
|
||||||
x-mac-creator="4F50494D";
|
x-mac-creator="4F50494D";
|
||||||
x-mac-type="504E4766"
|
x-mac-type="504E4766"
|
||||||
Content-disposition: attachment;
|
Content-disposition: attachment;
|
||||||
filename="gitlab_logo.png"
|
filename="gitlab_logo.png"
|
||||||
Content-transfer-encoding: base64
|
Content-transfer-encoding: base64
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
--B_3664825007_384940722--
|
--B_3664825007_384940722--
|
||||||
|
|
||||||
--B_3664825007_1904734766
|
--B_3664825007_1904734766
|
||||||
Content-type: application/pkcs7-signature; name="smime.p7s"
|
Content-type: application/pkcs7-signature; name="smime.p7s"
|
||||||
Content-transfer-encoding: base64
|
Content-transfer-encoding: base64
|
||||||
Content-disposition: attachment;
|
Content-disposition: attachment;
|
||||||
filename="smime.p7s"
|
filename="smime.p7s"
|
||||||
|
|
||||||
MIIRpwYJKoZIhvcNAQcCoIIRmDCCEZQCAQExDzANBglghkgBZQMEAgEFADALBgkqhkiG9w0B
|
MIIRpwYJKoZIhvcNAQcCoIIRmDCCEZQCAQExDzANBglghkgBZQMEAgEFADALBgkqhkiG9w0B
|
||||||
BwGggg8VMIIHojCCBYqgAwIBAgIEZ5a6PTANBgkqhkiG9w0BAQsFADCBtjELMAkGA1UEBhMC
|
BwGggg8VMIIHojCCBYqgAwIBAgIEZ5a6PTANBgkqhkiG9w0BAQsFADCBtjELMAkGA1UEBhMC
|
||||||
REUxDzANBgNVBAgMBkJheWVybjERMA8GA1UEBwwITXVlbmNoZW4xEDAOBgNVBAoMB1NpZW1l
|
REUxDzANBgNVBAgMBkJheWVybjERMA8GA1UEBwwITXVlbmNoZW4xEDAOBgNVBAoMB1NpZW1l
|
||||||
bnMxETAPBgNVBAUTCFpaWlpaWkE2MR0wGwYDVQQLDBRTaWVtZW5zIFRydXN0IENlbnRlcjE/
|
bnMxETAPBgNVBAUTCFpaWlpaWkE2MR0wGwYDVQQLDBRTaWVtZW5zIFRydXN0IENlbnRlcjE/
|
||||||
MD0GA1UEAww2U2llbWVucyBJc3N1aW5nIENBIE1lZGl1bSBTdHJlbmd0aCBBdXRoZW50aWNh
|
MD0GA1UEAww2U2llbWVucyBJc3N1aW5nIENBIE1lZGl1bSBTdHJlbmd0aCBBdXRoZW50aWNh
|
||||||
dGlvbiAyMDE2MB4XDTE5MTEyMTE0NDQ0N1oXDTIwMTEyMTE0NDQ0N1owdzERMA8GA1UEBRMI
|
dGlvbiAyMDE2MB4XDTE5MTEyMTE0NDQ0N1oXDTIwMTEyMTE0NDQ0N1owdzERMA8GA1UEBRMI
|
||||||
WjAwM0gwOFQxDjAMBgNVBCoMBURpZWdvMRgwFgYDVQQEDA9Mb3V6YW4gTWFydGluZXoxGDAW
|
WjAwM0gwOFQxDjAMBgNVBCoMBURpZWdvMRgwFgYDVQQEDA9Mb3V6YW4gTWFydGluZXoxGDAW
|
||||||
BgNVBAoMD1NpZW1lbnMtUGFydG5lcjEeMBwGA1UEAwwVTG91emFuIE1hcnRpbmV6IERpZWdv
|
BgNVBAoMD1NpZW1lbnMtUGFydG5lcjEeMBwGA1UEAwwVTG91emFuIE1hcnRpbmV6IERpZWdv
|
||||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuInpNaC7NRYD+0pOpHDz2pk9xmPt
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuInpNaC7NRYD+0pOpHDz2pk9xmPt
|
||||||
JGj860SF6Nmn6Eu9EMYKEDfneC6z5QcH+mPS2d0VWgqVVGbRXSPsxJtbi9TCWjQUZdHglEZK
|
JGj860SF6Nmn6Eu9EMYKEDfneC6z5QcH+mPS2d0VWgqVVGbRXSPsxJtbi9TCWjQUZdHglEZK
|
||||||
z9zxoFDh2dvW5/+TOT5Jf78FXyqak0YtY6+oMjQ/i9RUqPL7sIlyXLrBYrILzQ9Afo+7bXZg
|
z9zxoFDh2dvW5/+TOT5Jf78FXyqak0YtY6+oMjQ/i9RUqPL7sIlyXLrBYrILzQ9Afo+7bXZg
|
||||||
v3ypp6xtqAV2ctHzQWFi0onJzxLVYguiVb7fFF9rBEMvSZonuw5tvOwJIhbe5FDFOrDcfbyU
|
v3ypp6xtqAV2ctHzQWFi0onJzxLVYguiVb7fFF9rBEMvSZonuw5tvOwJIhbe5FDFOrDcfbyU
|
||||||
ofZ/wikIZ+A+CE5GryXuuQmGxJaC2QqOkRAWQDzLDx9nG+rKiEs5OvlfEZC7EV1PyjZ93coM
|
ofZ/wikIZ+A+CE5GryXuuQmGxJaC2QqOkRAWQDzLDx9nG+rKiEs5OvlfEZC7EV1PyjZ93coM
|
||||||
faCVdlAgcFZ5fvd37CjyjKl+1QIDAQABo4IC9DCCAvAwggEEBggrBgEFBQcBAQSB9zCB9DAy
|
faCVdlAgcFZ5fvd37CjyjKl+1QIDAQABo4IC9DCCAvAwggEEBggrBgEFBQcBAQSB9zCB9DAy
|
||||||
BggrBgEFBQcwAoYmaHR0cDovL2FoLnNpZW1lbnMuY29tL3BraT9aWlpaWlpBNi5jcnQwQQYI
|
BggrBgEFBQcwAoYmaHR0cDovL2FoLnNpZW1lbnMuY29tL3BraT9aWlpaWlpBNi5jcnQwQQYI
|
||||||
KwYBBQUHMAKGNWxkYXA6Ly9hbC5zaWVtZW5zLm5ldC9DTj1aWlpaWlpBNixMPVBLST9jQUNl
|
KwYBBQUHMAKGNWxkYXA6Ly9hbC5zaWVtZW5zLm5ldC9DTj1aWlpaWlpBNixMPVBLST9jQUNl
|
||||||
cnRpZmljYXRlMEkGCCsGAQUFBzAChj1sZGFwOi8vYWwuc2llbWVucy5jb20vQ049WlpaWlpa
|
cnRpZmljYXRlMEkGCCsGAQUFBzAChj1sZGFwOi8vYWwuc2llbWVucy5jb20vQ049WlpaWlpa
|
||||||
QTYsbz1UcnVzdGNlbnRlcj9jQUNlcnRpZmljYXRlMDAGCCsGAQUFBzABhiRodHRwOi8vb2Nz
|
QTYsbz1UcnVzdGNlbnRlcj9jQUNlcnRpZmljYXRlMDAGCCsGAQUFBzABhiRodHRwOi8vb2Nz
|
||||||
cC5wa2ktc2VydmljZXMuc2llbWVucy5jb20wHwYDVR0jBBgwFoAU+BVdRwxsd3tyxAIXkWii
|
cC5wa2ktc2VydmljZXMuc2llbWVucy5jb20wHwYDVR0jBBgwFoAU+BVdRwxsd3tyxAIXkWii
|
||||||
tvdqCUQwDAYDVR0TAQH/BAIwADBFBgNVHSAEPjA8MDoGDSsGAQQBoWkHAgIEAQMwKTAnBggr
|
tvdqCUQwDAYDVR0TAQH/BAIwADBFBgNVHSAEPjA8MDoGDSsGAQQBoWkHAgIEAQMwKTAnBggr
|
||||||
BgEFBQcCARYbaHR0cDovL3d3dy5zaWVtZW5zLmNvbS9wa2kvMIHKBgNVHR8EgcIwgb8wgbyg
|
BgEFBQcCARYbaHR0cDovL3d3dy5zaWVtZW5zLmNvbS9wa2kvMIHKBgNVHR8EgcIwgb8wgbyg
|
||||||
gbmggbaGJmh0dHA6Ly9jaC5zaWVtZW5zLmNvbS9wa2k/WlpaWlpaQTYuY3JshkFsZGFwOi8v
|
gbmggbaGJmh0dHA6Ly9jaC5zaWVtZW5zLmNvbS9wa2k/WlpaWlpaQTYuY3JshkFsZGFwOi8v
|
||||||
Y2wuc2llbWVucy5uZXQvQ049WlpaWlpaQTYsTD1QS0k/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
|
Y2wuc2llbWVucy5uZXQvQ049WlpaWlpaQTYsTD1QS0k/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
|
||||||
TGlzdIZJbGRhcDovL2NsLnNpZW1lbnMuY29tL0NOPVpaWlpaWkE2LG89VHJ1c3RjZW50ZXI/
|
TGlzdIZJbGRhcDovL2NsLnNpZW1lbnMuY29tL0NOPVpaWlpaWkE2LG89VHJ1c3RjZW50ZXI/
|
||||||
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
|
||||||
Cztca8vI1jUjQzVhS+0dWpvpfhkVumbvOnid8DI9lapYsX8dpZFsa3ya+T3tjUdGSOOKi0kg
|
Cztca8vI1jUjQzVhS+0dWpvpfhkVumbvOnid8DI9lapYsX8dpZFsa3ya+T3tjUdGSOOKi0kg
|
||||||
lWf/XYyyfhmDAgMBAAGjggLVMIIC0TAdBgNVHQ4EFgQUprhTCDwNLfPImpSfWdq+QvPTo9Mw
|
lWf/XYyyfhmDAgMBAAGjggLVMIIC0TAdBgNVHQ4EFgQUprhTCDwNLfPImpSfWdq+QvPTo9Mw
|
||||||
JwYDVR0RBCAwHoEcZGllZ28ubG91emFuLmV4dEBzaWVtZW5zLmNvbTAOBgNVHQ8BAf8EBAMC
|
JwYDVR0RBCAwHoEcZGllZ28ubG91emFuLmV4dEBzaWVtZW5zLmNvbTAOBgNVHQ8BAf8EBAMC
|
||||||
BDAwLAYDVR0lBCUwIwYIKwYBBQUHAwQGCisGAQQBgjcKAwQGCysGAQQBgjcKAwQBMIHKBgNV
|
BDAwLAYDVR0lBCUwIwYIKwYBBQUHAwQGCisGAQQBgjcKAwQGCysGAQQBgjcKAwQBMIHKBgNV
|
||||||
HR8EgcIwgb8wgbyggbmggbaGJmh0dHA6Ly9jaC5zaWVtZW5zLmNvbS9wa2k/WlpaWlpaQTMu
|
HR8EgcIwgb8wgbyggbmggbaGJmh0dHA6Ly9jaC5zaWVtZW5zLmNvbS9wa2k/WlpaWlpaQTMu
|
||||||
Y3JshkFsZGFwOi8vY2wuc2llbWVucy5uZXQvQ049WlpaWlpaQTMsTD1QS0k/Y2VydGlmaWNh
|
Y3JshkFsZGFwOi8vY2wuc2llbWVucy5uZXQvQ049WlpaWlpaQTMsTD1QS0k/Y2VydGlmaWNh
|
||||||
dGVSZXZvY2F0aW9uTGlzdIZJbGRhcDovL2NsLnNpZW1lbnMuY29tL0NOPVpaWlpaWkEzLG89
|
dGVSZXZvY2F0aW9uTGlzdIZJbGRhcDovL2NsLnNpZW1lbnMuY29tL0NOPVpaWlpaWkEzLG89
|
||||||
VHJ1c3RjZW50ZXI/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDBFBgNVHSAEPjA8MDoGDSsG
|
VHJ1c3RjZW50ZXI/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDBFBgNVHSAEPjA8MDoGDSsG
|
||||||
AQQBoWkHAgIEAQMwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5zaWVtZW5zLmNvbS9wa2kv
|
AQQBoWkHAgIEAQMwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5zaWVtZW5zLmNvbS9wa2kv
|
||||||
MAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUoassbqB68NPCTeof8R4hivwMre8wggEEBggr
|
MAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUoassbqB68NPCTeof8R4hivwMre8wggEEBggr
|
||||||
BgEFBQcBAQSB9zCB9DAyBggrBgEFBQcwAoYmaHR0cDovL2FoLnNpZW1lbnMuY29tL3BraT9a
|
BgEFBQcBAQSB9zCB9DAyBggrBgEFBQcwAoYmaHR0cDovL2FoLnNpZW1lbnMuY29tL3BraT9a
|
||||||
WlpaWlpBMy5jcnQwQQYIKwYBBQUHMAKGNWxkYXA6Ly9hbC5zaWVtZW5zLm5ldC9DTj1aWlpa
|
WlpaWlpBMy5jcnQwQQYIKwYBBQUHMAKGNWxkYXA6Ly9hbC5zaWVtZW5zLm5ldC9DTj1aWlpa
|
||||||
WlpBMyxMPVBLST9jQUNlcnRpZmljYXRlMEkGCCsGAQUFBzAChj1sZGFwOi8vYWwuc2llbWVu
|
WlpBMyxMPVBLST9jQUNlcnRpZmljYXRlMEkGCCsGAQUFBzAChj1sZGFwOi8vYWwuc2llbWVu
|
||||||
cy5jb20vQ049WlpaWlpaQTMsbz1UcnVzdGNlbnRlcj9jQUNlcnRpZmljYXRlMDAGCCsGAQUF
|
cy5jb20vQ049WlpaWlpaQTMsbz1UcnVzdGNlbnRlcj9jQUNlcnRpZmljYXRlMDAGCCsGAQUF
|
||||||
BzABhiRodHRwOi8vb2NzcC5wa2ktc2VydmljZXMuc2llbWVucy5jb20wDQYJKoZIhvcNAQEL
|
BzABhiRodHRwOi8vb2NzcC5wa2ktc2VydmljZXMuc2llbWVucy5jb20wDQYJKoZIhvcNAQEL
|
||||||
BQADggIBAF98ZMNg28LgkwdjOdvOGbC1QitsWjZTyotmQESF0nClDLUhb0O5675vVixntbrf
|
BQADggIBAF98ZMNg28LgkwdjOdvOGbC1QitsWjZTyotmQESF0nClDLUhb0O5675vVixntbrf
|
||||||
eB8xy1+KRiadk40GnAIJ0YzmNl4Tav6hPYv9VBWe5olsWG7C4qB3Q/SwhvW/e+owxv1cBra8
|
eB8xy1+KRiadk40GnAIJ0YzmNl4Tav6hPYv9VBWe5olsWG7C4qB3Q/SwhvW/e+owxv1cBra8
|
||||||
R3oRudiN81eTZQHyNghRephVqQG/dpPYqydoANfIhEpHa79QlpaCAeYl4896AZOS8HYbkDFs
|
R3oRudiN81eTZQHyNghRephVqQG/dpPYqydoANfIhEpHa79QlpaCAeYl4896AZOS8HYbkDFs
|
||||||
hLdv7sEHtl79YuSWI1wBjbJl70c0Sb4wLRgCPuHyQj2Uw/vQ5xJlEvBDZAIXXe1TP/nqiuY6
|
hLdv7sEHtl79YuSWI1wBjbJl70c0Sb4wLRgCPuHyQj2Uw/vQ5xJlEvBDZAIXXe1TP/nqiuY6
|
||||||
7nweJbbeqfFE6ZP3kCe+mEIWGSaO0iThZyLGer8fHs1XiEmhhPgvC7P7KodzpXU6+hX+ZzbD
|
7nweJbbeqfFE6ZP3kCe+mEIWGSaO0iThZyLGer8fHs1XiEmhhPgvC7P7KodzpXU6+hX+ZzbD
|
||||||
DxEjFfetV5sh0aNSXG9xx4hZmS9bpImBGR8MvZ7cgxqItvLtY2xvfUbYW244d4RcWesaCDq3
|
DxEjFfetV5sh0aNSXG9xx4hZmS9bpImBGR8MvZ7cgxqItvLtY2xvfUbYW244d4RcWesaCDq3
|
||||||
ZEIo6uCIzOzJAwjUdLIac+lLV0rxiHmb7O3cQ19kjpWDB31hmfrus/TKJ55pBKVWBX5m/mFv
|
ZEIo6uCIzOzJAwjUdLIac+lLV0rxiHmb7O3cQ19kjpWDB31hmfrus/TKJ55pBKVWBX5m/mFv
|
||||||
K8Ep5USpGrNS0EzOP7I1kQZv2VsvAhSxk/m5FMLpDy8T0O8YgbLypTXoeJFWCF6RduSjVsaZ
|
K8Ep5USpGrNS0EzOP7I1kQZv2VsvAhSxk/m5FMLpDy8T0O8YgbLypTXoeJFWCF6RduSjVsaZ
|
||||||
lkAtTQYud683pjyOMxJXaQUYGU1PmEYSOonMkVsT9aBcxYkXLp+Ln/+8G0OCYu7dRdwnj+Ut
|
lkAtTQYud683pjyOMxJXaQUYGU1PmEYSOonMkVsT9aBcxYkXLp+Ln/+8G0OCYu7dRdwnj+Ut
|
||||||
7yR/ltxtgDcaFApCb0qBTKbgbqZk1fASmkOp+kbdYmoUMYICVjCCAlICAQEwgb8wgbYxCzAJ
|
7yR/ltxtgDcaFApCb0qBTKbgbqZk1fASmkOp+kbdYmoUMYICVjCCAlICAQEwgb8wgbYxCzAJ
|
||||||
BgNVBAYTAkRFMQ8wDQYDVQQIDAZCYXllcm4xETAPBgNVBAcMCE11ZW5jaGVuMRAwDgYDVQQK
|
BgNVBAYTAkRFMQ8wDQYDVQQIDAZCYXllcm4xETAPBgNVBAcMCE11ZW5jaGVuMRAwDgYDVQQK
|
||||||
DAdTaWVtZW5zMREwDwYDVQQFEwhaWlpaWlpBNjEdMBsGA1UECwwUU2llbWVucyBUcnVzdCBD
|
DAdTaWVtZW5zMREwDwYDVQQFEwhaWlpaWlpBNjEdMBsGA1UECwwUU2llbWVucyBUcnVzdCBD
|
||||||
ZW50ZXIxPzA9BgNVBAMMNlNpZW1lbnMgSXNzdWluZyBDQSBNZWRpdW0gU3RyZW5ndGggQXV0
|
ZW50ZXIxPzA9BgNVBAMMNlNpZW1lbnMgSXNzdWluZyBDQSBNZWRpdW0gU3RyZW5ndGggQXV0
|
||||||
aGVudGljYXRpb24gMjAxNgIEZ5a6PTANBglghkgBZQMEAgEFAKBpMC8GCSqGSIb3DQEJBDEi
|
aGVudGljYXRpb24gMjAxNgIEZ5a6PTANBglghkgBZQMEAgEFAKBpMC8GCSqGSIb3DQEJBDEi
|
||||||
BCAOR58AbNfSrI+vtMs+dgAQtn3IVZ3RjYC5hz3j9k+6TTAYBgkqhkiG9w0BCQMxCwYJKoZI
|
BCAOR58AbNfSrI+vtMs+dgAQtn3IVZ3RjYC5hz3j9k+6TTAYBgkqhkiG9w0BCQMxCwYJKoZI
|
||||||
hvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yMDAyMTcyMTU2NDdaMA0GCSqGSIb3DQEBAQUABIIB
|
hvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yMDAyMTcyMTU2NDdaMA0GCSqGSIb3DQEBAQUABIIB
|
||||||
AHLSBcFHhNHPevbwqvA2ecuVb/aKnj45CFF6l8esP1H5DRm1ee5qMKuIS84NFuFC9RUENNhW
|
AHLSBcFHhNHPevbwqvA2ecuVb/aKnj45CFF6l8esP1H5DRm1ee5qMKuIS84NFuFC9RUENNhW
|
||||||
DBzsB+BVGz64o1f8QgIklYVrIJ4JZ0q1abNG7NbkVKWIpS3CQo//YWShUTYg+JpKx4YbahGR
|
DBzsB+BVGz64o1f8QgIklYVrIJ4JZ0q1abNG7NbkVKWIpS3CQo//YWShUTYg+JpKx4YbahGR
|
||||||
sP5zbufbU4eagrrqBChjPTLy+njdjwCNu0XPykBTKOOf6BMjnS33AYjHJyh83JOY7rw3IDLx
|
sP5zbufbU4eagrrqBChjPTLy+njdjwCNu0XPykBTKOOf6BMjnS33AYjHJyh83JOY7rw3IDLx
|
||||||
8POQH4g5EMRpl9354s0rEkIezMt7pfUAsqY3QnQ8hvlE4KTikPQ+tvLMK1l/ffcLAP8BdBNI
|
8POQH4g5EMRpl9354s0rEkIezMt7pfUAsqY3QnQ8hvlE4KTikPQ+tvLMK1l/ffcLAP8BdBNI
|
||||||
YA3ikb3qCoGNSLKieYzNnBPhNOIJELUtEEaljAFZYMQzMKCbI4JdiDs=
|
YA3ikb3qCoGNSLKieYzNnBPhNOIJELUtEEaljAFZYMQzMKCbI4JdiDs=
|
||||||
|
|
||||||
--B_3664825007_1904734766--
|
--B_3664825007_1904734766--
|
||||||
|
|
BIN
spec/fixtures/packages/helm/corrupted_chart.tgz
vendored
Normal file
BIN
spec/fixtures/packages/helm/corrupted_chart.tgz
vendored
Normal file
Binary file not shown.
BIN
spec/fixtures/safe_zip/invalid-unexpected-large.zip
vendored
Normal file
BIN
spec/fixtures/safe_zip/invalid-unexpected-large.zip
vendored
Normal file
Binary file not shown.
BIN
spec/fixtures/safe_zip/valid-symlinks-first.zip
vendored
BIN
spec/fixtures/safe_zip/valid-symlinks-first.zip
vendored
Binary file not shown.
|
@ -10,71 +10,117 @@ RSpec.describe Gitlab::Ci::ArtifactFileReader do
|
||||||
subject { described_class.new(job).read(path) }
|
subject { described_class.new(job).read(path) }
|
||||||
|
|
||||||
context 'when job has artifacts and metadata' do
|
context 'when job has artifacts and metadata' do
|
||||||
let!(:artifacts) { create(:ci_job_artifact, :archive, job: job) }
|
shared_examples 'extracting job artifact archive' do
|
||||||
let!(:metadata) { create(:ci_job_artifact, :metadata, job: job) }
|
it 'returns the content at the path' do
|
||||||
|
|
||||||
it 'returns the content at the path' do
|
|
||||||
is_expected.to be_present
|
|
||||||
expect(YAML.safe_load(subject).keys).to contain_exactly('rspec', 'time', 'custom')
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when path does not exist' do
|
|
||||||
let(:path) { 'file/does/not/exist.txt' }
|
|
||||||
let(:expected_error) do
|
|
||||||
"Path `#{path}` does not exist inside the `#{job.name}` artifacts archive!"
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'raises an error' do
|
|
||||||
expect { subject }.to raise_error(described_class::Error, expected_error)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when path points to a directory' do
|
|
||||||
let(:path) { 'other_artifacts_0.1.2' }
|
|
||||||
let(:expected_error) do
|
|
||||||
"Path `#{path}` was expected to be a file but it was a directory!"
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'raises an error' do
|
|
||||||
expect { subject }.to raise_error(described_class::Error, expected_error)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when path is nested' do
|
|
||||||
# path exists in ci_build_artifacts.zip
|
|
||||||
let(:path) { 'other_artifacts_0.1.2/doc_sample.txt' }
|
|
||||||
|
|
||||||
it 'returns the content at the nested path' do
|
|
||||||
is_expected.to be_present
|
is_expected.to be_present
|
||||||
|
expect(YAML.safe_load(subject).keys).to contain_exactly('rspec', 'time', 'custom')
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when path does not exist' do
|
||||||
|
let(:path) { 'file/does/not/exist.txt' }
|
||||||
|
let(:expected_error) do
|
||||||
|
"Path `#{path}` does not exist inside the `#{job.name}` artifacts archive!"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises an error' do
|
||||||
|
expect { subject }.to raise_error(described_class::Error, expected_error)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when path points to a directory' do
|
||||||
|
let(:path) { 'other_artifacts_0.1.2' }
|
||||||
|
let(:expected_error) do
|
||||||
|
"Path `#{path}` was expected to be a file but it was a directory!"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises an error' do
|
||||||
|
expect { subject }.to raise_error(described_class::Error, expected_error)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when path is nested' do
|
||||||
|
# path exists in ci_build_artifacts.zip
|
||||||
|
let(:path) { 'other_artifacts_0.1.2/doc_sample.txt' }
|
||||||
|
|
||||||
|
it 'returns the content at the nested path' do
|
||||||
|
is_expected.to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when artifact archive size is greater than the limit' do
|
||||||
|
let(:expected_error) do
|
||||||
|
"Artifacts archive for job `#{job.name}` is too large: max 1 KB"
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_const("#{described_class}::MAX_ARCHIVE_SIZE", 1.kilobyte)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises an error' do
|
||||||
|
expect { subject }.to raise_error(described_class::Error, expected_error)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when metadata entry shows size greater than the limit' do
|
||||||
|
let(:expected_error) do
|
||||||
|
"Artifacts archive for job `#{job.name}` is too large: max 5 MB"
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
expect_next_instance_of(Gitlab::Ci::Build::Artifacts::Metadata::Entry) do |entry|
|
||||||
|
expect(entry).to receive(:total_size).and_return(10.megabytes)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises an error' do
|
||||||
|
expect { subject }.to raise_error(described_class::Error, expected_error)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when artifact archive size is greater than the limit' do
|
context 'when job artifact is on local storage' do
|
||||||
let(:expected_error) do
|
let!(:artifacts) { create(:ci_job_artifact, :archive, job: job) }
|
||||||
"Artifacts archive for job `#{job.name}` is too large: max 1 KB"
|
let!(:metadata) { create(:ci_job_artifact, :metadata, job: job) }
|
||||||
end
|
|
||||||
|
|
||||||
before do
|
it_behaves_like 'extracting job artifact archive'
|
||||||
stub_const("#{described_class}::MAX_ARCHIVE_SIZE", 1.kilobyte)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'raises an error' do
|
|
||||||
expect { subject }.to raise_error(described_class::Error, expected_error)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when metadata entry shows size greater than the limit' do
|
context 'when job artifact is on remote storage' do
|
||||||
let(:expected_error) do
|
before do
|
||||||
"Artifacts archive for job `#{job.name}` is too large: max 5 MB"
|
stub_artifacts_object_storage
|
||||||
|
stub_request(:get, %r{https://artifacts.+ci_build_artifacts\.zip})
|
||||||
|
.to_return(
|
||||||
|
status: 200,
|
||||||
|
body: File.open(Rails.root.join('spec/fixtures/ci_build_artifacts.zip')),
|
||||||
|
headers: {}
|
||||||
|
)
|
||||||
|
stub_request(:get, %r{https://artifacts.+ci_build_artifacts_metadata})
|
||||||
|
.to_return(
|
||||||
|
status: 200,
|
||||||
|
body: File.open(Rails.root.join('spec/fixtures/ci_build_artifacts_metadata.gz')),
|
||||||
|
headers: {}
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let!(:artifacts) { create(:ci_job_artifact, :archive, :remote_store, job: job) }
|
||||||
|
let!(:metadata) { create(:ci_job_artifact, :metadata, :remote_store, job: job) }
|
||||||
|
|
||||||
|
it_behaves_like 'extracting job artifact archive'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when extracting job artifact raises entry size error' do
|
||||||
|
let!(:artifacts) { create(:ci_job_artifact, :archive, job: job) }
|
||||||
|
let!(:metadata) { create(:ci_job_artifact, :metadata, job: job) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
expect_next_instance_of(Gitlab::Ci::Build::Artifacts::Metadata::Entry) do |entry|
|
allow_next_instance_of(SafeZip::Extract, anything) do |extractor|
|
||||||
expect(entry).to receive(:total_size).and_return(10.megabytes)
|
allow(extractor).to receive(:extract).and_raise(SafeZip::Extract::EntrySizeError)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'raises an error' do
|
it 'raises an error' do
|
||||||
|
expected_error = "Path `#{path}` has invalid size in the zip!"
|
||||||
|
|
||||||
expect { subject }.to raise_error(described_class::Error, expected_error)
|
expect { subject }.to raise_error(described_class::Error, expected_error)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,12 +5,13 @@ require 'spec_helper'
|
||||||
RSpec.describe SafeZip::Entry do
|
RSpec.describe SafeZip::Entry do
|
||||||
let(:target_path) { Dir.mktmpdir('safe-zip') }
|
let(:target_path) { Dir.mktmpdir('safe-zip') }
|
||||||
let(:directories) { %w(public folder/with/subfolder) }
|
let(:directories) { %w(public folder/with/subfolder) }
|
||||||
let(:params) { SafeZip::ExtractParams.new(directories: directories, to: target_path) }
|
let(:files) { %w(public/index.html public/assets/image.png) }
|
||||||
|
let(:params) { SafeZip::ExtractParams.new(directories: directories, files: files, to: target_path) }
|
||||||
|
|
||||||
let(:entry) { described_class.new(zip_archive, zip_entry, params) }
|
let(:entry) { described_class.new(zip_archive, zip_entry, params) }
|
||||||
let(:entry_name) { 'public/folder/index.html' }
|
let(:entry_name) { 'public/folder/index.html' }
|
||||||
let(:entry_path_dir) { File.join(target_path, File.dirname(entry_name)) }
|
let(:entry_path_dir) { File.join(target_path, File.dirname(entry_name)) }
|
||||||
let(:entry_path) { File.join(target_path, entry_name) }
|
let(:entry_path) { File.join(File.realpath(target_path), entry_name) }
|
||||||
let(:zip_archive) { double }
|
let(:zip_archive) { double }
|
||||||
|
|
||||||
let(:zip_entry) do
|
let(:zip_entry) do
|
||||||
|
@ -28,7 +29,7 @@ RSpec.describe SafeZip::Entry do
|
||||||
describe '#path_dir' do
|
describe '#path_dir' do
|
||||||
subject { entry.path_dir }
|
subject { entry.path_dir }
|
||||||
|
|
||||||
it { is_expected.to eq(target_path + '/public/folder') }
|
it { is_expected.to eq(File.realpath(target_path) + '/public/folder') }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#exist?' do
|
describe '#exist?' do
|
||||||
|
@ -51,6 +52,9 @@ RSpec.describe SafeZip::Entry do
|
||||||
subject { entry.extract }
|
subject { entry.extract }
|
||||||
|
|
||||||
context 'when entry does not match the filtered directories' do
|
context 'when entry does not match the filtered directories' do
|
||||||
|
let(:directories) { %w(public folder/with/subfolder) }
|
||||||
|
let(:files) { [] }
|
||||||
|
|
||||||
using RSpec::Parameterized::TableSyntax
|
using RSpec::Parameterized::TableSyntax
|
||||||
|
|
||||||
where(:entry_name) do
|
where(:entry_name) do
|
||||||
|
@ -70,7 +74,30 @@ RSpec.describe SafeZip::Entry do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when entry does exist' do
|
context 'when entry does not match the filtered files' do
|
||||||
|
let(:directories) { [] }
|
||||||
|
let(:files) { %w(public/index.html public/assets/image.png) }
|
||||||
|
|
||||||
|
using RSpec::Parameterized::TableSyntax
|
||||||
|
|
||||||
|
where(:entry_name) do
|
||||||
|
[
|
||||||
|
'assets/folder/index.html',
|
||||||
|
'public/../folder/index.html',
|
||||||
|
'public/../../../../../index.html',
|
||||||
|
'../../../../../public/index.html',
|
||||||
|
'/etc/passwd'
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
with_them do
|
||||||
|
it 'does not extract file' do
|
||||||
|
is_expected.to be_falsey
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when there is an existing extracted entry' do
|
||||||
before do
|
before do
|
||||||
create_entry
|
create_entry
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,8 +4,10 @@ require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe SafeZip::ExtractParams do
|
RSpec.describe SafeZip::ExtractParams do
|
||||||
let(:target_path) { Dir.mktmpdir("safe-zip") }
|
let(:target_path) { Dir.mktmpdir("safe-zip") }
|
||||||
let(:params) { described_class.new(directories: directories, to: target_path) }
|
let(:real_target_path) { File.realpath(target_path) }
|
||||||
|
let(:params) { described_class.new(directories: directories, files: files, to: target_path) }
|
||||||
let(:directories) { %w(public folder/with/subfolder) }
|
let(:directories) { %w(public folder/with/subfolder) }
|
||||||
|
let(:files) { %w(public/index.html public/assets/image.png) }
|
||||||
|
|
||||||
after do
|
after do
|
||||||
FileUtils.remove_entry_secure(target_path)
|
FileUtils.remove_entry_secure(target_path)
|
||||||
|
@ -14,13 +16,13 @@ RSpec.describe SafeZip::ExtractParams do
|
||||||
describe '#extract_path' do
|
describe '#extract_path' do
|
||||||
subject { params.extract_path }
|
subject { params.extract_path }
|
||||||
|
|
||||||
it { is_expected.to eq(target_path) }
|
it { is_expected.to eq(real_target_path) }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#matching_target_directory' do
|
describe '#matching_target_directory' do
|
||||||
using RSpec::Parameterized::TableSyntax
|
using RSpec::Parameterized::TableSyntax
|
||||||
|
|
||||||
subject { params.matching_target_directory(target_path + path) }
|
subject { params.matching_target_directory(real_target_path + path) }
|
||||||
|
|
||||||
where(:path, :result) do
|
where(:path, :result) do
|
||||||
'/public/index.html' | '/public/'
|
'/public/index.html' | '/public/'
|
||||||
|
@ -30,7 +32,7 @@ RSpec.describe SafeZip::ExtractParams do
|
||||||
end
|
end
|
||||||
|
|
||||||
with_them do
|
with_them do
|
||||||
it { is_expected.to eq(result ? target_path + result : nil) }
|
it { is_expected.to eq(result ? real_target_path + result : nil) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -38,7 +40,7 @@ RSpec.describe SafeZip::ExtractParams do
|
||||||
subject { params.target_directories }
|
subject { params.target_directories }
|
||||||
|
|
||||||
it 'starts with target_path' do
|
it 'starts with target_path' do
|
||||||
is_expected.to all(start_with(target_path + '/'))
|
is_expected.to all(start_with(real_target_path + '/'))
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'ends with / for all paths' do
|
it 'ends with / for all paths' do
|
||||||
|
@ -53,4 +55,27 @@ RSpec.describe SafeZip::ExtractParams do
|
||||||
is_expected.to all(end_with('/*'))
|
is_expected.to all(end_with('/*'))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#matching_target_file' do
|
||||||
|
using RSpec::Parameterized::TableSyntax
|
||||||
|
|
||||||
|
subject { params.matching_target_file(real_target_path + path) }
|
||||||
|
|
||||||
|
where(:path, :result) do
|
||||||
|
'/public/index.html' | true
|
||||||
|
'/non/existing/path' | false
|
||||||
|
'/public/' | false
|
||||||
|
'/folder/with/index.html' | false
|
||||||
|
end
|
||||||
|
|
||||||
|
with_them do
|
||||||
|
it { is_expected.to eq(result) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when directories and files are empty' do
|
||||||
|
it 'is invalid' do
|
||||||
|
expect { described_class.new(to: target_path) }.to raise_error(ArgumentError, /directories or files are required/)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,7 @@ require 'spec_helper'
|
||||||
RSpec.describe SafeZip::Extract do
|
RSpec.describe SafeZip::Extract do
|
||||||
let(:target_path) { Dir.mktmpdir('safe-zip') }
|
let(:target_path) { Dir.mktmpdir('safe-zip') }
|
||||||
let(:directories) { %w(public) }
|
let(:directories) { %w(public) }
|
||||||
|
let(:files) { %w(public/index.html) }
|
||||||
let(:object) { described_class.new(archive) }
|
let(:object) { described_class.new(archive) }
|
||||||
let(:archive) { Rails.root.join('spec', 'fixtures', 'safe_zip', archive_name) }
|
let(:archive) { Rails.root.join('spec', 'fixtures', 'safe_zip', archive_name) }
|
||||||
|
|
||||||
|
@ -13,20 +14,36 @@ RSpec.describe SafeZip::Extract do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#extract' do
|
describe '#extract' do
|
||||||
subject { object.extract(directories: directories, to: target_path) }
|
subject { object.extract(directories: directories, files: files, to: target_path) }
|
||||||
|
|
||||||
shared_examples 'extracts archive' do
|
shared_examples 'extracts archive' do
|
||||||
it 'does extract archive' do
|
context 'when specifying directories' do
|
||||||
subject
|
subject { object.extract(directories: directories, to: target_path) }
|
||||||
|
|
||||||
expect(File.exist?(File.join(target_path, 'public', 'index.html'))).to eq(true)
|
it 'does extract archive' do
|
||||||
expect(File.exist?(File.join(target_path, 'source'))).to eq(false)
|
subject
|
||||||
|
|
||||||
|
expect(File.exist?(File.join(target_path, 'public', 'index.html'))).to eq(true)
|
||||||
|
expect(File.exist?(File.join(target_path, 'public', 'assets', 'image.png'))).to eq(true)
|
||||||
|
expect(File.exist?(File.join(target_path, 'source'))).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when specifying files' do
|
||||||
|
subject { object.extract(files: files, to: target_path) }
|
||||||
|
|
||||||
|
it 'does extract archive' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(File.exist?(File.join(target_path, 'public', 'index.html'))).to eq(true)
|
||||||
|
expect(File.exist?(File.join(target_path, 'public', 'assets', 'image.png'))).to eq(false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
shared_examples 'fails to extract archive' do
|
shared_examples 'fails to extract archive' do
|
||||||
it 'does not extract archive' do
|
it 'does not extract archive' do
|
||||||
expect { subject }.to raise_error(SafeZip::Extract::Error)
|
expect { subject }.to raise_error(SafeZip::Extract::Error, including(error_message))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -38,9 +55,18 @@ RSpec.describe SafeZip::Extract do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
%w(invalid-symlink-does-not-exist.zip invalid-symlinks-outside.zip).each do |name|
|
context 'when zip files are invalid' do
|
||||||
context "when using #{name} archive" do
|
using RSpec::Parameterized::TableSyntax
|
||||||
|
|
||||||
|
where(:name, :message) do
|
||||||
|
'invalid-symlink-does-not-exist.zip' | 'does not exist'
|
||||||
|
'invalid-symlinks-outside.zip' | 'Symlink cannot be created'
|
||||||
|
'invalid-unexpected-large.zip' | 'larger when inflated'
|
||||||
|
end
|
||||||
|
|
||||||
|
with_them do
|
||||||
let(:archive_name) { name }
|
let(:archive_name) { name }
|
||||||
|
let(:error_message) { message }
|
||||||
|
|
||||||
it_behaves_like 'fails to extract archive'
|
it_behaves_like 'fails to extract archive'
|
||||||
end
|
end
|
||||||
|
@ -49,6 +75,19 @@ RSpec.describe SafeZip::Extract do
|
||||||
context 'when no matching directories are found' do
|
context 'when no matching directories are found' do
|
||||||
let(:archive_name) { 'valid-simple.zip' }
|
let(:archive_name) { 'valid-simple.zip' }
|
||||||
let(:directories) { %w(non/existing) }
|
let(:directories) { %w(non/existing) }
|
||||||
|
let(:error_message) { 'No entries extracted' }
|
||||||
|
|
||||||
|
subject { object.extract(directories: directories, to: target_path) }
|
||||||
|
|
||||||
|
it_behaves_like 'fails to extract archive'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when no matching files are found' do
|
||||||
|
let(:archive_name) { 'valid-simple.zip' }
|
||||||
|
let(:files) { %w(non/existing) }
|
||||||
|
let(:error_message) { 'No entries extracted' }
|
||||||
|
|
||||||
|
subject { object.extract(files: files, to: target_path) }
|
||||||
|
|
||||||
it_behaves_like 'fails to extract archive'
|
it_behaves_like 'fails to extract archive'
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
require_migration!
|
||||||
|
|
||||||
|
RSpec.describe ClearDuplicateJobsCookies, :migration, feature_category: :redis do
|
||||||
|
def with_redis(&block)
|
||||||
|
Gitlab::Redis::Queues.with(&block)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'deletes duplicate jobs cookies' do
|
||||||
|
delete = ['resque:gitlab:duplicate:blabla:1:cookie:v2', 'resque:gitlab:duplicate:foobar:2:cookie:v2']
|
||||||
|
keep = ['resque:gitlab:duplicate:something', 'something:cookie:v2']
|
||||||
|
with_redis { |r| (delete + keep).each { |key| r.set(key, 'value') } }
|
||||||
|
|
||||||
|
expect(with_redis { |r| r.exists(delete + keep) }).to eq(4)
|
||||||
|
|
||||||
|
migrate!
|
||||||
|
|
||||||
|
expect(with_redis { |r| r.exists(delete) }).to eq(0)
|
||||||
|
expect(with_redis { |r| r.exists(keep) }).to eq(2)
|
||||||
|
end
|
||||||
|
end
|
|
@ -65,7 +65,6 @@ RSpec.describe Issuable do
|
||||||
it { is_expected.to validate_presence_of(:author) }
|
it { is_expected.to validate_presence_of(:author) }
|
||||||
it { is_expected.to validate_presence_of(:title) }
|
it { is_expected.to validate_presence_of(:title) }
|
||||||
it { is_expected.to validate_length_of(:title).is_at_most(described_class::TITLE_LENGTH_MAX) }
|
it { is_expected.to validate_length_of(:title).is_at_most(described_class::TITLE_LENGTH_MAX) }
|
||||||
it { is_expected.to validate_length_of(:description).is_at_most(described_class::DESCRIPTION_LENGTH_MAX).on(:create) }
|
|
||||||
|
|
||||||
it_behaves_like 'validates description length with custom validation' do
|
it_behaves_like 'validates description length with custom validation' do
|
||||||
before do
|
before do
|
||||||
|
|
|
@ -75,7 +75,58 @@ RSpec.describe Sanitizable do
|
||||||
|
|
||||||
it 'is not valid', :aggregate_failures do
|
it 'is not valid', :aggregate_failures do
|
||||||
expect(record).not_to be_valid
|
expect(record).not_to be_valid
|
||||||
expect(record.errors.full_messages).to include('Name cannot contain escaped HTML entities')
|
expect(record.errors.full_messages).to contain_exactly(
|
||||||
|
'Name cannot contain escaped HTML entities',
|
||||||
|
'Description cannot contain escaped HTML entities'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when input contains double-escaped data' do
|
||||||
|
let_it_be(:input) do
|
||||||
|
'%2526lt%253Bscript%2526gt%253Balert%25281%2529%2526lt%253B%252Fscript%2526gt%253B'
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'noop'
|
||||||
|
|
||||||
|
it 'is not valid', :aggregate_failures do
|
||||||
|
expect(record).not_to be_valid
|
||||||
|
expect(record.errors.full_messages).to contain_exactly(
|
||||||
|
'Name cannot contain escaped components',
|
||||||
|
'Description cannot contain escaped components'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when input contains a path traversal attempt' do
|
||||||
|
let_it_be(:input) { 'main../../../../../../api/v4/projects/1/import_project_members/2' }
|
||||||
|
|
||||||
|
it_behaves_like 'noop'
|
||||||
|
|
||||||
|
it 'is not valid', :aggregate_failures do
|
||||||
|
expect(record).not_to be_valid
|
||||||
|
expect(record.errors.full_messages).to contain_exactly(
|
||||||
|
'Name cannot contain a path traversal component',
|
||||||
|
'Description cannot contain a path traversal component'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when input contains both path traversal attempt and pre-escaped entities' do
|
||||||
|
let_it_be(:input) do
|
||||||
|
'main../../../../../../api/v4/projects/1/import_project_members/2<script>alert(1)</script>'
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'noop'
|
||||||
|
|
||||||
|
it 'is not valid', :aggregate_failures do
|
||||||
|
expect(record).not_to be_valid
|
||||||
|
expect(record.errors.full_messages).to contain_exactly(
|
||||||
|
'Name cannot contain a path traversal component',
|
||||||
|
'Name cannot contain escaped HTML entities',
|
||||||
|
'Description cannot contain a path traversal component',
|
||||||
|
'Description cannot contain escaped HTML entities'
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,7 +18,7 @@ RSpec.describe NamespaceSetting, type: :model do
|
||||||
describe "#default_branch_name_content" do
|
describe "#default_branch_name_content" do
|
||||||
let_it_be(:group) { create(:group) }
|
let_it_be(:group) { create(:group) }
|
||||||
|
|
||||||
let(:namespace_settings) { group.namespace_settings }
|
subject(:namespace_settings) { group.namespace_settings }
|
||||||
|
|
||||||
shared_examples "doesn't return an error" do
|
shared_examples "doesn't return an error" do
|
||||||
it "doesn't return an error" do
|
it "doesn't return an error" do
|
||||||
|
@ -28,6 +28,10 @@ RSpec.describe NamespaceSetting, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when not set" do
|
context "when not set" do
|
||||||
|
before do
|
||||||
|
namespace_settings.default_branch_name = nil
|
||||||
|
end
|
||||||
|
|
||||||
it_behaves_like "doesn't return an error"
|
it_behaves_like "doesn't return an error"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe API::ContainerRegistryEvent do
|
RSpec.describe API::ContainerRegistryEvent do
|
||||||
let(:secret_token) { 'secret_token' }
|
let(:secret_token) { 'secret_token' }
|
||||||
let(:events) { [{ action: 'push' }] }
|
let(:events) { [{ action: 'push' }, { action: 'pull' }] }
|
||||||
let(:registry_headers) { { 'Content-Type' => ::API::ContainerRegistryEvent::DOCKER_DISTRIBUTION_EVENTS_V1_JSON } }
|
let(:registry_headers) { { 'Content-Type' => ::API::ContainerRegistryEvent::DOCKER_DISTRIBUTION_EVENTS_V1_JSON } }
|
||||||
|
|
||||||
describe 'POST /container_registry_event/events' do
|
describe 'POST /container_registry_event/events' do
|
||||||
|
@ -19,14 +19,15 @@ RSpec.describe API::ContainerRegistryEvent do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns 200 status and events are passed to event handler' do
|
it 'returns 200 status and events are passed to event handler' do
|
||||||
event = spy(:event)
|
allow_next_instance_of(::ContainerRegistry::Event) do |event|
|
||||||
allow(::ContainerRegistry::Event).to receive(:new).and_return(event)
|
if event.supported?
|
||||||
expect(event).to receive(:supported?).and_return(true)
|
expect(event).to receive(:handle!).once
|
||||||
|
expect(event).to receive(:track!).once
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
post_events
|
post_events
|
||||||
|
|
||||||
expect(event).to have_received(:handle!).once
|
|
||||||
expect(event).to have_received(:track!).once
|
|
||||||
expect(response).to have_gitlab_http_status(:ok)
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -54,4 +54,17 @@ RSpec.describe Packages::Helm::ExtractFileMetadataService do
|
||||||
|
|
||||||
it { expect { subject }.to raise_error(described_class::ExtractionError, 'Error while parsing Chart.yaml: (<unknown>): did not find expected node content while parsing a flow node at line 2 column 1') }
|
it { expect { subject }.to raise_error(described_class::ExtractionError, 'Error while parsing Chart.yaml: (<unknown>): did not find expected node content while parsing a flow node at line 2 column 1') }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with a corrupted Chart.yaml of incorrect size' do
|
||||||
|
let(:helm_fixture_path) { expand_fixture_path('packages/helm/corrupted_chart.tgz') }
|
||||||
|
let(:expected_error_message) { 'Chart.yaml too big' }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(Zlib::GzipReader).to receive(:new).and_return(Zlib::GzipReader.new(File.open(helm_fixture_path)))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises an error with the expected message' do
|
||||||
|
expect { subject }.to raise_error(::Packages::Helm::ExtractFileMetadataService::ExtractionError, expected_error_message)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,6 +19,8 @@ RSpec.shared_examples 'thread comments for commit and snippet' do |resource_name
|
||||||
|
|
||||||
find('.js-comment-button').click
|
find('.js-comment-button').click
|
||||||
|
|
||||||
|
wait_for_all_requests
|
||||||
|
|
||||||
expect(page).to have_content(comment)
|
expect(page).to have_content(comment)
|
||||||
|
|
||||||
new_comment = all(comments_selector).last
|
new_comment = all(comments_selector).last
|
||||||
|
|
|
@ -10,40 +10,111 @@ RSpec.shared_examples 'matches_cross_reference_regex? fails fast' do
|
||||||
end
|
end
|
||||||
|
|
||||||
RSpec.shared_examples 'validates description length with custom validation' do
|
RSpec.shared_examples 'validates description length with custom validation' do
|
||||||
let(:issuable) { build(:issue, description: 'x' * (::Issuable::DESCRIPTION_LENGTH_MAX + 1)) }
|
let(:invalid_description) { 'x' * (::Issuable::DESCRIPTION_LENGTH_MAX + 1) }
|
||||||
let(:context) { :update }
|
let(:valid_description) { 'short description' }
|
||||||
|
let(:issuable) { build(:issue, description: description) }
|
||||||
|
|
||||||
subject { issuable.validate(context) }
|
let(:error_message) do
|
||||||
|
format(
|
||||||
|
_('is too long (%{size}). The maximum size is %{max_size}.'),
|
||||||
|
size: ActiveSupport::NumberHelper.number_to_human_size(invalid_description.bytesize),
|
||||||
|
max_size: ActiveSupport::NumberHelper.number_to_human_size(::Issuable::DESCRIPTION_LENGTH_MAX)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
subject(:validate) { issuable.validate(context) }
|
||||||
|
|
||||||
context 'when Issuable is a new record' do
|
context 'when Issuable is a new record' do
|
||||||
it 'validates the maximum description length' do
|
let(:context) { :create }
|
||||||
subject
|
|
||||||
expect(issuable.errors[:description]).to eq(["is too long (maximum is #{::Issuable::DESCRIPTION_LENGTH_MAX} characters)"])
|
context 'when description exceeds the maximum size' do
|
||||||
|
let(:description) { invalid_description }
|
||||||
|
|
||||||
|
it 'adds a description too long error' do
|
||||||
|
validate
|
||||||
|
|
||||||
|
expect(issuable.errors[:description]).to contain_exactly(error_message)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'on create' do
|
context 'when description is within the allowed limits' do
|
||||||
let(:context) { :create }
|
let(:description) { valid_description }
|
||||||
|
|
||||||
it 'does not validate the maximum description length' do
|
it 'does not add a validation error' do
|
||||||
allow(issuable).to receive(:description_max_length_for_new_records_is_valid).and_call_original
|
validate
|
||||||
|
|
||||||
subject
|
expect(issuable.errors).not_to have_key(:description)
|
||||||
|
|
||||||
expect(issuable).not_to have_received(:description_max_length_for_new_records_is_valid)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when Issuable is an existing record' do
|
context 'when Issuable is an existing record' do
|
||||||
|
let(:context) { :update }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(issuable).to receive(:expire_etag_cache) # to skip the expire_etag_cache callback
|
allow(issuable).to receive(:expire_etag_cache) # to skip the expire_etag_cache callback
|
||||||
|
|
||||||
|
issuable.description = existing_description
|
||||||
issuable.save!(validate: false)
|
issuable.save!(validate: false)
|
||||||
|
issuable.description = description
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not validate the maximum description length' do
|
context 'when record already had a valid description' do
|
||||||
subject
|
let(:existing_description) { 'small difference so it triggers description_changed?' }
|
||||||
expect(issuable.errors).not_to have_key(:description)
|
|
||||||
|
context 'when new description exceeds the maximum size' do
|
||||||
|
let(:description) { invalid_description }
|
||||||
|
|
||||||
|
it 'adds a description too long error' do
|
||||||
|
validate
|
||||||
|
|
||||||
|
expect(issuable.errors[:description]).to contain_exactly(error_message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when new description is within the allowed limits' do
|
||||||
|
let(:description) { valid_description }
|
||||||
|
|
||||||
|
it 'does not add a validation error' do
|
||||||
|
validate
|
||||||
|
|
||||||
|
expect(issuable.errors).not_to have_key(:description)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when record existed with an invalid description' do
|
||||||
|
let(:existing_description) { "#{invalid_description} small difference so it triggers description_changed?" }
|
||||||
|
|
||||||
|
context 'when description is not changed' do
|
||||||
|
let(:description) { existing_description }
|
||||||
|
|
||||||
|
it 'does not add a validation error' do
|
||||||
|
validate
|
||||||
|
|
||||||
|
expect(issuable.errors).not_to have_key(:description)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when new description exceeds the maximum size' do
|
||||||
|
let(:description) { invalid_description }
|
||||||
|
|
||||||
|
it 'allows updating descriptions that already existed above the limit' do
|
||||||
|
validate
|
||||||
|
|
||||||
|
expect(issuable.errors).not_to have_key(:description)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when new description is within the allowed limits' do
|
||||||
|
let(:description) { valid_description }
|
||||||
|
|
||||||
|
it 'does not add a validation error' do
|
||||||
|
validate
|
||||||
|
|
||||||
|
expect(issuable.errors).not_to have_key(:description)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,8 +32,25 @@ RSpec.shared_examples 'sanitizable' do |factory, fields|
|
||||||
subject { build(factory, attributes) }
|
subject { build(factory, attributes) }
|
||||||
|
|
||||||
it 'is not valid', :aggregate_failures do
|
it 'is not valid', :aggregate_failures do
|
||||||
|
error = 'cannot contain escaped HTML entities'
|
||||||
|
|
||||||
expect(subject).not_to be_valid
|
expect(subject).not_to be_valid
|
||||||
expect(subject.errors.details[field].flat_map(&:values)).to include('cannot contain escaped HTML entities')
|
expect(subject.errors.details[field].flat_map(&:values)).to include(error)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it contains a path component' do
|
||||||
|
let_it_be(:input) do
|
||||||
|
'main../../../../../../api/v4/projects/1/import_project_members/2'
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { build(factory, attributes) }
|
||||||
|
|
||||||
|
it 'is not valid', :aggregate_failures do
|
||||||
|
error = 'cannot contain a path traversal component'
|
||||||
|
|
||||||
|
expect(subject).not_to be_valid
|
||||||
|
expect(subject.errors.details[field].flat_map(&:values)).to include(error)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue