Merge branch 'master' into full-post-to-oss-security
Conflicts: doc/release/security.md
This commit is contained in:
commit
6413bfb5c6
29
CHANGELOG
29
CHANGELOG
|
@ -9,6 +9,7 @@ v 6.3.0
|
|||
- Fixed issue with 500 error when group did not exist
|
||||
- Ability to leave project
|
||||
- You can create file in repo using UI
|
||||
- You can remove file from repo using UI
|
||||
- API: dropped default_branch attribute from project during creation
|
||||
- Project default_branch is not stored in db any more. It takes from repo now.
|
||||
- Admin broadcast messages
|
||||
|
@ -16,8 +17,26 @@ v 6.3.0
|
|||
- Dont show last push widget if user removed this branch
|
||||
- Fix 500 error for repos with newline in file name
|
||||
- Extended html titles
|
||||
- API: create/update repo files
|
||||
- API: create/update/delete repo files
|
||||
- Admin can transfer project to any namespace
|
||||
- API: projects/all for admin users
|
||||
- Fix recent branches order
|
||||
|
||||
v 6.2.4
|
||||
- Security: Cast API private_token to string (CVE-2013-4580)
|
||||
- Security: Require gitlab-shell 1.7.8 (CVE-2013-4581, CVE-2013-4582, CVE-2013-4583)
|
||||
- Fix for Git SSH access for LDAP users
|
||||
|
||||
v 6.2.3
|
||||
- Security: More protection against CVE-2013-4489
|
||||
- Security: Require gitlab-shell 1.7.4 (CVE-2013-4490, CVE-2013-4546)
|
||||
- Fix sidekiq rake tasks
|
||||
|
||||
v 6.2.2
|
||||
- Security: Update gitlab_git (CVE-2013-4489)
|
||||
|
||||
v 6.2.1
|
||||
- Security: Fix issue with generated passwords for new users
|
||||
|
||||
v 6.2.0
|
||||
- Public project pages are now visible to everyone (files, issues, wik, etc.)
|
||||
|
@ -104,6 +123,14 @@ v 6.0.0
|
|||
- Improved MR comments logic
|
||||
- Render readme file for projects in public area
|
||||
|
||||
v 5.4.2
|
||||
- Security: Cast API private_token to string (CVE-2013-4580)
|
||||
- Security: Require gitlab-shell 1.7.8 (CVE-2013-4581, CVE-2013-4582, CVE-2013-4583)
|
||||
|
||||
v 5.4.1
|
||||
- Security: Fixes for CVE-2013-4489
|
||||
- Security: Require gitlab-shell 1.7.4 (CVE-2013-4490, CVE-2013-4546)
|
||||
|
||||
v 5.4.0
|
||||
- Ability to edit own comments
|
||||
- Documentation improvements
|
||||
|
|
|
@ -93,6 +93,12 @@ pre.well-pre {
|
|||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
|
||||
&.label-gray {
|
||||
background-color: #eee;
|
||||
color: #999;
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/** Big Labels **/
|
||||
|
|
|
@ -3,6 +3,16 @@ form {
|
|||
|
||||
label {
|
||||
@extend .control-label;
|
||||
|
||||
&.radio-label {
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
|
||||
input[type="radio"] {
|
||||
margin-top: 1px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
module Files
|
||||
class DeleteContext < BaseContext
|
||||
def execute
|
||||
allowed = if project.protected_branch?(ref)
|
||||
can?(current_user, :push_code_to_protected_branches, project)
|
||||
else
|
||||
can?(current_user, :push_code, project)
|
||||
end
|
||||
|
||||
unless allowed
|
||||
return error("You are not allowed to push into this branch")
|
||||
end
|
||||
|
||||
unless repository.branch_names.include?(ref)
|
||||
return error("You can only create files if you are on top of a branch")
|
||||
end
|
||||
|
||||
blob = repository.blob_at(ref, path)
|
||||
|
||||
unless blob
|
||||
return error("You can only edit text files")
|
||||
end
|
||||
|
||||
delete_file_action = Gitlab::Satellite::DeleteFileAction.new(current_user, project, ref, path)
|
||||
|
||||
deleted_successfully = delete_file_action.commit!(
|
||||
nil,
|
||||
params[:commit_message]
|
||||
)
|
||||
|
||||
if deleted_successfully
|
||||
success
|
||||
else
|
||||
error("Your changes could not be commited, because the file has been changed")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -7,9 +7,30 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
before_filter :authorize_code_access!
|
||||
before_filter :require_non_empty_project
|
||||
|
||||
def show
|
||||
@blob = @repository.blob_at(@commit.id, @path)
|
||||
before_filter :blob
|
||||
|
||||
not_found! unless @blob
|
||||
def show
|
||||
end
|
||||
|
||||
def destroy
|
||||
result = Files::DeleteContext.new(@project, current_user, params, @ref, @path).execute
|
||||
|
||||
if result[:status] == :success
|
||||
flash[:notice] = "Your changes have been successfully commited"
|
||||
redirect_to project_tree_path(@project, @ref)
|
||||
else
|
||||
flash[:alert] = result[:error]
|
||||
render :show
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def blob
|
||||
@blob ||= @repository.blob_at(@commit.id, @path)
|
||||
|
||||
return not_found! unless @blob
|
||||
|
||||
@blob
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
- if allowed_tree_edit?
|
||||
= link_to "edit", project_edit_tree_path(@project, @id), class: "btn btn-small"
|
||||
- else
|
||||
%span.btn.btn-small.disabled Edit
|
||||
%span.btn.btn-small.disabled edit
|
||||
= link_to "raw", project_raw_path(@project, @id), class: "btn btn-small", target: "_blank"
|
||||
-# only show normal/blame view links for text files
|
||||
- if @blob.text?
|
||||
|
@ -13,3 +13,7 @@
|
|||
- else
|
||||
= link_to "blame", project_blame_path(@project, @id), class: "btn btn-small" unless @blob.empty?
|
||||
= link_to "history", project_commits_path(@project, @id), class: "btn btn-small"
|
||||
|
||||
- if allowed_tree_edit?
|
||||
= link_to '#modal-remove-blob', class: "remove-blob btn btn-small btn-remove", "data-toggle" => "modal" do
|
||||
remove
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
%div#modal-remove-blob.modal.hide
|
||||
.modal-header
|
||||
%a.close{href: "#", "data-dismiss" => "modal"} ×
|
||||
%h3.page-title Remove #{@blob.name}
|
||||
%p.light
|
||||
From branch
|
||||
%strong= @ref
|
||||
|
||||
.modal-body
|
||||
= form_tag project_blob_path(@project, @id), method: :delete do
|
||||
.control-group.commit_message-group
|
||||
= label_tag 'commit_message', class: "control-label" do
|
||||
Commit message
|
||||
.controls
|
||||
= text_area_tag 'commit_message', params[:commit_message], placeholder: "Removed this file because...", required: true, rows: 3
|
||||
.control-group
|
||||
.controls
|
||||
= submit_tag 'Remove file', class: 'btn btn-remove'
|
||||
= link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
|
|
@ -2,3 +2,6 @@
|
|||
= render 'shared/ref_switcher', destination: 'blob', path: @path
|
||||
%div#tree-holder.tree-holder
|
||||
= render 'blob', blob: @blob
|
||||
|
||||
- if allowed_tree_edit?
|
||||
= render 'projects/blob/remove'
|
||||
|
|
|
@ -13,9 +13,20 @@
|
|||
= f.label :title
|
||||
.controls= f.text_field :title, placeholder: "Example Snippet", class: 'input-xlarge', required: true
|
||||
.control-group
|
||||
= f.label "Private?"
|
||||
= f.label "Access"
|
||||
.controls
|
||||
= f.check_box :private, {class: ''}
|
||||
= f.label :private_true, class: 'radio-label' do
|
||||
= f.radio_button :private, true
|
||||
%span
|
||||
%strong Private
|
||||
(only you can see this snippet)
|
||||
%br
|
||||
= f.label :private_false, class: 'radio-label' do
|
||||
= f.radio_button :private, false
|
||||
%span
|
||||
%strong Public
|
||||
(GitLab users can can see this snippet)
|
||||
|
||||
.control-group
|
||||
.file-editor
|
||||
= f.label :file_name, "File"
|
||||
|
@ -33,9 +44,10 @@
|
|||
- else
|
||||
= f.submit 'Save', class: "btn-save btn"
|
||||
|
||||
= link_to "Cancel", snippets_path(@project), class: "btn btn-cancel"
|
||||
- unless @snippet.new_record?
|
||||
.pull-right= link_to 'Destroy', snippet_path(@snippet), confirm: 'Removed snippet cannot be restored! Are you sure?', method: :delete, class: "btn pull-right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}"
|
||||
.pull-right.prepend-left-20
|
||||
= link_to 'Remove', snippet_path(@snippet), confirm: 'Removed snippet cannot be restored! Are you sure?', method: :delete, class: "btn btn-remove delete-snippet", id: "destroy_snippet_#{@snippet.id}"
|
||||
= link_to "Cancel", snippets_path(@project), class: "btn btn-cancel"
|
||||
|
||||
|
||||
:javascript
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
= link_to reliable_snippet_path(snippet) do
|
||||
= truncate(snippet.title, length: 60)
|
||||
- if snippet.private?
|
||||
%span.label.label-success
|
||||
%span.label.label-gray
|
||||
%i.icon-lock
|
||||
private
|
||||
%span.cgray.monospace.tiny.pull-right
|
||||
|
|
|
@ -173,7 +173,7 @@ Gitlab::Application.routes.draw do
|
|||
end
|
||||
|
||||
scope module: :projects do
|
||||
resources :blob, only: [:show], constraints: {id: /.+/}
|
||||
resources :blob, only: [:show, :destroy], constraints: {id: /.+/}
|
||||
resources :raw, only: [:show], constraints: {id: /.+/}
|
||||
resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ }
|
||||
resources :edit_tree, only: [:show, :update], constraints: {id: /.+/}, path: 'edit'
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
### List projects
|
||||
|
||||
Get a list of projects owned by the authenticated user.
|
||||
Get a list of projects accessible by the authenticated user.
|
||||
|
||||
```
|
||||
GET /projects
|
||||
|
@ -82,6 +82,22 @@ GET /projects
|
|||
```
|
||||
|
||||
|
||||
#### List owned projects
|
||||
|
||||
Get a list of projects owned by the authenticated user.
|
||||
|
||||
```
|
||||
GET /projects/owned
|
||||
```
|
||||
|
||||
#### List ALL projects
|
||||
|
||||
Get a list of all GitLab projects (admin only).
|
||||
|
||||
```
|
||||
GET /projects/all
|
||||
```
|
||||
|
||||
### Get single project
|
||||
|
||||
Get a specific project, identified by project ID or NAMESPACE/PROJECT_NAME , which is owned by the authentication user.
|
||||
|
|
|
@ -397,3 +397,15 @@ Parameters:
|
|||
+ `branch_name` (required) - The name of branch
|
||||
+ `content` (required) - New file content
|
||||
+ `commit_message` (required) - Commit message
|
||||
|
||||
## Delete existing file in repository
|
||||
|
||||
```
|
||||
DELETE /projects/:id/repository/files
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
||||
+ `file_path` (required) - Full path to file. Ex. lib/class.rb
|
||||
+ `branch_name` (required) - The name of branch
|
||||
+ `commit_message` (required) - Commit message
|
||||
|
|
|
@ -13,12 +13,14 @@ Please report suspected security vulnerabilities in private to support@gitlab.co
|
|||
|
||||
1. Verify that the issue can be repoduced
|
||||
1. Acknowledge the issue to the researcher that disclosed it
|
||||
1. Fix the issue on a feature branch, do this on the private dev.gitlab.org server and update the VERSION and CHANGELOG
|
||||
1. Fix the issue on a feature branch, do this on the private GitLab development server and update the VERSION and CHANGELOG in this branch
|
||||
1. Consider creating and testing workarounds
|
||||
1. Create feature branches for the blog posts on GitLab.org and GitLab.com and link them from the code branch
|
||||
1. Merge the code feature branch
|
||||
1. Create a git tag vX.X.X for CE and another one for EE
|
||||
1. Merge the code feature branch into master
|
||||
1. Cherry-pick the code into the latest stable branch
|
||||
1. Create a git tag vX.X.X for CE and another patch release for EE
|
||||
1. Push the code and the tags to all the CE and EE repositories
|
||||
1. Apply the patch to GitLab Cloud and the private GitLab development server
|
||||
1. Merge and publish the blog posts
|
||||
1. Send tweets about the release from @gitlabhq and @git_lab
|
||||
1. Send out an email to the subscribers mailing list on MailChimp
|
||||
|
@ -27,13 +29,17 @@ Please report suspected security vulnerabilities in private to support@gitlab.co
|
|||
1. Post a signed copy of our complete announcement to [oss-security](http://www.openwall.com/lists/oss-security/) and request a CVE number
|
||||
1. Add the security researcher to the [Security Researcher Acknowledgments list](http://www.gitlab.com/vulnerability-acknowledgements/)
|
||||
1. Thank the security researcher in an email for their cooperation
|
||||
1. Update the blogposts and the CHANGELOG when we receive a CVE number
|
||||
1. Update the blogpost and the CHANGELOG when we receive the CVE number
|
||||
|
||||
The timing of the code merge into master should be coordinated in advance.
|
||||
After the merge we strive to publish the announcements within 60 minutes.
|
||||
|
||||
## Blog post template
|
||||
|
||||
XXX Security Advisory for GitLab
|
||||
|
||||
A recently discovered critical vulnerability in GitLab allows [unauthenticated API access|remote code execution|unauthorized access to repositories|XXX|PICKSOMETHING]. All users should update GitLab and gitlab-shell immediately.
|
||||
We [have|haven't|XXX|PICKSOMETHING|] heard of this vulnerability being actively exploited.
|
||||
|
||||
### Version affected
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ class SnippetsFeature < Spinach::FeatureSteps
|
|||
end
|
||||
|
||||
And 'I click link "Destroy"' do
|
||||
click_link "Destroy"
|
||||
click_link "Remove"
|
||||
end
|
||||
|
||||
And 'I submit new snippet "Personal snippet three"' do
|
||||
|
@ -46,7 +46,7 @@ class SnippetsFeature < Spinach::FeatureSteps
|
|||
end
|
||||
|
||||
And 'I uncheck "Private" checkbox' do
|
||||
find(:xpath, "//input[@id='personal_snippet_private']").set true
|
||||
choose "Public"
|
||||
click_button "Save"
|
||||
end
|
||||
|
||||
|
|
|
@ -40,8 +40,7 @@ module API
|
|||
# Update existing file in repository
|
||||
#
|
||||
# Parameters:
|
||||
# file_name (required) - The name of new file. Ex. class.rb
|
||||
# file_path (optional) - The path to new file. Ex. lib/
|
||||
# file_path (optional) - The path to file. Ex. lib/class.rb
|
||||
# branch_name (required) - The name of branch
|
||||
# content (required) - File content
|
||||
# commit_message (required) - Commit message
|
||||
|
@ -67,7 +66,36 @@ module API
|
|||
render_api_error!(result[:error], 400)
|
||||
end
|
||||
end
|
||||
|
||||
# Delete existing file in repository
|
||||
#
|
||||
# Parameters:
|
||||
# file_path (optional) - The path to file. Ex. lib/class.rb
|
||||
# branch_name (required) - The name of branch
|
||||
# content (required) - File content
|
||||
# commit_message (required) - Commit message
|
||||
#
|
||||
# Example Request:
|
||||
# DELETE /projects/:id/repository/files
|
||||
#
|
||||
delete ":id/repository/files" do
|
||||
required_attributes! [:file_path, :branch_name, :commit_message]
|
||||
attrs = attributes_for_keys [:file_path, :branch_name, :commit_message]
|
||||
branch_name = attrs.delete(:branch_name)
|
||||
file_path = attrs.delete(:file_path)
|
||||
result = ::Files::DeleteContext.new(user_project, current_user, attrs, branch_name, file_path).execute
|
||||
|
||||
if result[:status] == :success
|
||||
status(200)
|
||||
|
||||
{
|
||||
file_path: file_path,
|
||||
branch_name: branch_name
|
||||
}
|
||||
else
|
||||
render_api_error!(result[:error], 400)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -31,6 +31,16 @@ module API
|
|||
present @projects, with: Entities::Project
|
||||
end
|
||||
|
||||
# Get all projects for admin user
|
||||
#
|
||||
# Example Request:
|
||||
# GET /projects/all
|
||||
get '/all' do
|
||||
authenticated_as_admin!
|
||||
@projects = paginate Project
|
||||
present @projects, with: Entities::Project
|
||||
end
|
||||
|
||||
# Get a single project
|
||||
#
|
||||
# Parameters:
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
require_relative 'file_action'
|
||||
|
||||
module Gitlab
|
||||
module Satellite
|
||||
class DeleteFileAction < FileAction
|
||||
# Deletes file and creates a new commit for it
|
||||
#
|
||||
# Returns false if committing the change fails
|
||||
# Returns false if pushing from the satellite to bare repo failed or was rejected
|
||||
# Returns true otherwise
|
||||
def commit!(content, commit_message)
|
||||
in_locked_and_timed_satellite do |repo|
|
||||
prepare_satellite!(repo)
|
||||
|
||||
# create target branch in satellite at the corresponding commit from bare repo
|
||||
repo.git.checkout({raise: true, timeout: true, b: true}, ref, "origin/#{ref}")
|
||||
|
||||
# update the file in the satellite's working dir
|
||||
file_path_in_satellite = File.join(repo.working_dir, file_path)
|
||||
File.delete(file_path_in_satellite)
|
||||
|
||||
# add removed file
|
||||
repo.remove(file_path_in_satellite)
|
||||
|
||||
# commit the changes
|
||||
# will raise CommandFailed when commit fails
|
||||
repo.git.commit(raise: true, timeout: true, a: true, m: commit_message)
|
||||
|
||||
|
||||
# push commit back to bare repo
|
||||
# will raise CommandFailed when push fails
|
||||
repo.git.push({raise: true, timeout: true}, :origin, ref)
|
||||
|
||||
# everything worked
|
||||
true
|
||||
end
|
||||
rescue Grit::Git::CommandFailed => ex
|
||||
Gitlab::GitLogger.error(ex.message)
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -8,13 +8,13 @@ module Gitlab
|
|||
#
|
||||
# Returns false if the ref has been updated while editing the file
|
||||
# Returns false if committing the change fails
|
||||
# Returns false if pushing from the satellite to Gitolite failed or was rejected
|
||||
# Returns false if pushing from the satellite to bare repo failed or was rejected
|
||||
# Returns true otherwise
|
||||
def commit!(content, commit_message)
|
||||
in_locked_and_timed_satellite do |repo|
|
||||
prepare_satellite!(repo)
|
||||
|
||||
# create target branch in satellite at the corresponding commit from Gitolite
|
||||
# create target branch in satellite at the corresponding commit from bare repo
|
||||
repo.git.checkout({raise: true, timeout: true, b: true}, ref, "origin/#{ref}")
|
||||
|
||||
# update the file in the satellite's working dir
|
||||
|
@ -26,7 +26,7 @@ module Gitlab
|
|||
repo.git.commit(raise: true, timeout: true, a: true, m: commit_message)
|
||||
|
||||
|
||||
# push commit back to Gitolite
|
||||
# push commit back to bare repo
|
||||
# will raise CommandFailed when push fails
|
||||
repo.git.push({raise: true, timeout: true}, :origin, ref)
|
||||
|
||||
|
|
|
@ -7,13 +7,13 @@ module Gitlab
|
|||
#
|
||||
# Returns false if the ref has been updated while editing the file
|
||||
# Returns false if committing the change fails
|
||||
# Returns false if pushing from the satellite to Gitolite failed or was rejected
|
||||
# Returns false if pushing from the satellite to bare repo failed or was rejected
|
||||
# Returns true otherwise
|
||||
def commit!(content, commit_message)
|
||||
in_locked_and_timed_satellite do |repo|
|
||||
prepare_satellite!(repo)
|
||||
|
||||
# create target branch in satellite at the corresponding commit from Gitolite
|
||||
# create target branch in satellite at the corresponding commit from bare repo
|
||||
repo.git.checkout({raise: true, timeout: true, b: true}, ref, "origin/#{ref}")
|
||||
|
||||
# update the file in the satellite's working dir
|
||||
|
@ -28,7 +28,7 @@ module Gitlab
|
|||
repo.git.commit(raise: true, timeout: true, a: true, m: commit_message)
|
||||
|
||||
|
||||
# push commit back to Gitolite
|
||||
# push commit back to bare repo
|
||||
# will raise CommandFailed when push fails
|
||||
repo.git.push({raise: true, timeout: true}, :origin, ref)
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ module Gitlab
|
|||
in_locked_and_timed_satellite do |merge_repo|
|
||||
prepare_satellite!(merge_repo)
|
||||
if merge_in_satellite!(merge_repo)
|
||||
# push merge back to Gitolite
|
||||
# push merge back to bare repo
|
||||
# will raise CommandFailed when push fails
|
||||
merge_repo.git.push(default_options, :origin, merge_request.target_branch)
|
||||
# remove source branch
|
||||
|
|
|
@ -123,7 +123,7 @@ module Gitlab
|
|||
remotes.each { |name| repo.git.remote(default_options,'rm', name)}
|
||||
end
|
||||
|
||||
# Updates the satellite from Gitolite
|
||||
# Updates the satellite from bare repo
|
||||
#
|
||||
# Note: this will only update remote branches (i.e. origin/*)
|
||||
def update_from_source!
|
||||
|
|
|
@ -78,4 +78,38 @@ describe API::API do
|
|||
response.status.should == 400
|
||||
end
|
||||
end
|
||||
|
||||
describe "DELETE /projects/:id/repository/files" do
|
||||
let(:valid_params) {
|
||||
{
|
||||
file_path: 'spec/spec_helper.rb',
|
||||
branch_name: 'master',
|
||||
commit_message: 'Changed file'
|
||||
}
|
||||
}
|
||||
|
||||
it "should delete existing file in project repo" do
|
||||
Gitlab::Satellite::DeleteFileAction.any_instance.stub(
|
||||
commit!: true,
|
||||
)
|
||||
|
||||
delete api("/projects/#{project.id}/repository/files", user), valid_params
|
||||
response.status.should == 200
|
||||
json_response['file_path'].should == 'spec/spec_helper.rb'
|
||||
end
|
||||
|
||||
it "should return a 400 bad request if no params given" do
|
||||
delete api("/projects/#{project.id}/repository/files", user)
|
||||
response.status.should == 400
|
||||
end
|
||||
|
||||
it "should return a 400 if satellite fails to create file" do
|
||||
Gitlab::Satellite::DeleteFileAction.any_instance.stub(
|
||||
commit!: false,
|
||||
)
|
||||
|
||||
delete api("/projects/#{project.id}/repository/files", user), valid_params
|
||||
response.status.should == 400
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -36,6 +36,32 @@ describe API::API do
|
|||
end
|
||||
end
|
||||
|
||||
describe "GET /projects/all" do
|
||||
context "when unauthenticated" do
|
||||
it "should return authentication error" do
|
||||
get api("/projects/all")
|
||||
response.status.should == 401
|
||||
end
|
||||
end
|
||||
|
||||
context "when authenticated as regular user" do
|
||||
it "should return authentication error" do
|
||||
get api("/projects/all", user)
|
||||
response.status.should == 403
|
||||
end
|
||||
end
|
||||
|
||||
context "when authenticated as admin" do
|
||||
it "should return an array of all projects" do
|
||||
get api("/projects/all", admin)
|
||||
response.status.should == 200
|
||||
json_response.should be_an Array
|
||||
json_response.first['name'].should == project.name
|
||||
json_response.first['owner']['email'].should == user.email
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST /projects" do
|
||||
context "maximum number of projects reached" do
|
||||
before do
|
||||
|
|
Loading…
Reference in New Issue