diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index 3a6a9b7a70d..a26b986aeb0 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -4,195 +4,192 @@ describe 'Git HTTP requests', lib: true do let(:user) { create(:user) } let(:project) { create(:project) } - describe "#call" do - context "when the project doesn't exist" do - context "when no authentication is provided" do + context "when the project doesn't exist" do + context "when no authentication is provided" do + it "responds with status 401" do + download('doesnt/exist.git') do |response| + expect(response.status).to eq(401) + end + end + end + + context "when username and password are provided" do + context "when authentication fails" do it "responds with status 401" do - download('doesnt/exist.git') do |response| + download('doesnt/exist.git', user: user.username, password: "nope") do |response| expect(response.status).to eq(401) end end end - context "when username and password are provided" do - context "when authentication fails" do - it "responds with status 401" do - download('doesnt/exist.git', user: user.username, password: "nope") do |response| - expect(response.status).to eq(401) - end - end - end - - context "when authentication succeeds" do - it "responds with status 404" do - download('/doesnt/exist.git', user: user.username, password: user.password) do |response| - expect(response.status).to eq(404) - end - end - end - end - end - - context "when the Wiki for a project exists" do - it "responds with the right project" do - wiki = ProjectWiki.new(project) - project.update_attribute(:visibility_level, Project::PUBLIC) - - download("/#{wiki.repository.path_with_namespace}.git") do |response| - json_body = ActiveSupport::JSON.decode(response.body) - - expect(response.status).to eq(200) - expect(json_body['RepoPath']).to include(wiki.repository.path_with_namespace) - end - end - end - - context "when the project exists" do - let(:path) { "#{project.path_with_namespace}.git" } - let(:env) { {} } - - context "when the project is public" do - before do - project.update_attribute(:visibility_level, Project::PUBLIC) - end - - it "responds with status 200" do - download(path, env) do |response| - expect(response.status).to eq(200) - end - end - - context 'but git-upload-pack is disabled' do - it "responds with status 404" do - allow(Gitlab.config.gitlab_shell).to receive(:upload_pack).and_return(false) - - download(path, env) do |response| - expect(response.status).to eq(404) - end - end - end - end - - context "when the project is private" do - before do - project.update_attribute(:visibility_level, Project::PRIVATE) - end - - context "when no authentication is provided" do - it "responds with status 401" do - download(path, env) do |response| - expect(response.status).to eq(401) - end - end - end - - context "when username and password are provided" do - let(:env) { { user: user.username, password: 'nope' } } - - context "when authentication fails" do - it "responds with status 401" do - download(path, env) do |response| - expect(response.status).to eq(401) - end - end - - context "when the user is IP banned" do - it "responds with status 401" do - expect(Rack::Attack::Allow2Ban).to receive(:filter).and_return(true) - allow_any_instance_of(Rack::Request).to receive(:ip).and_return('1.2.3.4') - - clone_get(path, env) - - expect(response.status).to eq(401) - end - end - end - - context "when authentication succeeds" do - let(:env) { { user: user.username, password: user.password } } - - context "when the user has access to the project" do - before do - project.team << [user, :master] - end - - context "when the user is blocked" do - it "responds with status 404" do - user.block - project.team << [user, :master] - - download(path, env) do |response| - expect(response.status).to eq(404) - end - end - end - - context "when the user isn't blocked" do - it "responds with status 200" do - expect(Rack::Attack::Allow2Ban).to receive(:reset) - - clone_get(path, env) - - expect(response.status).to eq(200) - end - end - - context "when blank password attempts follow a valid login" do - def attempt_login(include_password) - password = include_password ? user.password : "" - clone_get path, user: user.username, password: password - response.status - end - - it "repeated attempts followed by successful attempt" do - options = Gitlab.config.rack_attack.git_basic_auth - maxretry = options[:maxretry] - 1 - ip = '1.2.3.4' - - allow_any_instance_of(Rack::Request).to receive(:ip).and_return(ip) - Rack::Attack::Allow2Ban.reset(ip, options) - - maxretry.times.each do - expect(attempt_login(false)).to eq(401) - end - - expect(attempt_login(true)).to eq(200) - expect(Rack::Attack::Allow2Ban.banned?(ip)).to be_falsey - - maxretry.times.each do - expect(attempt_login(false)).to eq(401) - end - - Rack::Attack::Allow2Ban.reset(ip, options) - end - end - end - - context "when the user doesn't have access to the project" do - it "responds with status 404" do - download(path, user: user.username, password: user.password) do |response| - expect(response.status).to eq(404) - end - end - end - end - end - - context "when a gitlab ci token is provided" do - it "responds with status 200" do - token = "123" - project = FactoryGirl.create :empty_project - project.update_attributes(runners_token: token, builds_enabled: true) - - clone_get "#{project.path_with_namespace}.git", user: 'gitlab-ci-token', password: token - - expect(response.status).to eq(200) + context "when authentication succeeds" do + it "responds with status 404" do + download('/doesnt/exist.git', user: user.username, password: user.password) do |response| + expect(response.status).to eq(404) end end end end end + context "when the Wiki for a project exists" do + it "responds with the right project" do + wiki = ProjectWiki.new(project) + project.update_attribute(:visibility_level, Project::PUBLIC) + + download("/#{wiki.repository.path_with_namespace}.git") do |response| + json_body = ActiveSupport::JSON.decode(response.body) + + expect(response.status).to eq(200) + expect(json_body['RepoPath']).to include(wiki.repository.path_with_namespace) + end + end + end + + context "when the project exists" do + let(:path) { "#{project.path_with_namespace}.git" } + let(:env) { {} } + + context "when the project is public" do + before do + project.update_attribute(:visibility_level, Project::PUBLIC) + end + + it "responds with status 200" do + download(path, env) do |response| + expect(response.status).to eq(200) + end + end + + context 'but git-upload-pack is disabled' do + it "responds with status 404" do + allow(Gitlab.config.gitlab_shell).to receive(:upload_pack).and_return(false) + + download(path, env) do |response| + expect(response.status).to eq(404) + end + end + end + end + + context "when the project is private" do + before do + project.update_attribute(:visibility_level, Project::PRIVATE) + end + + context "when no authentication is provided" do + it "responds with status 401" do + download(path, env) do |response| + expect(response.status).to eq(401) + end + end + end + + context "when username and password are provided" do + let(:env) { { user: user.username, password: 'nope' } } + + context "when authentication fails" do + it "responds with status 401" do + download(path, env) do |response| + expect(response.status).to eq(401) + end + end + + context "when the user is IP banned" do + it "responds with status 401" do + expect(Rack::Attack::Allow2Ban).to receive(:filter).and_return(true) + allow_any_instance_of(Rack::Request).to receive(:ip).and_return('1.2.3.4') + + clone_get(path, env) + + expect(response.status).to eq(401) + end + end + end + + context "when authentication succeeds" do + let(:env) { { user: user.username, password: user.password } } + + context "when the user has access to the project" do + before do + project.team << [user, :master] + end + + context "when the user is blocked" do + it "responds with status 404" do + user.block + project.team << [user, :master] + + download(path, env) do |response| + expect(response.status).to eq(404) + end + end + end + + context "when the user isn't blocked" do + it "responds with status 200" do + expect(Rack::Attack::Allow2Ban).to receive(:reset) + + clone_get(path, env) + + expect(response.status).to eq(200) + end + end + + context "when blank password attempts follow a valid login" do + def attempt_login(include_password) + password = include_password ? user.password : "" + clone_get path, user: user.username, password: password + response.status + end + + it "repeated attempts followed by successful attempt" do + options = Gitlab.config.rack_attack.git_basic_auth + maxretry = options[:maxretry] - 1 + ip = '1.2.3.4' + + allow_any_instance_of(Rack::Request).to receive(:ip).and_return(ip) + Rack::Attack::Allow2Ban.reset(ip, options) + + maxretry.times.each do + expect(attempt_login(false)).to eq(401) + end + + expect(attempt_login(true)).to eq(200) + expect(Rack::Attack::Allow2Ban.banned?(ip)).to be_falsey + + maxretry.times.each do + expect(attempt_login(false)).to eq(401) + end + + Rack::Attack::Allow2Ban.reset(ip, options) + end + end + end + + context "when the user doesn't have access to the project" do + it "responds with status 404" do + download(path, user: user.username, password: user.password) do |response| + expect(response.status).to eq(404) + end + end + end + end + end + + context "when a gitlab ci token is provided" do + it "responds with status 200" do + token = "123" + project = FactoryGirl.create :empty_project + project.update_attributes(runners_token: token, builds_enabled: true) + + clone_get "#{project.path_with_namespace}.git", user: 'gitlab-ci-token', password: token + + expect(response.status).to eq(200) + end + end + end + end def clone_get(project, options={}) get "/#{project}/info/refs", { service: 'git-upload-pack' }, auth_env(*options.values_at(:user, :password)) end