Skip to content
Snippets Groups Projects
Commit 1e8ef329 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/security/gitlab@12-7-stable-ee

parent efed756a
No related branches found
No related tags found
No related merge requests found
Showing
with 269 additions and 13 deletions
# frozen_string_literal: true
require 'spec_helper'
require 'nokogiri'
describe Gitlab::Asciidoc::IncludeProcessor do
let_it_be(:project) { create(:project, :repository) }
let(:processor_context) do
{
project: project,
max_includes: max_includes,
ref: ref
}
end
let(:ref) { project.repository.root_ref }
let(:max_includes) { 10 }
let(:reader) { Asciidoctor::PreprocessorReader.new(document, lines, 'file.adoc') }
let(:document) { Asciidoctor::Document.new(lines) }
subject(:processor) { described_class.new(processor_context) }
let(:a_blob) { double(:Blob, readable_text?: true, data: a_data) }
let(:a_data) { StringIO.new('include::b.adoc[]') }
let(:lines) { [':max-include-depth: 1000'] + Array.new(10, 'include::a.adoc[]') }
before do
allow(project.repository).to receive(:blob_at).with(ref, 'a.adoc').and_return(a_blob)
end
describe '#include_allowed?' do
it 'allows the first include' do
expect(processor.send(:include_allowed?, 'foo.adoc', reader)).to be_truthy
end
it 'disallows the Nth + 1 include' do
max_includes.times { processor.send(:read_blob, ref, 'a.adoc') }
expect(processor.send(:include_allowed?, 'foo.adoc', reader)).to be_falsey
end
end
end
Loading
Loading
@@ -425,6 +425,24 @@ module Gitlab
create_file(current_file, "= AsciiDoc\n")
end
 
def many_includes(target)
Array.new(10, "include::#{target}[]").join("\n")
end
context 'cyclic imports' do
before do
create_file('doc/api/a.adoc', many_includes('b.adoc'))
create_file('doc/api/b.adoc', many_includes('a.adoc'))
end
let(:include_path) { 'a.adoc' }
let(:requested_path) { 'doc/api/README.md' }
it 'completes successfully' do
is_expected.to include('<p>Include this:</p>')
end
end
context 'with path to non-existing file' do
let(:include_path) { 'not-exists.adoc' }
 
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::NoCacheHeaders do
class NoCacheTester
include Gitlab::NoCacheHeaders
end
describe "#no_cache_headers" do
subject { NoCacheTester.new }
it "raises a RuntimeError" do
expect { subject.no_cache_headers }.to raise_error(RuntimeError)
end
end
end
Loading
Loading
@@ -3,7 +3,7 @@
require 'spec_helper'
 
describe Gitlab::ReferenceExtractor do
let(:project) { create(:project) }
let_it_be(:project) { create(:project) }
 
before do
project.add_developer(project.creator)
Loading
Loading
@@ -293,4 +293,34 @@ describe Gitlab::ReferenceExtractor do
end
end
end
describe '#references' do
let_it_be(:user) { create(:user) }
let_it_be(:issue) { create(:issue, project: project) }
let(:text) { "Ref. #{issue.to_reference}" }
subject { described_class.new(project, user) }
before do
subject.analyze(text)
end
context 'when references are visible' do
before do
project.add_developer(user)
end
it 'returns visible references of given type' do
expect(subject.references(:issue)).to eq([issue])
end
it 'does not increase stateful_not_visible_counter' do
expect { subject.references(:issue) }.not_to change { subject.stateful_not_visible_counter }
end
end
it 'increases stateful_not_visible_counter' do
expect { subject.references(:issue) }.to change { subject.stateful_not_visible_counter }.by(1)
end
end
end
Loading
Loading
@@ -9,7 +9,7 @@ describe GrafanaIntegration do
 
describe 'validations' do
it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_presence_of(:token) }
it { is_expected.to validate_presence_of(:encrypted_token) }
 
it 'disallows invalid urls for grafana_url' do
unsafe_url = %{https://replaceme.com/'><script>alert(document.cookie)</script>}
Loading
Loading
@@ -66,4 +66,24 @@ describe GrafanaIntegration do
end
end
end
describe 'attribute encryption' do
subject(:grafana_integration) { create(:grafana_integration, token: 'super-secret') }
context 'token' do
it 'encrypts original value into encrypted_token attribute' do
expect(grafana_integration.encrypted_token).not_to be_nil
end
it 'locks access to raw value in private method', :aggregate_failures do
expect { grafana_integration.token }.to raise_error(NoMethodError, /private method .token. called/)
expect(grafana_integration.send(:token)).to eql('super-secret')
end
it 'prevents overriding token value with its encrypted or masked version', :aggregate_failures do
expect { grafana_integration.update(token: grafana_integration.encrypted_token) }.not_to change { grafana_integration.reload.send(:token) }
expect { grafana_integration.update(token: grafana_integration.masked_token) }.not_to change { grafana_integration.reload.send(:token) }
end
end
end
end
Loading
Loading
@@ -350,12 +350,12 @@ describe Note do
end
 
describe "cross_reference_not_visible_for?" do
let(:private_user) { create(:user) }
let(:private_project) { create(:project, namespace: private_user.namespace) { |p| p.add_maintainer(private_user) } }
let(:private_issue) { create(:issue, project: private_project) }
let_it_be(:private_user) { create(:user) }
let_it_be(:private_project) { create(:project, namespace: private_user.namespace) { |p| p.add_maintainer(private_user) } }
let_it_be(:private_issue) { create(:issue, project: private_project) }
 
let(:ext_proj) { create(:project, :public) }
let(:ext_issue) { create(:issue, project: ext_proj) }
let_it_be(:ext_proj) { create(:project, :public) }
let_it_be(:ext_issue) { create(:issue, project: ext_proj) }
 
shared_examples "checks references" do
it "returns true" do
Loading
Loading
@@ -393,10 +393,24 @@ describe Note do
it_behaves_like "checks references"
end
 
context "when there are two references in note" do
context "when there is a reference to a label" do
let_it_be(:private_label) { create(:label, project: private_project) }
let(:note) do
create :note,
noteable: ext_issue, project: ext_proj,
note: "added label #{private_label.to_reference(ext_proj)}",
system: true
end
let!(:system_note_metadata) { create(:system_note_metadata, note: note, action: :label) }
it_behaves_like "checks references"
end
context "when there are two references in note" do
let_it_be(:ext_issue2) { create(:issue, project: ext_proj) }
let(:note) do
create :note,
noteable: ext_issue2, project: ext_proj,
note: "mentioned in issue #{private_issue.to_reference(ext_proj)} and " \
"public issue #{ext_issue.to_reference(ext_proj)}",
system: true
Loading
Loading
Loading
Loading
@@ -447,6 +447,18 @@ describe API::Files do
expect(response).to have_gitlab_http_status(200)
end
 
it 'sets no-cache headers' do
url = route('.gitignore') + "/raw"
expect(Gitlab::Workhorse).to receive(:send_git_blob)
get api(url, current_user), params: params
expect(response.headers["Cache-Control"]).to include("no-store")
expect(response.headers["Cache-Control"]).to include("no-cache")
expect(response.headers["Pragma"]).to eq("no-cache")
expect(response.headers["Expires"]).to eq("Fri, 01 Jan 1990 00:00:00 GMT")
end
context 'when mandatory params are not given' do
it_behaves_like '400 response' do
let(:request) { get api(route("any%2Ffile"), current_user) }
Loading
Loading
Loading
Loading
@@ -45,7 +45,7 @@ describe 'Getting Grafana Integration' do
 
it_behaves_like 'a working graphql query'
 
it { expect(integration_data['token']).to eql grafana_integration.token }
it { expect(integration_data['token']).to eql grafana_integration.masked_token }
it { expect(integration_data['grafanaUrl']).to eql grafana_integration.grafana_url }
 
it do
Loading
Loading
Loading
Loading
@@ -1545,7 +1545,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
 
authorize_artifacts
 
expect(response).to have_gitlab_http_status(500)
expect(response).to have_gitlab_http_status(:forbidden)
end
 
context 'authorization token is invalid' do
Loading
Loading
@@ -1675,6 +1675,18 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
end
end
 
context 'Is missing GitLab Workhorse token headers' do
let(:jwt_token) { JWT.encode({ 'iss' => 'invalid-header' }, Gitlab::Workhorse.secret, 'HS256') }
it 'fails to post artifacts without GitLab-Workhorse' do
expect(Gitlab::ErrorTracking).to receive(:track_exception).once
upload_artifacts(file_upload, headers_with_token)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'when setting an expire date' do
let(:default_artifacts_expire_in) {}
let(:post_data) do
Loading
Loading
Loading
Loading
@@ -10,6 +10,10 @@ describe Projects::ImportExport::ExportService do
let(:service) { described_class.new(project, user) }
let!(:after_export_strategy) { Gitlab::ImportExport::AfterExportStrategies::DownloadNotificationStrategy.new }
 
before do
project.add_maintainer(user)
end
it 'saves the version' do
expect(Gitlab::ImportExport::VersionSaver).to receive(:new).and_call_original
 
Loading
Loading
@@ -137,5 +141,18 @@ describe Projects::ImportExport::ExportService do
expect(service).not_to receive(:execute_after_export_action)
end
end
context 'when user does not have admin_project permission' do
let!(:another_user) { create(:user) }
subject(:service) { described_class.new(project, another_user) }
it 'fails' do
expected_message =
"User with ID: %s does not have permission to Project %s with ID: %s." %
[another_user.id, project.name, project.id]
expect { service.execute }.to raise_error(Gitlab::ImportExport::Error).with_message(expected_message)
end
end
end
end
Loading
Loading
@@ -210,7 +210,7 @@ describe Projects::Operations::UpdateService do
integration = project.reload.grafana_integration
 
expect(integration.grafana_url).to eq(expected_attrs[:grafana_url])
expect(integration.token).to eq(expected_attrs[:token])
expect(integration.send(:token)).to eq(expected_attrs[:token])
end
end
 
Loading
Loading
@@ -226,7 +226,7 @@ describe Projects::Operations::UpdateService do
integration = project.reload.grafana_integration
 
expect(integration.grafana_url).to eq(expected_attrs[:grafana_url])
expect(integration.token).to eq(expected_attrs[:token])
expect(integration.send(:token)).to eq(expected_attrs[:token])
end
 
context 'with all grafana attributes blank in params' do
Loading
Loading
Loading
Loading
@@ -5,7 +5,7 @@ require "spec_helper"
describe Projects::UpdatePagesService do
let_it_be(:project, refind: true) { create(:project, :repository) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit('HEAD').sha) }
let_it_be(:build) { create(:ci_build, pipeline: pipeline, ref: 'HEAD') }
let(:build) { create(:ci_build, pipeline: pipeline, ref: 'HEAD') }
let(:invalid_file) { fixture_file_upload('spec/fixtures/dk.png') }
 
let(:file) { fixture_file_upload("spec/fixtures/pages.zip") }
Loading
Loading
@@ -204,6 +204,32 @@ describe Projects::UpdatePagesService do
end
end
 
context 'when file size is spoofed' do
let(:metadata) { spy('metadata') }
include_context 'pages zip with spoofed size'
before do
file = fixture_file_upload(fake_zip_path, 'pages.zip')
metafile = fixture_file_upload('spec/fixtures/pages.zip.meta')
create(:ci_job_artifact, :archive, file: file, job: build)
create(:ci_job_artifact, :metadata, file: metafile, job: build)
allow(build).to receive(:artifacts_metadata_entry)
.and_return(metadata)
allow(metadata).to receive(:total_size).and_return(100)
end
it 'raises an error' do
expect do
subject.execute
end.to raise_error(Projects::UpdatePagesService::FailedToExtractError,
'Entry public/index.html should be 1B but is larger when inflated')
expect(deploy_status).to be_script_failure
end
end
def deploy_status
GenericCommitStatus.find_by(name: 'pages:deploy')
end
Loading
Loading
Loading
Loading
@@ -5,6 +5,11 @@ module ReferenceParserHelpers
Nokogiri::HTML.fragment('<a></a>').children[0]
end
 
def expect_gathered_references(result, visible, not_visible_count)
expect(result[:visible]).to eq(visible)
expect(result[:not_visible].count).to eq(not_visible_count)
end
shared_examples 'no project N+1 queries' do
it 'avoids N+1 queries in #nodes_visible_to_user', :request_store do
context = Banzai::RenderContext.new(project, user)
Loading
Loading
# frozen_string_literal: true
# the idea of creating zip archive with spoofed size is borrowed from
# https://github.com/rubyzip/rubyzip/pull/403/files#diff-118213fb4baa6404a40f89e1147661ebR88
RSpec.shared_context 'pages zip with spoofed size' do
let(:real_zip_path) { Tempfile.new(['real', '.zip']).path }
let(:fake_zip_path) { Tempfile.new(['fake', '.zip']).path }
before do
full_file_name = 'public/index.html'
true_size = 500_000
fake_size = 1
::Zip::File.open(real_zip_path, ::Zip::File::CREATE) do |zf|
zf.get_output_stream(full_file_name) do |os|
os.write 'a' * true_size
end
end
compressed_size = nil
::Zip::File.open(real_zip_path) do |zf|
a_entry = zf.find_entry(full_file_name)
compressed_size = a_entry.compressed_size
end
true_size_bytes = [compressed_size, true_size, full_file_name.size].pack('LLS')
fake_size_bytes = [compressed_size, fake_size, full_file_name.size].pack('LLS')
data = File.binread(real_zip_path)
data.gsub! true_size_bytes, fake_size_bytes
File.open(fake_zip_path, 'wb') do |file|
file.write data
end
end
after do
File.delete(real_zip_path) if File.exist?(real_zip_path)
File.delete(fake_zip_path) if File.exist?(fake_zip_path)
end
end
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment