)]}'
{"keystone/application_credential/__init__.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"009ae0bcd6a8b3f3cada913fe8cab89b77679966","unresolved":false,"context_lines":[{"line_number":10,"context_line":"# License for the specific language governing permissions and limitations"},{"line_number":11,"context_line":"# under the License."},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"pass"}],"source_content_type":"text/x-python","patch_set":15,"id":"9f91af0f_9a20abb2","side":"PARENT","line":13,"range":{"start_line":13,"start_character":0,"end_line":13,"end_character":4},"updated":"2018-01-05 18:38:49.000000000","message":"Aha, I was going to comment on this in the previous patch :)","commit_id":"44ad208eae321a07a55d3b18dd3ac26f520e0d91"}],"keystone/application_credential/core.py":[{"author":{"_account_id":2218,"name":"Adam Young","email":"adam@younglogic.com","username":"ayoung"},"change_message_id":"fb835c570e93facc6d575257490ce4cc2b70cd38","unresolved":false,"context_lines":[{"line_number":59,"context_line":"        \"\"\""},{"line_number":60,"context_line":"        trust \u003d {"},{"line_number":61,"context_line":"            \u0027trustor_user_id\u0027: application_credential[\u0027user_id\u0027],"},{"line_number":62,"context_line":"            \u0027trustee_user_id\u0027: application_credential[\u0027user_id\u0027],"},{"line_number":63,"context_line":"            \u0027project_id\u0027: application_credential[\u0027project_id\u0027],"},{"line_number":64,"context_line":"            \u0027expires_at\u0027: application_credential.get(\u0027expires_at\u0027),"},{"line_number":65,"context_line":"            \u0027impersonation\u0027: False"}],"source_content_type":"text/x-python","patch_set":2,"id":"df87a7cf_ae26f0b6","line":62,"updated":"2017-12-03 03:03:20.000000000","message":"I think that maybe this is not right.  The trustee should be the new \"user\" which should be the abstraction behind the application_credential.","commit_id":"0274a3e0c99cb413447e7191c7f5fd667594d8d7"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"74c7ea42539752957d2d38ed954edf9e7c607f29","unresolved":false,"context_lines":[{"line_number":55,"context_line":"            self._delete_app_creds_on_user_delete_callback)"},{"line_number":56,"context_line":"        notifications.register_event_callback("},{"line_number":57,"context_line":"            notifications.ACTIONS.internal,"},{"line_number":58,"context_line":"            # This notification is emitted when a role assignment is removed,"},{"line_number":59,"context_line":"            # we can take advantage of it even though we\u0027re not a token."},{"line_number":60,"context_line":"            notifications.INVALIDATE_USER_PROJECT_TOKEN_PERSISTENCE,"},{"line_number":61,"context_line":"            self._delete_app_creds_on_assignment_removal)"},{"line_number":62,"context_line":""},{"line_number":63,"context_line":"    def _delete_app_creds_on_user_delete_callback("}],"source_content_type":"text/x-python","patch_set":15,"id":"9f91af0f_c7a3d29d","line":60,"range":{"start_line":58,"start_character":12,"end_line":60,"end_character":68},"updated":"2018-01-04 23:21:11.000000000","message":"When we remove the sql token storage layer we\u0027re going to have to make sure we repurpose this to be specific to application credentials.","commit_id":"904183c7305d76295998e2255893cdd0e209945d"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"009ae0bcd6a8b3f3cada913fe8cab89b77679966","unresolved":false,"context_lines":[{"line_number":55,"context_line":"            self._delete_app_creds_on_user_delete_callback)"},{"line_number":56,"context_line":"        notifications.register_event_callback("},{"line_number":57,"context_line":"            notifications.ACTIONS.internal,"},{"line_number":58,"context_line":"            # This notification is emitted when a role assignment is removed,"},{"line_number":59,"context_line":"            # we can take advantage of it even though we\u0027re not a token."},{"line_number":60,"context_line":"            notifications.INVALIDATE_USER_PROJECT_TOKEN_PERSISTENCE,"},{"line_number":61,"context_line":"            self._delete_app_creds_on_assignment_removal)"},{"line_number":62,"context_line":""},{"line_number":63,"context_line":"    def _delete_app_creds_on_user_delete_callback("}],"source_content_type":"text/x-python","patch_set":15,"id":"9f91af0f_0e2c6097","line":60,"range":{"start_line":58,"start_character":12,"end_line":60,"end_character":68},"in_reply_to":"9f91af0f_c7a3d29d","updated":"2018-01-05 18:38:49.000000000","message":"Good call on this BTW.. I tested this locally and it worked when I removed a user from a project.","commit_id":"904183c7305d76295998e2255893cdd0e209945d"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"009ae0bcd6a8b3f3cada913fe8cab89b77679966","unresolved":false,"context_lines":[{"line_number":95,"context_line":"    def authenticate(self, request, application_credential_id, secret):"},{"line_number":96,"context_line":"        self.driver.authenticate(application_credential_id, secret)"},{"line_number":97,"context_line":""},{"line_number":98,"context_line":"    def create_application_credential(self, application_credential,"},{"line_number":99,"context_line":"                                      initiator\u003dNone):"},{"line_number":100,"context_line":"        \"\"\"Create a new application credential."},{"line_number":101,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"9f91af0f_ee4d7c72","line":98,"range":{"start_line":98,"start_character":44,"end_line":98,"end_character":66},"updated":"2018-01-05 18:38:49.000000000","message":"I assume the application credential ID is going to be generated by the controller?","commit_id":"904183c7305d76295998e2255893cdd0e209945d"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"57f63f4f699e5b596edc3a8f840548a0a458819c","unresolved":false,"context_lines":[{"line_number":95,"context_line":"    def authenticate(self, request, application_credential_id, secret):"},{"line_number":96,"context_line":"        self.driver.authenticate(application_credential_id, secret)"},{"line_number":97,"context_line":""},{"line_number":98,"context_line":"    def create_application_credential(self, application_credential,"},{"line_number":99,"context_line":"                                      initiator\u003dNone):"},{"line_number":100,"context_line":"        \"\"\"Create a new application credential."},{"line_number":101,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"9f91af0f_ff6dfb31","line":98,"range":{"start_line":98,"start_character":44,"end_line":98,"end_character":66},"in_reply_to":"9f91af0f_2e6112d4","updated":"2018-01-08 22:46:22.000000000","message":"That\u0027s a good question and I\u0027m not sure I know why that is... I think I\u0027d be fine if we just keep everything in the dict and not include an argument we don\u0027t use. That feels more DRY to me. But whatever you decide will be OK with me.\n\nSide note: but we should probably fix that in other places, too, but obviously not a pressing thing.","commit_id":"904183c7305d76295998e2255893cdd0e209945d"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"c0b64687627539ccc3d27e752d5a5eb8ceb756ce","unresolved":false,"context_lines":[{"line_number":95,"context_line":"    def authenticate(self, request, application_credential_id, secret):"},{"line_number":96,"context_line":"        self.driver.authenticate(application_credential_id, secret)"},{"line_number":97,"context_line":""},{"line_number":98,"context_line":"    def create_application_credential(self, application_credential,"},{"line_number":99,"context_line":"                                      initiator\u003dNone):"},{"line_number":100,"context_line":"        \"\"\"Create a new application credential."},{"line_number":101,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"9f91af0f_2e6112d4","line":98,"range":{"start_line":98,"start_character":44,"end_line":98,"end_character":66},"in_reply_to":"9f91af0f_ee4d7c72","updated":"2018-01-07 21:08:04.000000000","message":"Yeah, the controller uses _assign_unique_id to insert an ID into the dict, which is consistent with how other modules work. What\u0027s inconsistent here is most managers/drivers include a separate argument for the ID but then never use it. Not sure if there\u0027s a real reason for that or if I should add that just for consistency.","commit_id":"904183c7305d76295998e2255893cdd0e209945d"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"8a0ee50015cb47623debc3e298ec9962278753d1","unresolved":false,"context_lines":[{"line_number":75,"context_line":"            user_id\u003duser_id,"},{"line_number":76,"context_line":"            project_id\u003dproject_id,"},{"line_number":77,"context_line":"            effective\u003dTrue)"},{"line_number":78,"context_line":"        return list(set([x[\u0027role_id\u0027] for x in assignment_list]))"},{"line_number":79,"context_line":""},{"line_number":80,"context_line":"    def _require_user_has_role_in_project(self, roles, user_id, project_id):"},{"line_number":81,"context_line":"        user_roles \u003d self._get_user_roles(user_id, project_id)"}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_369a2c14","line":78,"updated":"2018-01-11 20:14:16.000000000","message":"Ah - so this answers my question in the previous patch. If I provide a list of roles that contain duplicates when I create an app cred, this should prune my list down to a set of unique roles. Got it.","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"8a0ee50015cb47623debc3e298ec9962278753d1","unresolved":false,"context_lines":[{"line_number":109,"context_line":"            self._APP_CRED, application_credential[\u0027id\u0027], initiator)"},{"line_number":110,"context_line":"        return ref"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":"    def get_application_credential(self, application_credential_id):"},{"line_number":113,"context_line":"        \"\"\"Get application credential details."},{"line_number":114,"context_line":""},{"line_number":115,"context_line":"        :returns: an application credential"}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_36c30cf0","line":112,"updated":"2018-01-11 20:14:16.000000000","message":"We can implement caching on these methods.","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"1fa18bb95d26997417f2d2b52f06a61db4a1828b","unresolved":false,"context_lines":[{"line_number":109,"context_line":"            self._APP_CRED, application_credential[\u0027id\u0027], initiator)"},{"line_number":110,"context_line":"        return ref"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":"    def get_application_credential(self, application_credential_id):"},{"line_number":113,"context_line":"        \"\"\"Get application credential details."},{"line_number":114,"context_line":""},{"line_number":115,"context_line":"        :returns: an application credential"}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_f7ba7edc","line":112,"in_reply_to":"7f96bb07_36c30cf0","updated":"2018-01-11 21:26:42.000000000","message":"Done","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"8a0ee50015cb47623debc3e298ec9962278753d1","unresolved":false,"context_lines":[{"line_number":122,"context_line":"    def list_application_credentials(self, user_id, hints\u003dNone):"},{"line_number":123,"context_line":"        \"\"\"List application credentials for a user."},{"line_number":124,"context_line":""},{"line_number":125,"context_line":"        :returns: a plist of application credentials"},{"line_number":126,"context_line":"        \"\"\""},{"line_number":127,"context_line":"        hints \u003d hints or driver_hints.Hints()"},{"line_number":128,"context_line":"        return self.driver.list_application_credentials_for_user("}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_965f8040","line":125,"range":{"start_line":125,"start_character":20,"end_line":125,"end_character":25},"updated":"2018-01-11 20:14:16.000000000","message":"nit: list*","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"1fa18bb95d26997417f2d2b52f06a61db4a1828b","unresolved":false,"context_lines":[{"line_number":122,"context_line":"    def list_application_credentials(self, user_id, hints\u003dNone):"},{"line_number":123,"context_line":"        \"\"\"List application credentials for a user."},{"line_number":124,"context_line":""},{"line_number":125,"context_line":"        :returns: a plist of application credentials"},{"line_number":126,"context_line":"        \"\"\""},{"line_number":127,"context_line":"        hints \u003d hints or driver_hints.Hints()"},{"line_number":128,"context_line":"        return self.driver.list_application_credentials_for_user("}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_57c9f275","line":125,"range":{"start_line":125,"start_character":20,"end_line":125,"end_character":25},"in_reply_to":"7f96bb07_965f8040","updated":"2018-01-11 21:26:42.000000000","message":"Done","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":15054,"name":"wangxiyuan","email":"wangxiyuan1007@gmail.com","username":"wangxiyuan"},"change_message_id":"81512c422ddb7cde77b340370505e0e21751c7c1","unresolved":false,"context_lines":[{"line_number":154,"context_line":"        :raises keystone.exception.ApplicationCredentialNotFound: If the"},{"line_number":155,"context_line":"            application credential doesn\u0027t exist."},{"line_number":156,"context_line":"        \"\"\""},{"line_number":157,"context_line":"        self.driver.delete_application_credential(application_credential_id)"},{"line_number":158,"context_line":"        notifications.Audit.deleted("},{"line_number":159,"context_line":"            self._APP_CRED, application_credential_id, initiator)"},{"line_number":160,"context_line":""}],"source_content_type":"text/x-python","patch_set":32,"id":"7f96bb07_dc9cdf0f","line":157,"updated":"2018-01-16 12:02:32.000000000","message":"we should invalidate the cache data here. Right?","commit_id":"837cf8ceadb55f109b0b2675e259f856d1774db5"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"fbc6bc6091b716114eff76e7b944fe05126d3ee7","unresolved":false,"context_lines":[{"line_number":154,"context_line":"        :raises keystone.exception.ApplicationCredentialNotFound: If the"},{"line_number":155,"context_line":"            application credential doesn\u0027t exist."},{"line_number":156,"context_line":"        \"\"\""},{"line_number":157,"context_line":"        self.driver.delete_application_credential(application_credential_id)"},{"line_number":158,"context_line":"        notifications.Audit.deleted("},{"line_number":159,"context_line":"            self._APP_CRED, application_credential_id, initiator)"},{"line_number":160,"context_line":""}],"source_content_type":"text/x-python","patch_set":32,"id":"7f96bb07_38c93dab","line":157,"in_reply_to":"7f96bb07_dc9cdf0f","updated":"2018-01-16 21:17:35.000000000","message":"Done","commit_id":"837cf8ceadb55f109b0b2675e259f856d1774db5"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"536b93de2e9b21feeb9511223eb6f84f2a95d116","unresolved":false,"context_lines":[{"line_number":79,"context_line":"            user_id\u003duser_id,"},{"line_number":80,"context_line":"            project_id\u003dproject_id,"},{"line_number":81,"context_line":"            effective\u003dTrue)"},{"line_number":82,"context_line":"        return list(set([x[\u0027role_id\u0027] for x in assignment_list]))"},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"    def _require_user_has_role_in_project(self, roles, user_id, project_id):"},{"line_number":85,"context_line":"        user_roles \u003d self._get_user_roles(user_id, project_id)"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_5a209df7","line":82,"range":{"start_line":82,"start_character":20,"end_line":82,"end_character":23},"updated":"2018-01-17 18:12:32.000000000","message":"Based on this, it looks like assignment list is a list of dictionaries, which are the role references. We have a utility method in common that removes duplicate dictionaries from a list. We had a bug this release or last release with code very similar to this that wasn\u0027t removing duplicates because of dictionary ordering (which set doesn\u0027t seem to account for).\n\nhttps://github.com/openstack/keystone/blob/28abf3e44b0319c7a2f7f86392e1362bac10bf93/keystone/common/utils.py#L123\n\nWe might be able to do something like:\n\n  def _get_user_roles(self, user_id, project_id):\n      assignment_list \u003d PROVIDERS.assignment_api.list_role_assignments(\n          user_id\u003duser_id, project_id\u003dproject_id, effective\u003dTrue\n      )\n      return utils.remove_duplicate_dicts_by_id(assignment_list)","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"bc804c87ce8022a9d0e589c311cc2d6fe881f742","unresolved":false,"context_lines":[{"line_number":79,"context_line":"            user_id\u003duser_id,"},{"line_number":80,"context_line":"            project_id\u003dproject_id,"},{"line_number":81,"context_line":"            effective\u003dTrue)"},{"line_number":82,"context_line":"        return list(set([x[\u0027role_id\u0027] for x in assignment_list]))"},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"    def _require_user_has_role_in_project(self, roles, user_id, project_id):"},{"line_number":85,"context_line":"        user_roles \u003d self._get_user_roles(user_id, project_id)"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_3bd91356","line":82,"range":{"start_line":82,"start_character":20,"end_line":82,"end_character":23},"in_reply_to":"7f96bb07_207c7eea","updated":"2018-01-17 19:34:03.000000000","message":"Oh - good call... nevermind","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"f42e97dab64a1dc43b030f6a0f41f66966a72424","unresolved":false,"context_lines":[{"line_number":79,"context_line":"            user_id\u003duser_id,"},{"line_number":80,"context_line":"            project_id\u003dproject_id,"},{"line_number":81,"context_line":"            effective\u003dTrue)"},{"line_number":82,"context_line":"        return list(set([x[\u0027role_id\u0027] for x in assignment_list]))"},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"    def _require_user_has_role_in_project(self, roles, user_id, project_id):"},{"line_number":85,"context_line":"        user_roles \u003d self._get_user_roles(user_id, project_id)"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_207c7eea","line":82,"range":{"start_line":82,"start_character":20,"end_line":82,"end_character":23},"in_reply_to":"7f96bb07_5a209df7","updated":"2018-01-17 19:25:29.000000000","message":"The thing is that the end result here is a list of ids, but the output of that method is a list of dictionaries. In order to use that it would have to look something like this:\n\n return [r[\u0027id\u0027] for r in utils.remove_duplicate_dicts_by_id(\n            [{\u0027id\u0027: a[\u0027role_id\u0027]} for a in assignment_list])]\n\nwhich is a bit verbose but not the worst","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"536b93de2e9b21feeb9511223eb6f84f2a95d116","unresolved":false,"context_lines":[{"line_number":83,"context_line":""},{"line_number":84,"context_line":"    def _require_user_has_role_in_project(self, roles, user_id, project_id):"},{"line_number":85,"context_line":"        user_roles \u003d self._get_user_roles(user_id, project_id)"},{"line_number":86,"context_line":"        for role in roles:"},{"line_number":87,"context_line":"            matching_roles \u003d [x for x in user_roles"},{"line_number":88,"context_line":"                              if x \u003d\u003d role[\u0027id\u0027]]"},{"line_number":89,"context_line":"            if not matching_roles:"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_1aca151a","line":86,"updated":"2018-01-17 18:12:32.000000000","message":"If it\u0027s possible to create an application credential without roles, we might need to check that there is at least one thing in user_roles.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"f42e97dab64a1dc43b030f6a0f41f66966a72424","unresolved":false,"context_lines":[{"line_number":83,"context_line":""},{"line_number":84,"context_line":"    def _require_user_has_role_in_project(self, roles, user_id, project_id):"},{"line_number":85,"context_line":"        user_roles \u003d self._get_user_roles(user_id, project_id)"},{"line_number":86,"context_line":"        for role in roles:"},{"line_number":87,"context_line":"            matching_roles \u003d [x for x in user_roles"},{"line_number":88,"context_line":"                              if x \u003d\u003d role[\u0027id\u0027]]"},{"line_number":89,"context_line":"            if not matching_roles:"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_4068aa1b","line":86,"in_reply_to":"7f96bb07_1aca151a","updated":"2018-01-17 19:25:29.000000000","message":"It should not be possible if they go through the REST API. If the user doesn\u0027t specify a role in their request then the roles are taken from the token. They can\u0027t do this with an unscoped token so there will always be a role.\n\nHowever, if someone is trying to write some kind of plugin and not going through the REST API then I guess they could hit this, can add a guard.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"bc804c87ce8022a9d0e589c311cc2d6fe881f742","unresolved":false,"context_lines":[{"line_number":83,"context_line":""},{"line_number":84,"context_line":"    def _require_user_has_role_in_project(self, roles, user_id, project_id):"},{"line_number":85,"context_line":"        user_roles \u003d self._get_user_roles(user_id, project_id)"},{"line_number":86,"context_line":"        for role in roles:"},{"line_number":87,"context_line":"            matching_roles \u003d [x for x in user_roles"},{"line_number":88,"context_line":"                              if x \u003d\u003d role[\u0027id\u0027]]"},{"line_number":89,"context_line":"            if not matching_roles:"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_9bd2a727","line":86,"in_reply_to":"7f96bb07_4068aa1b","updated":"2018-01-17 19:34:03.000000000","message":"Ok - so roles is ultimately optional, but pull from the token in that case. Which is consistent with what we have in the spec:\n\nhttp://specs.openstack.org/openstack/keystone-specs/specs/keystone/queens/application-credentials.html#application-credential-management\n\nPerfect, thanks.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"536b93de2e9b21feeb9511223eb6f84f2a95d116","unresolved":false,"context_lines":[{"line_number":87,"context_line":"            matching_roles \u003d [x for x in user_roles"},{"line_number":88,"context_line":"                              if x \u003d\u003d role[\u0027id\u0027]]"},{"line_number":89,"context_line":"            if not matching_roles:"},{"line_number":90,"context_line":"                raise exception.RoleAssignmentNotFound(role_id\u003drole[\u0027id\u0027],"},{"line_number":91,"context_line":"                                                       actor_id\u003duser_id,"},{"line_number":92,"context_line":"                                                       target_id\u003dproject_id)"},{"line_number":93,"context_line":""}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_9a062552","line":90,"updated":"2018-01-17 18:12:32.000000000","message":"This is only used when creating an application credential. Would this be considered invalid data if a user supplied roles in the application credential reference that they didn\u0027t have? If so, should we return a 400 instead of a 404?","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"bc804c87ce8022a9d0e589c311cc2d6fe881f742","unresolved":false,"context_lines":[{"line_number":87,"context_line":"            matching_roles \u003d [x for x in user_roles"},{"line_number":88,"context_line":"                              if x \u003d\u003d role[\u0027id\u0027]]"},{"line_number":89,"context_line":"            if not matching_roles:"},{"line_number":90,"context_line":"                raise exception.RoleAssignmentNotFound(role_id\u003drole[\u0027id\u0027],"},{"line_number":91,"context_line":"                                                       actor_id\u003duser_id,"},{"line_number":92,"context_line":"                                                       target_id\u003dproject_id)"},{"line_number":93,"context_line":""}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_1ba457b9","line":90,"in_reply_to":"7f96bb07_00a14246","updated":"2018-01-17 19:34:03.000000000","message":"Yeah - I think that\u0027s fine. I just wanted to make sure we weren\u0027t bubbling this up to the user if we should be returning a 400 instead.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"f42e97dab64a1dc43b030f6a0f41f66966a72424","unresolved":false,"context_lines":[{"line_number":87,"context_line":"            matching_roles \u003d [x for x in user_roles"},{"line_number":88,"context_line":"                              if x \u003d\u003d role[\u0027id\u0027]]"},{"line_number":89,"context_line":"            if not matching_roles:"},{"line_number":90,"context_line":"                raise exception.RoleAssignmentNotFound(role_id\u003drole[\u0027id\u0027],"},{"line_number":91,"context_line":"                                                       actor_id\u003duser_id,"},{"line_number":92,"context_line":"                                                       target_id\u003dproject_id)"},{"line_number":93,"context_line":""}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_00a14246","line":90,"in_reply_to":"7f96bb07_9a062552","updated":"2018-01-17 19:25:29.000000000","message":"Agreed, I transformed it here: https://review.openstack.org/#/c/524423/33/keystone/application_credential/controllers.py@115\n\nI suppose I could bring that down here? Sort of felt like a layer violation to me","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"536b93de2e9b21feeb9511223eb6f84f2a95d116","unresolved":false,"context_lines":[{"line_number":105,"context_line":"        app_cred_ref.pop(\u0027secret_hash\u0027)"},{"line_number":106,"context_line":"        app_cred_ref[\u0027roles\u0027] \u003d self._get_role_list("},{"line_number":107,"context_line":"            app_cred_ref[\u0027roles\u0027])"},{"line_number":108,"context_line":"        id \u003d app_cred_ref.pop(\u0027application_credential_id\u0027)"},{"line_number":109,"context_line":"        app_cred_ref[\u0027id\u0027] \u003d id"},{"line_number":110,"context_line":"        return app_cred_ref"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":"    def create_application_credential(self, application_credential,"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_fa5de978","line":109,"range":{"start_line":108,"start_character":8,"end_line":109,"end_character":31},"updated":"2018-01-17 18:12:32.000000000","message":"We can move this to the sql implementation of the backend.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"f42e97dab64a1dc43b030f6a0f41f66966a72424","unresolved":false,"context_lines":[{"line_number":105,"context_line":"        app_cred_ref.pop(\u0027secret_hash\u0027)"},{"line_number":106,"context_line":"        app_cred_ref[\u0027roles\u0027] \u003d self._get_role_list("},{"line_number":107,"context_line":"            app_cred_ref[\u0027roles\u0027])"},{"line_number":108,"context_line":"        id \u003d app_cred_ref.pop(\u0027application_credential_id\u0027)"},{"line_number":109,"context_line":"        app_cred_ref[\u0027id\u0027] \u003d id"},{"line_number":110,"context_line":"        return app_cred_ref"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":"    def create_application_credential(self, application_credential,"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_609126f1","line":109,"range":{"start_line":108,"start_character":8,"end_line":109,"end_character":31},"in_reply_to":"7f96bb07_fa5de978","updated":"2018-01-17 19:25:29.000000000","message":"Fixed in next patchset","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"536b93de2e9b21feeb9511223eb6f84f2a95d116","unresolved":false,"context_lines":[{"line_number":113,"context_line":"                                      initiator\u003dNone):"},{"line_number":114,"context_line":"        \"\"\"Create a new application credential."},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"        :returns: a new application credential"},{"line_number":117,"context_line":"        \"\"\""},{"line_number":118,"context_line":"        application_credential \u003d application_credential.copy()"},{"line_number":119,"context_line":"        user_id \u003d application_credential[\u0027user_id\u0027]"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_9a970549","line":116,"range":{"start_line":116,"start_character":9,"end_line":116,"end_character":16},"updated":"2018-01-17 18:12:32.000000000","message":"nit: We could document the application_credential parameter, too.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"536b93de2e9b21feeb9511223eb6f84f2a95d116","unresolved":false,"context_lines":[{"line_number":115,"context_line":""},{"line_number":116,"context_line":"        :returns: a new application credential"},{"line_number":117,"context_line":"        \"\"\""},{"line_number":118,"context_line":"        application_credential \u003d application_credential.copy()"},{"line_number":119,"context_line":"        user_id \u003d application_credential[\u0027user_id\u0027]"},{"line_number":120,"context_line":"        project_id \u003d application_credential[\u0027project_id\u0027]"},{"line_number":121,"context_line":"        roles \u003d application_credential.pop(\u0027roles\u0027)"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_5a765d40","line":118,"range":{"start_line":118,"start_character":8,"end_line":118,"end_character":30},"updated":"2018-01-17 18:12:32.000000000","message":"If we\u0027re using the same name to store the copy, can\u0027t we just use the original?","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"f42e97dab64a1dc43b030f6a0f41f66966a72424","unresolved":false,"context_lines":[{"line_number":115,"context_line":""},{"line_number":116,"context_line":"        :returns: a new application credential"},{"line_number":117,"context_line":"        \"\"\""},{"line_number":118,"context_line":"        application_credential \u003d application_credential.copy()"},{"line_number":119,"context_line":"        user_id \u003d application_credential[\u0027user_id\u0027]"},{"line_number":120,"context_line":"        project_id \u003d application_credential[\u0027project_id\u0027]"},{"line_number":121,"context_line":"        roles \u003d application_credential.pop(\u0027roles\u0027)"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_bb3e83b5","line":118,"range":{"start_line":118,"start_character":8,"end_line":118,"end_character":30},"in_reply_to":"7f96bb07_5a765d40","updated":"2018-01-17 19:25:29.000000000","message":"I was having problems with the unit tests where I wanted to compare the output of the create/get with the reference dict, but the create modifies the object since it\u0027s passed by reference. That made me think it\u0027s probably better form to make a copy rather than operate on the original.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"536b93de2e9b21feeb9511223eb6f84f2a95d116","unresolved":false,"context_lines":[{"line_number":118,"context_line":"        application_credential \u003d application_credential.copy()"},{"line_number":119,"context_line":"        user_id \u003d application_credential[\u0027user_id\u0027]"},{"line_number":120,"context_line":"        project_id \u003d application_credential[\u0027project_id\u0027]"},{"line_number":121,"context_line":"        roles \u003d application_credential.pop(\u0027roles\u0027)"},{"line_number":122,"context_line":"        self._require_user_has_role_in_project(roles, user_id, project_id)"},{"line_number":123,"context_line":"        unhashed_secret \u003d application_credential[\u0027secret\u0027]"},{"line_number":124,"context_line":"        ref \u003d self.driver.create_application_credential("}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_7a49d9b4","line":121,"range":{"start_line":121,"start_character":38,"end_line":121,"end_character":51},"updated":"2018-01-17 18:12:32.000000000","message":"Roles are required when creating an application credential, right?","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"bc804c87ce8022a9d0e589c311cc2d6fe881f742","unresolved":false,"context_lines":[{"line_number":118,"context_line":"        application_credential \u003d application_credential.copy()"},{"line_number":119,"context_line":"        user_id \u003d application_credential[\u0027user_id\u0027]"},{"line_number":120,"context_line":"        project_id \u003d application_credential[\u0027project_id\u0027]"},{"line_number":121,"context_line":"        roles \u003d application_credential.pop(\u0027roles\u0027)"},{"line_number":122,"context_line":"        self._require_user_has_role_in_project(roles, user_id, project_id)"},{"line_number":123,"context_line":"        unhashed_secret \u003d application_credential[\u0027secret\u0027]"},{"line_number":124,"context_line":"        ref \u003d self.driver.create_application_credential("}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_bb920356","line":121,"range":{"start_line":121,"start_character":38,"end_line":121,"end_character":51},"in_reply_to":"7f96bb07_3b7cb381","updated":"2018-01-17 19:34:03.000000000","message":"Got it, your response to my other comments cleared this up. The controller seems like an appropriate place to do this. And we can certainly move it later if we decide to.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"f42e97dab64a1dc43b030f6a0f41f66966a72424","unresolved":false,"context_lines":[{"line_number":118,"context_line":"        application_credential \u003d application_credential.copy()"},{"line_number":119,"context_line":"        user_id \u003d application_credential[\u0027user_id\u0027]"},{"line_number":120,"context_line":"        project_id \u003d application_credential[\u0027project_id\u0027]"},{"line_number":121,"context_line":"        roles \u003d application_credential.pop(\u0027roles\u0027)"},{"line_number":122,"context_line":"        self._require_user_has_role_in_project(roles, user_id, project_id)"},{"line_number":123,"context_line":"        unhashed_secret \u003d application_credential[\u0027secret\u0027]"},{"line_number":124,"context_line":"        ref \u003d self.driver.create_application_credential("}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_3b7cb381","line":121,"range":{"start_line":121,"start_character":38,"end_line":121,"end_character":51},"in_reply_to":"7f96bb07_7a49d9b4","updated":"2018-01-17 19:25:29.000000000","message":"Yes this should always come in from the controller with roles.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"536b93de2e9b21feeb9511223eb6f84f2a95d116","unresolved":false,"context_lines":[{"line_number":163,"context_line":"        notifications.Audit.deleted("},{"line_number":164,"context_line":"            self._APP_CRED, application_credential_id, initiator)"},{"line_number":165,"context_line":""},{"line_number":166,"context_line":"    def delete_application_credentials_for_user(self, user_id):"},{"line_number":167,"context_line":"        \"\"\"Delete all application credentials for a user."},{"line_number":168,"context_line":""},{"line_number":169,"context_line":"        This is triggered when a user is deleted."}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_1a66952b","line":166,"updated":"2018-01-17 18:12:32.000000000","message":"Same comment here as on line 173. I\u0027m just wondering if we should keep these public if they are only used in callbacks.\n\nIt would totally make sense to keep them if we expose an API for users to delete all their application credentials. Or a privileged API for administrators to delete all application credentials for a user, without actually deleting or disabling the user.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"f42e97dab64a1dc43b030f6a0f41f66966a72424","unresolved":false,"context_lines":[{"line_number":163,"context_line":"        notifications.Audit.deleted("},{"line_number":164,"context_line":"            self._APP_CRED, application_credential_id, initiator)"},{"line_number":165,"context_line":""},{"line_number":166,"context_line":"    def delete_application_credentials_for_user(self, user_id):"},{"line_number":167,"context_line":"        \"\"\"Delete all application credentials for a user."},{"line_number":168,"context_line":""},{"line_number":169,"context_line":"        This is triggered when a user is deleted."}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_1bec5728","line":166,"in_reply_to":"7f96bb07_1a66952b","updated":"2018-01-17 19:25:29.000000000","message":"Yeah, both of those could be potentially useful. It wasn\u0027t part of the spec so I didn\u0027t make them part of the public API. I could make these private for now and then make them unprivate if we decide to expose them.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"bc804c87ce8022a9d0e589c311cc2d6fe881f742","unresolved":false,"context_lines":[{"line_number":163,"context_line":"        notifications.Audit.deleted("},{"line_number":164,"context_line":"            self._APP_CRED, application_credential_id, initiator)"},{"line_number":165,"context_line":""},{"line_number":166,"context_line":"    def delete_application_credentials_for_user(self, user_id):"},{"line_number":167,"context_line":"        \"\"\"Delete all application credentials for a user."},{"line_number":168,"context_line":""},{"line_number":169,"context_line":"        This is triggered when a user is deleted."}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_7b98fb73","line":166,"in_reply_to":"7f96bb07_1bec5728","updated":"2018-01-17 19:34:03.000000000","message":"++ that\u0027s a good idea.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"536b93de2e9b21feeb9511223eb6f84f2a95d116","unresolved":false,"context_lines":[{"line_number":170,"context_line":"        \"\"\""},{"line_number":171,"context_line":"        self.driver.delete_application_credentials_for_user(user_id)"},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"    def delete_application_credentials_for_user_on_project(self, user_id,"},{"line_number":174,"context_line":"                                                           project_id):"},{"line_number":175,"context_line":"        \"\"\"Delete all application credentials for a user on a given project."},{"line_number":176,"context_line":""}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_1aa455b9","line":173,"range":{"start_line":173,"start_character":8,"end_line":173,"end_character":58},"updated":"2018-01-17 18:12:32.000000000","message":"This is only used for the callback. Do we plan to expose this via a public API? If not, do we want to consider not making it a public method, or just roll it into the logic of the callback method?","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"22bea188cf4d6aaddff20cbdf1206f2560d79d14","unresolved":false,"context_lines":[{"line_number":65,"context_line":"    def _delete_app_creds_on_user_delete_callback("},{"line_number":66,"context_line":"            self, service, resource_type, operation, payload):"},{"line_number":67,"context_line":"        user_id \u003d payload[\u0027resource_info\u0027]"},{"line_number":68,"context_line":"        self.delete_application_credentials_for_user(user_id)"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"    def _delete_app_creds_on_assignment_removal("},{"line_number":71,"context_line":"            self, service, resource_type, operation, payload):"}],"source_content_type":"text/x-python","patch_set":37,"id":"7f96bb07_4dd9c254","line":68,"range":{"start_line":68,"start_character":13,"end_line":68,"end_character":52},"updated":"2018-01-17 20:09:27.000000000","message":"This is using the driver implementation directly instead of using the private methods.","commit_id":"0476549cd8afd613a02edf8cc6329478ee3963c1"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"22bea188cf4d6aaddff20cbdf1206f2560d79d14","unresolved":false,"context_lines":[{"line_number":71,"context_line":"            self, service, resource_type, operation, payload):"},{"line_number":72,"context_line":"        user_id \u003d payload[\u0027resource_info\u0027][\u0027user_id\u0027]"},{"line_number":73,"context_line":"        project_id \u003d payload[\u0027resource_info\u0027][\u0027project_id\u0027]"},{"line_number":74,"context_line":"        self.delete_application_credentials_for_user_on_project(user_id,"},{"line_number":75,"context_line":"                                                                project_id)"},{"line_number":76,"context_line":""},{"line_number":77,"context_line":"    def _get_user_roles(self, user_id, project_id):"}],"source_content_type":"text/x-python","patch_set":37,"id":"7f96bb07_ad24065f","line":74,"range":{"start_line":74,"start_character":13,"end_line":74,"end_character":63},"updated":"2018-01-17 20:09:27.000000000","message":"hah - I was wondering why this was still passing since we made this a private method. This is using the manager directly.","commit_id":"0476549cd8afd613a02edf8cc6329478ee3963c1"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"017d7607cb661d0c9ccb4a6a6de2d160cea6619e","unresolved":false,"context_lines":[{"line_number":71,"context_line":"            self, service, resource_type, operation, payload):"},{"line_number":72,"context_line":"        user_id \u003d payload[\u0027resource_info\u0027][\u0027user_id\u0027]"},{"line_number":73,"context_line":"        project_id \u003d payload[\u0027resource_info\u0027][\u0027project_id\u0027]"},{"line_number":74,"context_line":"        self.delete_application_credentials_for_user_on_project(user_id,"},{"line_number":75,"context_line":"                                                                project_id)"},{"line_number":76,"context_line":""},{"line_number":77,"context_line":"    def _get_user_roles(self, user_id, project_id):"}],"source_content_type":"text/x-python","patch_set":37,"id":"7f96bb07_63efede8","line":74,"range":{"start_line":74,"start_character":13,"end_line":74,"end_character":63},"in_reply_to":"7f96bb07_2379e592","updated":"2018-01-17 21:20:13.000000000","message":"This behavior is also noted on line 37 and 38.","commit_id":"0476549cd8afd613a02edf8cc6329478ee3963c1"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"0f03aeba1813a61c071e269a295391d176235998","unresolved":false,"context_lines":[{"line_number":71,"context_line":"            self, service, resource_type, operation, payload):"},{"line_number":72,"context_line":"        user_id \u003d payload[\u0027resource_info\u0027][\u0027user_id\u0027]"},{"line_number":73,"context_line":"        project_id \u003d payload[\u0027resource_info\u0027][\u0027project_id\u0027]"},{"line_number":74,"context_line":"        self.delete_application_credentials_for_user_on_project(user_id,"},{"line_number":75,"context_line":"                                                                project_id)"},{"line_number":76,"context_line":""},{"line_number":77,"context_line":"    def _get_user_roles(self, user_id, project_id):"}],"source_content_type":"text/x-python","patch_set":37,"id":"7f96bb07_2379e592","line":74,"range":{"start_line":74,"start_character":13,"end_line":74,"end_character":63},"in_reply_to":"7f96bb07_ad24065f","updated":"2018-01-17 21:09:05.000000000","message":"That\u0027s...weird\n\n (Pdb) self                                                                                                                                                                                                                                                                               \n\n \u003ckeystone.application_credential.core.Manager object at 0x7f76c3b61c50\u003e                                                                                                                                                                                                                  \n\n (Pdb) self.delete_application_credentials_for_user                                                                                                                                                                                                                                       \n\n \u003cbound method ApplicationCredential.delete_application_credentials_for_user of \u003ckeystone.application_credential.backends.sql.ApplicationCredential object at 0x7f76c3d97f60\u003e\u003e","commit_id":"0476549cd8afd613a02edf8cc6329478ee3963c1"}],"keystone/conf/application_credential.py":[{"author":{"_account_id":2218,"name":"Adam Young","email":"adam@younglogic.com","username":"ayoung"},"change_message_id":"fa98d20b93303b0ecbbb4f9a17360de47543ab91","unresolved":false,"context_lines":[{"line_number":32,"context_line":"]"},{"line_number":33,"context_line":""},{"line_number":34,"context_line":""},{"line_number":35,"context_line":"def register_opts(conf):"},{"line_number":36,"context_line":"    conf.register_opts(ALL_OPTS, group\u003dGROUP_NAME)"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"df87a7cf_2e32e0f2","line":35,"updated":"2017-12-03 03:12:32.000000000","message":"I think this needs to contain 2 foreign keys:\n1: The Trust\n2: The service_user for the credential.","commit_id":"0274a3e0c99cb413447e7191c7f5fd667594d8d7"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"8a0ee50015cb47623debc3e298ec9962278753d1","unresolved":false,"context_lines":[{"line_number":28,"context_line":""},{"line_number":29,"context_line":"GROUP_NAME \u003d __name__.split(\u0027.\u0027)[-1]"},{"line_number":30,"context_line":"ALL_OPTS \u003d ["},{"line_number":31,"context_line":"    driver,"},{"line_number":32,"context_line":"]"},{"line_number":33,"context_line":""},{"line_number":34,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_f63fe4d3","line":31,"updated":"2018-01-11 20:14:16.000000000","message":"We could expose caching options here, too. Or we can do that in a subsequent patch to keep patch sizes sane.","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"1fa18bb95d26997417f2d2b52f06a61db4a1828b","unresolved":false,"context_lines":[{"line_number":28,"context_line":""},{"line_number":29,"context_line":"GROUP_NAME \u003d __name__.split(\u0027.\u0027)[-1]"},{"line_number":30,"context_line":"ALL_OPTS \u003d ["},{"line_number":31,"context_line":"    driver,"},{"line_number":32,"context_line":"]"},{"line_number":33,"context_line":""},{"line_number":34,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_579ed263","line":31,"in_reply_to":"7f96bb07_f63fe4d3","updated":"2018-01-11 21:26:42.000000000","message":"I\u0027ll opt for doing it later","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":15054,"name":"wangxiyuan","email":"wangxiyuan1007@gmail.com","username":"wangxiyuan"},"change_message_id":"81512c422ddb7cde77b340370505e0e21751c7c1","unresolved":false,"context_lines":[{"line_number":24,"context_line":"driver, so there is no reason to change this unless you are providing a custom"},{"line_number":25,"context_line":"entry point."},{"line_number":26,"context_line":"\"\"\"))"},{"line_number":27,"context_line":""},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"GROUP_NAME \u003d __name__.split(\u0027.\u0027)[-1]"},{"line_number":30,"context_line":"ALL_OPTS \u003d ["}],"source_content_type":"text/x-python","patch_set":32,"id":"7f96bb07_5ce20fa2","line":27,"updated":"2018-01-16 12:02:32.000000000","message":"it\u0027s better to add the related \u0027caching\u0027 and \u0027cache_time\u0027 configs as well","commit_id":"837cf8ceadb55f109b0b2675e259f856d1774db5"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"fbc6bc6091b716114eff76e7b944fe05126d3ee7","unresolved":false,"context_lines":[{"line_number":24,"context_line":"driver, so there is no reason to change this unless you are providing a custom"},{"line_number":25,"context_line":"entry point."},{"line_number":26,"context_line":"\"\"\"))"},{"line_number":27,"context_line":""},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"GROUP_NAME \u003d __name__.split(\u0027.\u0027)[-1]"},{"line_number":30,"context_line":"ALL_OPTS \u003d ["}],"source_content_type":"text/x-python","patch_set":32,"id":"7f96bb07_f8c6759a","line":27,"in_reply_to":"7f96bb07_5ce20fa2","updated":"2018-01-16 21:17:35.000000000","message":"Done","commit_id":"837cf8ceadb55f109b0b2675e259f856d1774db5"}],"keystone/tests/unit/application_credential/test_backends.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"8a0ee50015cb47623debc3e298ec9962278753d1","unresolved":false,"context_lines":[{"line_number":54,"context_line":""},{"line_number":55,"context_line":"    def test_create_duplicate_application_credential(self):"},{"line_number":56,"context_line":"        # Ensure a user can\u0027t create two application credentials with the same"},{"line_number":57,"context_line":"        # name"},{"line_number":58,"context_line":"        app_cred \u003d self.create_application_credential(self.user_foo[\u0027id\u0027],"},{"line_number":59,"context_line":"                                                      self.tenant_bar[\u0027id\u0027])"},{"line_number":60,"context_line":"        name \u003d app_cred[\u0027name\u0027]"}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_f1260eb8","line":57,"updated":"2018-01-11 20:14:16.000000000","message":"What if they are for different projects?","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"0b16c59d9504591b4bfacc6852aec3c1751c9f9d","unresolved":false,"context_lines":[{"line_number":54,"context_line":""},{"line_number":55,"context_line":"    def test_create_duplicate_application_credential(self):"},{"line_number":56,"context_line":"        # Ensure a user can\u0027t create two application credentials with the same"},{"line_number":57,"context_line":"        # name"},{"line_number":58,"context_line":"        app_cred \u003d self.create_application_credential(self.user_foo[\u0027id\u0027],"},{"line_number":59,"context_line":"                                                      self.tenant_bar[\u0027id\u0027])"},{"line_number":60,"context_line":"        name \u003d app_cred[\u0027name\u0027]"}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_4c9ba471","line":57,"in_reply_to":"7f96bb07_7cbc1505","updated":"2018-01-11 22:50:12.000000000","message":"ack - thanks for digging that up","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"b7a6d06ac4ee04af3dadc8b3a44802aa70fe5bb8","unresolved":false,"context_lines":[{"line_number":54,"context_line":""},{"line_number":55,"context_line":"    def test_create_duplicate_application_credential(self):"},{"line_number":56,"context_line":"        # Ensure a user can\u0027t create two application credentials with the same"},{"line_number":57,"context_line":"        # name"},{"line_number":58,"context_line":"        app_cred \u003d self.create_application_credential(self.user_foo[\u0027id\u0027],"},{"line_number":59,"context_line":"                                                      self.tenant_bar[\u0027id\u0027])"},{"line_number":60,"context_line":"        name \u003d app_cred[\u0027name\u0027]"}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_7cbc1505","line":57,"in_reply_to":"7f96bb07_f1260eb8","updated":"2018-01-11 20:45:44.000000000","message":"Nope. An app cred needs to be uniquely identifiable, either by ID alone, or by user + name. Since app creds belong to users, not projects, it only makes sense for them to be unique by name for a user. We agreed to this in the spec: \"name must be unique among a User’s application credentials, but name is only guaranteed to be unique under that User. name may be useful for Consumers who want human readable config files.\" http://specs.openstack.org/openstack/keystone-specs/specs/keystone/queens/application-credentials.html#application-credential-management","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"8a0ee50015cb47623debc3e298ec9962278753d1","unresolved":false,"context_lines":[{"line_number":79,"context_line":"        app_cred \u003d self.create_application_credential(self.user_foo[\u0027id\u0027],"},{"line_number":80,"context_line":"                                                      self.tenant_bar[\u0027id\u0027])"},{"line_number":81,"context_line":"        app_cred[\u0027allow_application_credential_creation\u0027] \u003d True"},{"line_number":82,"context_line":"        resp \u003d self.app_cred_api.create_application_credential(app_cred)"},{"line_number":83,"context_line":"        self.assertDictEqual(app_cred, resp)"},{"line_number":84,"context_line":""},{"line_number":85,"context_line":"    def test_get_application_credential(self):"}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_31eeb622","line":82,"updated":"2018-01-11 20:14:16.000000000","message":"I though application credentials were immutable [0].\n\n[0] http://specs.openstack.org/openstack/keystone-specs/specs/keystone/queens/application-credentials.html#proposed-change","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"1fa18bb95d26997417f2d2b52f06a61db4a1828b","unresolved":false,"context_lines":[{"line_number":79,"context_line":"        app_cred \u003d self.create_application_credential(self.user_foo[\u0027id\u0027],"},{"line_number":80,"context_line":"                                                      self.tenant_bar[\u0027id\u0027])"},{"line_number":81,"context_line":"        app_cred[\u0027allow_application_credential_creation\u0027] \u003d True"},{"line_number":82,"context_line":"        resp \u003d self.app_cred_api.create_application_credential(app_cred)"},{"line_number":83,"context_line":"        self.assertDictEqual(app_cred, resp)"},{"line_number":84,"context_line":""},{"line_number":85,"context_line":"    def test_get_application_credential(self):"}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_977d3a1e","line":82,"in_reply_to":"7f96bb07_1cbcf1da","updated":"2018-01-11 21:26:42.000000000","message":"Done","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"b7a6d06ac4ee04af3dadc8b3a44802aa70fe5bb8","unresolved":false,"context_lines":[{"line_number":79,"context_line":"        app_cred \u003d self.create_application_credential(self.user_foo[\u0027id\u0027],"},{"line_number":80,"context_line":"                                                      self.tenant_bar[\u0027id\u0027])"},{"line_number":81,"context_line":"        app_cred[\u0027allow_application_credential_creation\u0027] \u003d True"},{"line_number":82,"context_line":"        resp \u003d self.app_cred_api.create_application_credential(app_cred)"},{"line_number":83,"context_line":"        self.assertDictEqual(app_cred, resp)"},{"line_number":84,"context_line":""},{"line_number":85,"context_line":"    def test_get_application_credential(self):"}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_1cbcf1da","line":82,"in_reply_to":"7f96bb07_31eeb622","updated":"2018-01-11 20:45:44.000000000","message":"The `self.create_application_credential` method just creates a dict, so this isn\u0027t changing an already-created app cred. I\u0027ll make the helper method private so that\u0027s more clear.\n\nSort of worth noting that it\u0027s currently only immutable by virtue of there not being an update method, so there\u0027s not a good way to test that here in the manager. There\u0027s a test in the controller showing that a PATCH doesn\u0027t work.","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"0b16c59d9504591b4bfacc6852aec3c1751c9f9d","unresolved":false,"context_lines":[{"line_number":79,"context_line":"        app_cred \u003d self.create_application_credential(self.user_foo[\u0027id\u0027],"},{"line_number":80,"context_line":"                                                      self.tenant_bar[\u0027id\u0027])"},{"line_number":81,"context_line":"        app_cred[\u0027allow_application_credential_creation\u0027] \u003d True"},{"line_number":82,"context_line":"        resp \u003d self.app_cred_api.create_application_credential(app_cred)"},{"line_number":83,"context_line":"        self.assertDictEqual(app_cred, resp)"},{"line_number":84,"context_line":""},{"line_number":85,"context_line":"    def test_get_application_credential(self):"}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_0c8fdc2a","line":82,"in_reply_to":"7f96bb07_977d3a1e","updated":"2018-01-11 22:50:12.000000000","message":"Ah - I totally spaced the self.create_application_credential bit for being a manager method /facepalm\n\nThanks for clarifying.","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"1fd52e65b1f2fb599c717333bc0709f2edb7c2b5","unresolved":false,"context_lines":[{"line_number":195,"context_line":"                          uuid.uuid4().hex,"},{"line_number":196,"context_line":"                          uuid.uuid4().hex)"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"    def test_authenticate_expired(self):"},{"line_number":199,"context_line":"        yesterday \u003d datetime.datetime.utcnow() - datetime.timedelta(days\u003d1)"},{"line_number":200,"context_line":"        app_cred \u003d self.create_application_credential(self.user_foo[\u0027id\u0027],"},{"line_number":201,"context_line":"                                                      self.tenant_bar[\u0027id\u0027],"},{"line_number":202,"context_line":"                                                      expires\u003dyesterday)"},{"line_number":203,"context_line":"        resp \u003d self.app_cred_api.create_application_credential(app_cred)"},{"line_number":204,"context_line":"        self.assertRaises(AssertionError,"},{"line_number":205,"context_line":"                          self.app_cred_api.authenticate,"},{"line_number":206,"context_line":"                          self.make_request(),"},{"line_number":207,"context_line":"                          resp[\u0027id\u0027],"},{"line_number":208,"context_line":"                          resp[\u0027secret\u0027])"},{"line_number":209,"context_line":""},{"line_number":210,"context_line":"    def test_authenticate_bad_secret(self):"},{"line_number":211,"context_line":"        app_cred \u003d self.create_application_credential(self.user_foo[\u0027id\u0027],"}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_fbf8487d","line":208,"range":{"start_line":198,"start_character":0,"end_line":208,"end_character":41},"updated":"2018-01-10 22:29:28.000000000","message":"So it\u0027s possible to create an application credential that is already expired?","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"1fa18bb95d26997417f2d2b52f06a61db4a1828b","unresolved":false,"context_lines":[{"line_number":195,"context_line":"                          uuid.uuid4().hex,"},{"line_number":196,"context_line":"                          uuid.uuid4().hex)"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"    def test_authenticate_expired(self):"},{"line_number":199,"context_line":"        yesterday \u003d datetime.datetime.utcnow() - datetime.timedelta(days\u003d1)"},{"line_number":200,"context_line":"        app_cred \u003d self.create_application_credential(self.user_foo[\u0027id\u0027],"},{"line_number":201,"context_line":"                                                      self.tenant_bar[\u0027id\u0027],"},{"line_number":202,"context_line":"                                                      expires\u003dyesterday)"},{"line_number":203,"context_line":"        resp \u003d self.app_cred_api.create_application_credential(app_cred)"},{"line_number":204,"context_line":"        self.assertRaises(AssertionError,"},{"line_number":205,"context_line":"                          self.app_cred_api.authenticate,"},{"line_number":206,"context_line":"                          self.make_request(),"},{"line_number":207,"context_line":"                          resp[\u0027id\u0027],"},{"line_number":208,"context_line":"                          resp[\u0027secret\u0027])"},{"line_number":209,"context_line":""},{"line_number":210,"context_line":"    def test_authenticate_bad_secret(self):"},{"line_number":211,"context_line":"        app_cred \u003d self.create_application_credential(self.user_foo[\u0027id\u0027],"}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_f79d9e59","line":208,"range":{"start_line":198,"start_character":0,"end_line":208,"end_character":41},"in_reply_to":"7f96bb07_fbf8487d","updated":"2018-01-11 21:26:42.000000000","message":"Answered in the controller patch - the validation there should catch that","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"8a0ee50015cb47623debc3e298ec9962278753d1","unresolved":false,"context_lines":[{"line_number":217,"context_line":"                          self.app_cred_api.authenticate,"},{"line_number":218,"context_line":"                          self.make_request(),"},{"line_number":219,"context_line":"                          resp[\u0027id\u0027],"},{"line_number":220,"context_line":"                          badpass)"}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_91cb0a52","line":220,"updated":"2018-01-11 20:14:16.000000000","message":"Since we have logic in the manager to prune duplicate roles, we could add a test that ensures you can create an application credential with a list of roles containing duplicates.","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"1fa18bb95d26997417f2d2b52f06a61db4a1828b","unresolved":false,"context_lines":[{"line_number":217,"context_line":"                          self.app_cred_api.authenticate,"},{"line_number":218,"context_line":"                          self.make_request(),"},{"line_number":219,"context_line":"                          resp[\u0027id\u0027],"},{"line_number":220,"context_line":"                          badpass)"}],"source_content_type":"text/x-python","patch_set":27,"id":"7f96bb07_77742e36","line":220,"in_reply_to":"7f96bb07_91cb0a52","updated":"2018-01-11 21:26:42.000000000","message":"Done","commit_id":"b0ca110798a156ac93ef471c328f14c3537fe164"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"3e402f7452f78981b9c4f9ee1ae5c363fe85750d","unresolved":false,"context_lines":[{"line_number":76,"context_line":"        resp \u003d self.app_cred_api.create_application_credential(app_cred)"},{"line_number":77,"context_line":"        self.assertDictEqual(app_cred_orig, resp)"},{"line_number":78,"context_line":""},{"line_number":79,"context_line":"    def test_create_application_credential_roles_pruned(self):"},{"line_number":80,"context_line":"        # Ensure a user can\u0027t create an application credential for a project"},{"line_number":81,"context_line":"        # they don\u0027t have a role assignment on"},{"line_number":82,"context_line":"        app_cred \u003d self._new_app_cred_data(self.user_foo[\u0027id\u0027],"}],"source_content_type":"text/x-python","patch_set":28,"id":"7f96bb07_2cac188b","line":79,"updated":"2018-01-11 22:52:11.000000000","message":"I think this test name got mixed up with the one on line 69.","commit_id":"f37b1a795637c936fafc7157199e936e23b514a3"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"536b93de2e9b21feeb9511223eb6f84f2a95d116","unresolved":false,"context_lines":[{"line_number":55,"context_line":"        self.assertDictEqual(app_cred, resp)"},{"line_number":56,"context_line":"        self.assertEqual(orig_roles[0][\u0027id\u0027], resp_roles[0][\u0027id\u0027])"},{"line_number":57,"context_line":""},{"line_number":58,"context_line":"    def test_create_duplicate_application_credential(self):"},{"line_number":59,"context_line":"        # Ensure a user can\u0027t create two application credentials with the same"},{"line_number":60,"context_line":"        # name"},{"line_number":61,"context_line":"        app_cred \u003d self._new_app_cred_data(self.user_foo[\u0027id\u0027],"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_b539b2d7","line":58,"range":{"start_line":58,"start_character":42,"end_line":58,"end_character":52},"updated":"2018-01-17 18:12:32.000000000","message":"nit: credential_fails","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"536b93de2e9b21feeb9511223eb6f84f2a95d116","unresolved":false,"context_lines":[{"line_number":74,"context_line":"        # they don\u0027t have a role assignment on"},{"line_number":75,"context_line":"        app_cred \u003d self._new_app_cred_data(self.user_foo[\u0027id\u0027],"},{"line_number":76,"context_line":"                                           self.tenant_baz[\u0027id\u0027])"},{"line_number":77,"context_line":"        self.assertRaises(exception.RoleAssignmentNotFound,"},{"line_number":78,"context_line":"                          self.app_cred_api.create_application_credential,"},{"line_number":79,"context_line":"                          app_cred)"},{"line_number":80,"context_line":""}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_75b24a4b","line":77,"range":{"start_line":77,"start_character":36,"end_line":77,"end_character":58},"updated":"2018-01-17 18:12:32.000000000","message":"I think there is an api guideline somewhere about returning 404/400 in cases like this. If this is a validation thing, do we return a 400 or a 404?","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"f42e97dab64a1dc43b030f6a0f41f66966a72424","unresolved":false,"context_lines":[{"line_number":74,"context_line":"        # they don\u0027t have a role assignment on"},{"line_number":75,"context_line":"        app_cred \u003d self._new_app_cred_data(self.user_foo[\u0027id\u0027],"},{"line_number":76,"context_line":"                                           self.tenant_baz[\u0027id\u0027])"},{"line_number":77,"context_line":"        self.assertRaises(exception.RoleAssignmentNotFound,"},{"line_number":78,"context_line":"                          self.app_cred_api.create_application_credential,"},{"line_number":79,"context_line":"                          app_cred)"},{"line_number":80,"context_line":""}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_3bd83379","line":77,"range":{"start_line":77,"start_character":36,"end_line":77,"end_character":58},"in_reply_to":"7f96bb07_75b24a4b","updated":"2018-01-17 19:25:29.000000000","message":"Responded in core.py","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"536b93de2e9b21feeb9511223eb6f84f2a95d116","unresolved":false,"context_lines":[{"line_number":76,"context_line":"                                           self.tenant_baz[\u0027id\u0027])"},{"line_number":77,"context_line":"        self.assertRaises(exception.RoleAssignmentNotFound,"},{"line_number":78,"context_line":"                          self.app_cred_api.create_application_credential,"},{"line_number":79,"context_line":"                          app_cred)"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    def test_application_credential_allow_recursion(self):"},{"line_number":82,"context_line":"        app_cred \u003d self._new_app_cred_data(self.user_foo[\u0027id\u0027],"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_b56772e9","line":79,"updated":"2018-01-17 18:12:32.000000000","message":"What happens if a user attempts to create an application credential without roles?","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"f42e97dab64a1dc43b030f6a0f41f66966a72424","unresolved":false,"context_lines":[{"line_number":76,"context_line":"                                           self.tenant_baz[\u0027id\u0027])"},{"line_number":77,"context_line":"        self.assertRaises(exception.RoleAssignmentNotFound,"},{"line_number":78,"context_line":"                          self.app_cred_api.create_application_credential,"},{"line_number":79,"context_line":"                          app_cred)"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    def test_application_credential_allow_recursion(self):"},{"line_number":82,"context_line":"        app_cred \u003d self._new_app_cred_data(self.user_foo[\u0027id\u0027],"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_9bc867a6","line":79,"in_reply_to":"7f96bb07_b56772e9","updated":"2018-01-17 19:25:29.000000000","message":"Responded in core.py","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"536b93de2e9b21feeb9511223eb6f84f2a95d116","unresolved":false,"context_lines":[{"line_number":154,"context_line":"        self.app_cred_api.create_application_credential(app_cred_2)"},{"line_number":155,"context_line":"        self.assertIn(app_cred_1[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":156,"context_line":"        self.assertIn(app_cred_2[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":157,"context_line":"        self.app_cred_api.delete_application_credentials_for_user("},{"line_number":158,"context_line":"            self.user_foo[\u0027id\u0027])"},{"line_number":159,"context_line":"        hints \u003d driver_hints.Hints()"},{"line_number":160,"context_line":"        self.assertListEqual("}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_d50d5ee8","line":157,"range":{"start_line":157,"start_character":26,"end_line":157,"end_character":65},"updated":"2018-01-17 18:12:32.000000000","message":"We might want to add this same test but instead of invoking the method directly we could delete or disable the user and ensure the wiring for the callback is correct.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"40db719ec8d93015530316b78ece3621fcd73acc","unresolved":false,"context_lines":[{"line_number":154,"context_line":"        self.app_cred_api.create_application_credential(app_cred_2)"},{"line_number":155,"context_line":"        self.assertIn(app_cred_1[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":156,"context_line":"        self.assertIn(app_cred_2[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":157,"context_line":"        self.app_cred_api.delete_application_credentials_for_user("},{"line_number":158,"context_line":"            self.user_foo[\u0027id\u0027])"},{"line_number":159,"context_line":"        hints \u003d driver_hints.Hints()"},{"line_number":160,"context_line":"        self.assertListEqual("}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_fb296b36","line":157,"range":{"start_line":157,"start_character":26,"end_line":157,"end_character":65},"in_reply_to":"7f96bb07_1b3a1798","updated":"2018-01-17 19:29:11.000000000","message":"I think it\u0027s picked up in the notification framework when you invoke the API via the controller... so maybe we can add that in the next patch if that\u0027s the case.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"f42e97dab64a1dc43b030f6a0f41f66966a72424","unresolved":false,"context_lines":[{"line_number":154,"context_line":"        self.app_cred_api.create_application_credential(app_cred_2)"},{"line_number":155,"context_line":"        self.assertIn(app_cred_1[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":156,"context_line":"        self.assertIn(app_cred_2[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":157,"context_line":"        self.app_cred_api.delete_application_credentials_for_user("},{"line_number":158,"context_line":"            self.user_foo[\u0027id\u0027])"},{"line_number":159,"context_line":"        hints \u003d driver_hints.Hints()"},{"line_number":160,"context_line":"        self.assertListEqual("}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_1b3a1798","line":157,"range":{"start_line":157,"start_character":26,"end_line":157,"end_character":65},"in_reply_to":"7f96bb07_d50d5ee8","updated":"2018-01-17 19:25:29.000000000","message":"Sure...will have to figure out how to trigger notifications from the unit tests","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"0f51576af604631667b814c4c3c3d55bc09f247b","unresolved":false,"context_lines":[{"line_number":154,"context_line":"        self.app_cred_api.create_application_credential(app_cred_2)"},{"line_number":155,"context_line":"        self.assertIn(app_cred_1[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":156,"context_line":"        self.assertIn(app_cred_2[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":157,"context_line":"        self.app_cred_api.delete_application_credentials_for_user("},{"line_number":158,"context_line":"            self.user_foo[\u0027id\u0027])"},{"line_number":159,"context_line":"        hints \u003d driver_hints.Hints()"},{"line_number":160,"context_line":"        self.assertListEqual("}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_fba08b44","line":157,"range":{"start_line":157,"start_character":26,"end_line":157,"end_character":65},"in_reply_to":"7f96bb07_fb296b36","updated":"2018-01-17 19:48:24.000000000","message":"Got this working with the notification callbacks: \n\nhttp://paste.openstack.org/show/646539/","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"005c5c4986463b14e2b7e3b8977d42401d9a7c09","unresolved":false,"context_lines":[{"line_number":154,"context_line":"        self.app_cred_api.create_application_credential(app_cred_2)"},{"line_number":155,"context_line":"        self.assertIn(app_cred_1[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":156,"context_line":"        self.assertIn(app_cred_2[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":157,"context_line":"        self.app_cred_api.delete_application_credentials_for_user("},{"line_number":158,"context_line":"            self.user_foo[\u0027id\u0027])"},{"line_number":159,"context_line":"        hints \u003d driver_hints.Hints()"},{"line_number":160,"context_line":"        self.assertListEqual("}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_4d054210","line":157,"range":{"start_line":157,"start_character":26,"end_line":157,"end_character":65},"in_reply_to":"7f96bb07_fba08b44","updated":"2018-01-17 19:55:31.000000000","message":"Perfect, thank you","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"536b93de2e9b21feeb9511223eb6f84f2a95d116","unresolved":false,"context_lines":[{"line_number":178,"context_line":"        self.assertIn(app_cred_proj_A_1[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":179,"context_line":"        self.assertIn(app_cred_proj_A_2[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":180,"context_line":"        self.assertIn(app_cred_proj_B[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":181,"context_line":"        self.app_cred_api.delete_application_credentials_for_user_on_project("},{"line_number":182,"context_line":"            self.user_foo[\u0027id\u0027], self.tenant_bar[\u0027id\u0027])"},{"line_number":183,"context_line":"        self.assertNotIn(app_cred_proj_A_1[\u0027id\u0027],"},{"line_number":184,"context_line":"                         self._list_ids(self.user_foo))"}],"source_content_type":"text/x-python","patch_set":34,"id":"7f96bb07_f5109a02","line":181,"range":{"start_line":181,"start_character":26,"end_line":181,"end_character":76},"updated":"2018-01-17 18:12:32.000000000","message":"Same comment here.","commit_id":"39f2241ea8800292e9a11a80a6e8ee85f06b51d8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"ba15eb899623f59a9925daac143434d41422b18a","unresolved":false,"context_lines":[{"line_number":182,"context_line":"        self.assertIn(app_cred_proj_B[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":183,"context_line":"        # This should trigger a notification which should invoke a callback in"},{"line_number":184,"context_line":"        # the application credential Manager to cleanup all of user_foo\u0027s"},{"line_number":185,"context_line":"        # application credentials on project baz."},{"line_number":186,"context_line":"        PROVIDERS.assignment_api.remove_role_from_user_and_project("},{"line_number":187,"context_line":"            user_id\u003dself.user_foo[\u0027id\u0027],"},{"line_number":188,"context_line":"            tenant_id\u003dself.tenant_bar[\u0027id\u0027],"}],"source_content_type":"text/x-python","patch_set":36,"id":"7f96bb07_0dce5ab3","line":185,"range":{"start_line":185,"start_character":45,"end_line":185,"end_character":48},"updated":"2018-01-17 20:04:20.000000000","message":"nit: bar... i fat-fingered that","commit_id":"a8790d6d7ccd63b4228376ba60f554e753fa5879"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"5b19f98fbcee2cd94b05b3682ac893cad88b3948","unresolved":false,"context_lines":[{"line_number":182,"context_line":"        self.assertIn(app_cred_proj_B[\u0027id\u0027], self._list_ids(self.user_foo))"},{"line_number":183,"context_line":"        # This should trigger a notification which should invoke a callback in"},{"line_number":184,"context_line":"        # the application credential Manager to cleanup all of user_foo\u0027s"},{"line_number":185,"context_line":"        # application credentials on project baz."},{"line_number":186,"context_line":"        PROVIDERS.assignment_api.remove_role_from_user_and_project("},{"line_number":187,"context_line":"            user_id\u003dself.user_foo[\u0027id\u0027],"},{"line_number":188,"context_line":"            tenant_id\u003dself.tenant_bar[\u0027id\u0027],"}],"source_content_type":"text/x-python","patch_set":37,"id":"7f96bb07_6dbefeff","line":185,"range":{"start_line":185,"start_character":45,"end_line":185,"end_character":48},"updated":"2018-01-17 20:04:49.000000000","message":"nit: bar, sorry about that..","commit_id":"0476549cd8afd613a02edf8cc6329478ee3963c1"}]}
