Project

General

Profile

Actions

Defect #44721

open

Creating an issue with a tracker_id that is not available in the project silently uses another tracker (201 Created instead of 422)

Added by Jan from Planio www.plan.io about 3 hours ago.

Status:
New
Priority:
Normal
Category:
REST API
Resolution:
Affected version:

Description

Steps to reproduce

Project foo has the trackers Feature (2) and Support (3) enabled, Bug (1) is not enabled (or the user's role may not add issues with it). Create an issue through the REST API with the tracker that is not available:

curl -i -H "Content-Type: application/json" -H "X-Redmine-API-Key: $KEY" \
  -d '{"issue":{"project_id":"foo","subject":"test","tracker_id":1}}' \
  https://redmine.example.com/issues.json

Actual result

HTTP/1.1 201 Created. The issue exists with tracker Feature (2), the project's first available tracker. The response body shows the substituted tracker, but there is no error, no warning and no hint that the request was not applied as sent. A client that trusts the 201 does not notice. The same happens in the web UI when a form posts a tracker that is not allowed (see #37007), and PUT /issues/:id with such a tracker_id answers 200 and keeps the old tracker.

Expected result

HTTP/1.1 422 Unprocessable Content with {"errors":["Tracker is not included in the list"]}, the same error the model raises when an existing issue is moved to a tracker that is disabled in the project. A value the client sent explicitly should either be applied or refused, never replaced.

Analysis

In Issue#safe_attributes= (source:trunk/app/models/issue.rb#L602) a tracker_id that is not in allowed_target_trackers(user) is dropped without a trace:

if (t = attrs.delete('tracker_id')) && safe_attribute?('tracker_id')
  if allowed_target_trackers(user).where(:id => t.to_i).exists?
    self.tracker_id = t
  end
end
if project && tracker.nil?
  # Set a default tracker to accept custom field values
  # even if tracker is not specified
  allowed_trackers = allowed_target_trackers(user)
  ...
  self.tracker ||= allowed_trackers.first
end

On a new record tracker is still nil after that, so the fallback that was added in r14083 for #19368 (to accept custom field values when no tracker_id is given) assigns allowed_trackers.first. The check in validate_issue ("Checks that the issue can not be added/moved to a disabled tracker", source:trunk/app/models/issue.rb#L800) never fires, because the disabled tracker was never assigned. The fallback cannot tell "no tracker_id in the request" from "a tracker_id that is not allowed"; the first case is what #19368 wanted, the second should be an error.

allowed_target_trackers also covers the role's per-tracker add_issues permission, so a tracker that is enabled in the project but not permitted for the role is substituted the same way.

Proposed fix

Remember a tracker_id that was sent but not allowed and refuse the record in validation; the fallback for a request without tracker_id stays as it is:

# app/models/issue.rb, safe_attributes=
if (t = attrs.delete('tracker_id')) && safe_attribute?('tracker_id')
  if allowed_target_trackers(user).where(:id => t.to_i).exists?
    self.tracker_id = t
  elsif t.present?
    @unallowed_tracker_id = t
  end
end

# validate_issue
if @unallowed_tracker_id.present?
  errors.add :tracker_id, :inclusion
end

Test for test/integration/api_test/issues_test.rb:

test "POST /issues.json with a tracker that is not enabled in the project should return 422" do
  Project.find(1).update!(:trackers => [Tracker.find(1)])   # Bug only
  assert_no_difference('Issue.count') do
    post '/issues.json',
      :params => {:issue => {:project_id => 1, :tracker_id => 2, :subject => 'API'}},
      :headers => credentials('jsmith')
  end
  assert_response 422
  json = ActiveSupport::JSON.decode(response.body)
  assert_include "Tracker is not included in the list", json['errors']
end

A patch can follow if this direction is agreed.


Related issues

Related to Redmine - Defect #31028: Get 200 response even when specifying an id value that does not exist.NewActions
Related to Redmine - Defect #13267: No error message for invalid field valuesNewActions
Related to Redmine - Defect #37007: Switching project in "New Issue" shows wrong fields and uses disallowed default trackerNewActions
Related to Redmine - Defect #19368: Creating an issue without tracker_id attribute ignores custom field valuesClosedJean-Philippe LangActions
Actions

Also available in: Atom PDF