Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #11350 - Duplicate parameters can be created within subtype #2604

Closed
wants to merge 1 commit into from

Conversation

dLobatog
Copy link
Member

Parameter class leaves its :name uniqueness validation to subtypes such as
CommonParameter, GroupParameter, and so forth. This means that one can
trivially create duplicate parameters by calling Parameter.new, then changing
the type attribute of the newly created object.

To avoid this situation (and remove some duplicated validations) we can simply
declare a default validation on all Parameter names scoped by reference_id, and
override it for CommonParameter which doesn't have a reference_id.

@domcleal
Copy link
Contributor

I couldn't reproduce the issue you reported at #2600 (comment), because the unique index catches it.

   (0.1ms)  begin transaction
  SQL (0.6ms)  INSERT INTO "parameters" ("created_at", "hidden_value", "name", "priority", "reference_id", "type", "updated_at", "value") VALUES (?, ?, ?, ?, ?, ?, ?, ?)  [["created_at", Fri, 14 Aug 2015 06:49:35 UTC +00:00], ["hidden_value", false], ["name", "foo"], ["priority", nil], ["reference_id", 2], ["type", "DomainParameter"], ["updated_at", Fri, 14 Aug 2015 06:49:35 UTC +00:00], ["value", nil]]
   (27.4ms)  commit transaction
   (0.1ms)  begin transaction
  SQL (0.4ms)  INSERT INTO "parameters" ("created_at", "hidden_value", "name", "priority", "reference_id", "type", "updated_at", "value") VALUES (?, ?, ?, ?, ?, ?, ?, ?)  [["created_at", Fri, 14 Aug 2015 06:49:35 UTC +00:00], ["hidden_value", false], ["name", "foo"], ["priority", nil], ["reference_id", 2], ["type", "DomainParameter"], ["updated_at", Fri, 14 Aug 2015 06:49:35 UTC +00:00], ["value", nil]]
2015-08-14T07:49:35 [sql] [D] SQLite3::ConstraintException: UNIQUE constraint failed: parameters.type, parameters.reference_id, parameters.name: INSERT INTO "parameters" ("created_at", "hidden_value", "name", "priority", "reference_id", "type", "updated_at", "value") VALUES (?, ?, ?, ?, ?, ?, ?, ?)
   (0.1ms)  rollback transaction
ActiveRecord::StatementInvalid: SQLite3::ConstraintException: UNIQUE constraint failed: parameters.type, parameters.reference_id, parameters.name: INSERT INTO "parameters" ("created_at", "hidden_value", "name", "priority", "reference_id", "type", "updated_at", "value") VALUES (?, ?, ?, ?, ?, ?, ?, ?)

I don't think creating parameters via the parent class and changing the STI 'type' column is correct usage. Perhaps you'd use .becomes or something to change the class, as we probably have this issue in a lot of other STI based models - you rely on having the correct subclass loaded for more than just uniqueness validations.

Oh yes, we also have Foreman::STI which can interpret :type in a .new call, so if that was added to Parameter then you could even do Parameter.new(:type => 'DomainParameter') and you'd actually get a DomainParameter back.

@@ -7,7 +7,7 @@ class Parameter < ActiveRecord::Base

belongs_to_host :foreign_key => :reference_id
include Authorizable
validates :name, :presence => true, :no_whitespace => true
validates :name, :presence => true, :no_whitespace => true, :uniqueness => { :scope => :reference_id }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would uniqueness scope include :type as well? Putting it in the subclass would do this automatically.

Parameter class leaves its :name uniqueness validation to subtypes such as
CommonParameter, GroupParameter, and so forth. This means that one can
trivially create duplicate parameters by calling Parameter.new, then changing
the type attribute of the newly created object.

To avoid this situation (and remove some duplicated validations) we can simply
declare a default validation on all Parameter names scoped by reference_id, and
override it for CommonParameter which doesn't have a reference_id.
@dLobatog
Copy link
Member Author

@domcleal Updated, now it takes into account type in the uniqueness validator. I've also added that to the test.

I don't think it's correct usage either but creating parameters through Parameter.new could happen at some point. Probably something is iffy with my environment, as not only my development db does contain the index but as non_unique (unique doesn't show up on my schema.rb nor when I run SHOW INDEX FROM parameters on mysql), but also when I ran tests with a mint db it seems not to create the index properly either. I'll keep digging if this is something wrong with my env or Foreman.

The patch doesn't provide much if the unique index exists and works, feel free to disregard if you feel the scant LOC savings are not worth the hassle 😄

@domcleal
Copy link
Contributor

Strange that you're missing unique, I can't think why that'd be. We have had bugs such as #8366 so have recreated the index, maybe something went wrong then.

The proposed change does make me somewhat uncomfortable, especially as in #2563 we go in the opposite direction with a different parameter validator by moving them from the base class into the subclasses! (We did this to run validation correctly when the referenced model was unsaved, i.e. when cloning, since reference_id wouldn't be filled in yet.)

@dLobatog
Copy link
Member Author

Alright, will close here & in Redmine, reopen at will.

@dLobatog dLobatog closed this Aug 14, 2015
@dLobatog dLobatog deleted the 11350 branch August 14, 2015 07:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants