)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"3324b5abe3e9da27b20a5f7f339faccc071be913","unresolved":false,"context_lines":[{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Our previous token model (``KeystoneToken``) was built to accept"},{"line_number":10,"context_line":"complete token responses and use reflection to be more pythonic. Now"},{"line_number":11,"context_line":"that we\u0027re no longer supporting token providers or storage layers"},{"line_number":12,"context_line":"that rely on passing around full token responses, we can introduce"},{"line_number":13,"context_line":"a more pythonic way of building tokens."},{"line_number":14,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":11,"id":"5f7c97a3_2c3bd539","line":11,"range":{"start_line":11,"start_character":5,"end_line":11,"end_character":47},"updated":"2018-06-15 09:51:12.000000000","message":"This is news to me. We only have one provider in-tree, fernet, but JWT is on the horizon. Did we formally remove out-of-tree provider support?","commit_id":"31243ef67b3213fd4ed268a47a61582143c73834"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"34fdb48523e1f02d32b4477530e90e30eb8704c6","unresolved":false,"context_lines":[{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Our previous token model (``KeystoneToken``) was built to accept"},{"line_number":10,"context_line":"complete token responses and use reflection to be more pythonic. Now"},{"line_number":11,"context_line":"that we\u0027re no longer supporting token providers or storage layers"},{"line_number":12,"context_line":"that rely on passing around full token responses, we can introduce"},{"line_number":13,"context_line":"a more pythonic way of building tokens."},{"line_number":14,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":11,"id":"5f7c97a3_172ef48b","line":11,"range":{"start_line":11,"start_character":5,"end_line":11,"end_character":47},"in_reply_to":"5f7c97a3_2c3bd539","updated":"2018-06-18 21:35:49.000000000","message":"No - that\u0027s still possible and out-of-tree support shouldn\u0027t go away (at least I don\u0027t have a plan to ever remove it).\n\nWhat I meant when I wrote this is that we shouldn\u0027t support token providers that pass around dictionaries that end up being the actual token response (like what we used to do with the UUID/PKI/Fernet token providers). What I plan to do is simplify the token provider interface in a way that makes it simpler to maintain (and for external providers to implement), since external drivers shouldn\u0027t need to muck around or understand a massive token dictionary.\n\nI can reword this if you think it will make it more clear.","commit_id":"31243ef67b3213fd4ed268a47a61582143c73834"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"15b666115a9bc94fbcfe99c3706c8de5162db705","unresolved":false,"context_lines":[{"line_number":17,"context_line":"of the application to fill in the blanks. This should hopefully make"},{"line_number":18,"context_line":"our entire authentication and validation API paths more clear and"},{"line_number":19,"context_line":"understandable."},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"Change-Id: I2e461e7fdf4f47547e07fc279ec4e6fbd86f23ad"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":12,"id":"5f7c97a3_1d19fc20","line":20,"updated":"2018-06-20 21:07:05.000000000","message":"Can you give a little information about scenarios in which this will be better than KeystoneToken?\n\nI\u0027m having a little trouble wrapping my mind around it, because right now we have things like this:\n\n response \u003d PROVIDERS.token_provider_api.validate_token(token_id)\n return token_model.KeystoneToken(token_id\u003dtoken_id,\n                                  token_data\u003dresponse)\n\nToken data is directly associated with the token ID because of the way it\u0027s serialized. It seems like with the new model, we\u0027d have to do something like this:\n\n response \u003d PROVIDERS.token_provider_api.validate_token(token_id)\n token \u003d token_model.TokenModel()\n token.user_id \u003d response[\u0027user\u0027][\u0027id\u0027]\n if \u0027domain\u0027 in response:\n   token.domain_id \u003d response[\u0027domain\u0027][\u0027id\u0027]\n # etc \n token.mint(token_id, response[\u0027issued_at\u0027])\n\nA little more background on what this will unlock for us would be good.","commit_id":"7ebcfdc9bf2a439a75db47277a49bb2432bd0663"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"4e2f959cff3fd891799ab1b0a0a5d6feed6a07fe","unresolved":false,"context_lines":[{"line_number":17,"context_line":"of the application to fill in the blanks. This should hopefully make"},{"line_number":18,"context_line":"our entire authentication and validation API paths more clear and"},{"line_number":19,"context_line":"understandable."},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"Change-Id: I2e461e7fdf4f47547e07fc279ec4e6fbd86f23ad"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":12,"id":"5f7c97a3_fc274f62","line":20,"in_reply_to":"5f7c97a3_1d19fc20","updated":"2018-06-21 15:59:39.000000000","message":"Done","commit_id":"7ebcfdc9bf2a439a75db47277a49bb2432bd0663"}],"keystone/models/token_model.py":[{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"197940521ffaf31a9a22e46001c271dd41d79b0b","unresolved":false,"context_lines":[{"line_number":395,"context_line":"    def project(self):"},{"line_number":396,"context_line":"        return self.__project"},{"line_number":397,"context_line":""},{"line_number":398,"context_line":"    @project.setter"},{"line_number":399,"context_line":"    def project(self, value):"},{"line_number":400,"context_line":"        if value:"},{"line_number":401,"context_line":"            self.__project \u003d PROVIDERS.resource_api.get_project(value)"},{"line_number":402,"context_line":"        else:"},{"line_number":403,"context_line":"            self.__project \u003d None"},{"line_number":404,"context_line":""},{"line_number":405,"context_line":"    @property"},{"line_number":406,"context_line":"    def project_scoped(self):"}],"source_content_type":"text/x-python","patch_set":9,"id":"5f7c97a3_19d362d7","line":403,"range":{"start_line":398,"start_character":3,"end_line":403,"end_character":33},"updated":"2018-06-07 19:10:21.000000000","message":"This isn\u0027t going to work. I wouldn\u0027t support setting the entire project, it should be a dict, unless you\u0027re pulling the ID out of the dict... but then I would just tell folks to do set on project id and if self.__project is None on the @property call, or load from db in the project_id call.\n\nBasically, don\u0027t support setting .project directly","commit_id":"4d9084f8f73005fe73fec0e23a3e5c60b47e5a33"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"8b36912b650604ace003218bc2b0cbea792d25ab","unresolved":false,"context_lines":[{"line_number":395,"context_line":"    def project(self):"},{"line_number":396,"context_line":"        return self.__project"},{"line_number":397,"context_line":""},{"line_number":398,"context_line":"    @project.setter"},{"line_number":399,"context_line":"    def project(self, value):"},{"line_number":400,"context_line":"        if value:"},{"line_number":401,"context_line":"            self.__project \u003d PROVIDERS.resource_api.get_project(value)"},{"line_number":402,"context_line":"        else:"},{"line_number":403,"context_line":"            self.__project \u003d None"},{"line_number":404,"context_line":""},{"line_number":405,"context_line":"    @property"},{"line_number":406,"context_line":"    def project_scoped(self):"}],"source_content_type":"text/x-python","patch_set":9,"id":"5f7c97a3_4f1b4772","line":403,"range":{"start_line":398,"start_character":3,"end_line":403,"end_character":33},"in_reply_to":"5f7c97a3_19d362d7","updated":"2018-06-07 20:43:33.000000000","message":"Done","commit_id":"4d9084f8f73005fe73fec0e23a3e5c60b47e5a33"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"197940521ffaf31a9a22e46001c271dd41d79b0b","unresolved":false,"context_lines":[{"line_number":482,"context_line":"    @trust.setter"},{"line_number":483,"context_line":"    def trust(self, value):"},{"line_number":484,"context_line":"        if value:"},{"line_number":485,"context_line":"            self.__trust \u003d PROVIDERS.trust_api.get_trust(value)"},{"line_number":486,"context_line":"            self.trustor \u003d self.__trust[\u0027trustor_user_id\u0027]"},{"line_number":487,"context_line":"            self.trustee \u003d self.__trust[\u0027trustee_user_id\u0027]"},{"line_number":488,"context_line":"            self.trust_project \u003d self.__trust[\u0027project_id\u0027]"}],"source_content_type":"text/x-python","patch_set":9,"id":"5f7c97a3_d9d40abe","line":485,"range":{"start_line":485,"start_character":12,"end_line":485,"end_character":63},"updated":"2018-06-07 19:10:21.000000000","message":"Same comment as above for project.","commit_id":"4d9084f8f73005fe73fec0e23a3e5c60b47e5a33"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"8b36912b650604ace003218bc2b0cbea792d25ab","unresolved":false,"context_lines":[{"line_number":482,"context_line":"    @trust.setter"},{"line_number":483,"context_line":"    def trust(self, value):"},{"line_number":484,"context_line":"        if value:"},{"line_number":485,"context_line":"            self.__trust \u003d PROVIDERS.trust_api.get_trust(value)"},{"line_number":486,"context_line":"            self.trustor \u003d self.__trust[\u0027trustor_user_id\u0027]"},{"line_number":487,"context_line":"            self.trustee \u003d self.__trust[\u0027trustee_user_id\u0027]"},{"line_number":488,"context_line":"            self.trust_project \u003d self.__trust[\u0027project_id\u0027]"}],"source_content_type":"text/x-python","patch_set":9,"id":"5f7c97a3_af0c5b39","line":485,"range":{"start_line":485,"start_character":12,"end_line":485,"end_character":63},"in_reply_to":"5f7c97a3_d9d40abe","updated":"2018-06-07 20:43:33.000000000","message":"Done","commit_id":"4d9084f8f73005fe73fec0e23a3e5c60b47e5a33"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"197940521ffaf31a9a22e46001c271dd41d79b0b","unresolved":false,"context_lines":[{"line_number":564,"context_line":"    @user.setter"},{"line_number":565,"context_line":"    def user(self, value):"},{"line_number":566,"context_line":"        if value:"},{"line_number":567,"context_line":"            self.__user \u003d PROVIDERS.identity_api.get_user(value)"},{"line_number":568,"context_line":"        else:"},{"line_number":569,"context_line":"            self.__user \u003d None"},{"line_number":570,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"5f7c97a3_99de92d8","line":567,"range":{"start_line":567,"start_character":26,"end_line":567,"end_character":64},"updated":"2018-06-07 19:10:21.000000000","message":"See above.\n\nPretty much repeat throughout anything that is typically a dict, don\u0027t assign an ID into a dict returning property.","commit_id":"4d9084f8f73005fe73fec0e23a3e5c60b47e5a33"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"8b36912b650604ace003218bc2b0cbea792d25ab","unresolved":false,"context_lines":[{"line_number":564,"context_line":"    @user.setter"},{"line_number":565,"context_line":"    def user(self, value):"},{"line_number":566,"context_line":"        if value:"},{"line_number":567,"context_line":"            self.__user \u003d PROVIDERS.identity_api.get_user(value)"},{"line_number":568,"context_line":"        else:"},{"line_number":569,"context_line":"            self.__user \u003d None"},{"line_number":570,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"5f7c97a3_8f115f56","line":567,"range":{"start_line":567,"start_character":26,"end_line":567,"end_character":64},"in_reply_to":"5f7c97a3_99de92d8","updated":"2018-06-07 20:43:33.000000000","message":"Done","commit_id":"4d9084f8f73005fe73fec0e23a3e5c60b47e5a33"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"62d287d72f185e77f0020def564a696d0362d622","unresolved":false,"context_lines":[{"line_number":376,"context_line":""},{"line_number":377,"context_line":"    @user.setter"},{"line_number":378,"context_line":"    def user(self, value):"},{"line_number":379,"context_line":"        self.__user \u003d value"},{"line_number":380,"context_line":""},{"line_number":381,"context_line":"    @property"},{"line_number":382,"context_line":"    def user_domain(self):"}],"source_content_type":"text/x-python","patch_set":10,"id":"5f7c97a3_090467c5","line":379,"updated":"2018-06-08 04:16:07.000000000","message":"We should probably validate the data that is assigned here. That can be done in a follow-up. Applies to all similar dict setters, and you need to extract the I\u0027d and populate the *_id field.\n\nSuggest just dropping these setters.","commit_id":"54dc7d3a6c48e18596bbd8ca60f87f9a12a46cc1"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"006fa93bdfa3e89af065b3401def9f9db3fb6694","unresolved":false,"context_lines":[{"line_number":376,"context_line":""},{"line_number":377,"context_line":"    @user.setter"},{"line_number":378,"context_line":"    def user(self, value):"},{"line_number":379,"context_line":"        self.__user \u003d value"},{"line_number":380,"context_line":""},{"line_number":381,"context_line":"    @property"},{"line_number":382,"context_line":"    def user_domain(self):"}],"source_content_type":"text/x-python","patch_set":10,"id":"5f7c97a3_08469751","line":379,"in_reply_to":"5f7c97a3_090467c5","updated":"2018-06-08 14:19:28.000000000","message":"I get a bunch of errors like this if I have property methods without setters [0]. This is what I removed [1]. Thoughts?\n\n[0] http://paste.openstack.org/show/722981/\n[1] http://paste.openstack.org/show/722982/","commit_id":"54dc7d3a6c48e18596bbd8ca60f87f9a12a46cc1"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"15b666115a9bc94fbcfe99c3706c8de5162db705","unresolved":false,"context_lines":[{"line_number":300,"context_line":"        return self.get(\u0027methods\u0027, [])"},{"line_number":301,"context_line":""},{"line_number":302,"context_line":""},{"line_number":303,"context_line":"class TokenModel(object):"},{"line_number":304,"context_line":""},{"line_number":305,"context_line":"    def __init__(self):"},{"line_number":306,"context_line":"        self.user_id \u003d None"}],"source_content_type":"text/x-python","patch_set":12,"id":"5f7c97a3_8265a94b","line":303,"updated":"2018-06-20 21:07:05.000000000","message":"This could use a docstring","commit_id":"7ebcfdc9bf2a439a75db47277a49bb2432bd0663"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"4e2f959cff3fd891799ab1b0a0a5d6feed6a07fe","unresolved":false,"context_lines":[{"line_number":300,"context_line":"        return self.get(\u0027methods\u0027, [])"},{"line_number":301,"context_line":""},{"line_number":302,"context_line":""},{"line_number":303,"context_line":"class TokenModel(object):"},{"line_number":304,"context_line":""},{"line_number":305,"context_line":"    def __init__(self):"},{"line_number":306,"context_line":"        self.user_id \u003d None"}],"source_content_type":"text/x-python","patch_set":12,"id":"5f7c97a3_33673a28","line":303,"in_reply_to":"5f7c97a3_8265a94b","updated":"2018-06-21 15:59:39.000000000","message":"Done. Kind of unrelated... but the only other place in keystone where we really use something like this is for revocation events, and that object is called RevokeEvent. The predecessor to this approach was called KeystoneToken, and this is currently TokenModel.\n\nDo we want to simplify the name to be more like the convention with RevokeEvent (e.g. Token)? We also get the model bit from the module\u0027s namespace:\n\n  from keystone.models import token_model\n  ...\n  token \u003d token_model.Token()\n\nMaybe having Model in the name is redundant.","commit_id":"7ebcfdc9bf2a439a75db47277a49bb2432bd0663"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"15b666115a9bc94fbcfe99c3706c8de5162db705","unresolved":false,"context_lines":[{"line_number":343,"context_line":"        self.__application_credential \u003d None"},{"line_number":344,"context_line":""},{"line_number":345,"context_line":"    def __repr__(self):"},{"line_number":346,"context_line":"        \"\"\"Return string representation of KeystoneToken.\"\"\""},{"line_number":347,"context_line":"        desc \u003d (\u0027\u003c%(type)s (audit_id\u003d%(audit_id)s, \u0027"},{"line_number":348,"context_line":"                \u0027audit_chain_id\u003d%(audit_ids)s) at %(loc)s\u003e\u0027)"},{"line_number":349,"context_line":"        self_cls_name \u003d reflection.get_class_name(self, fully_qualified\u003dFalse)"}],"source_content_type":"text/x-python","patch_set":12,"id":"5f7c97a3_623c0d30","line":346,"range":{"start_line":346,"start_character":43,"end_line":346,"end_character":56},"updated":"2018-06-20 21:07:05.000000000","message":"TokenModel","commit_id":"7ebcfdc9bf2a439a75db47277a49bb2432bd0663"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"4e2f959cff3fd891799ab1b0a0a5d6feed6a07fe","unresolved":false,"context_lines":[{"line_number":343,"context_line":"        self.__application_credential \u003d None"},{"line_number":344,"context_line":""},{"line_number":345,"context_line":"    def __repr__(self):"},{"line_number":346,"context_line":"        \"\"\"Return string representation of KeystoneToken.\"\"\""},{"line_number":347,"context_line":"        desc \u003d (\u0027\u003c%(type)s (audit_id\u003d%(audit_id)s, \u0027"},{"line_number":348,"context_line":"                \u0027audit_chain_id\u003d%(audit_ids)s) at %(loc)s\u003e\u0027)"},{"line_number":349,"context_line":"        self_cls_name \u003d reflection.get_class_name(self, fully_qualified\u003dFalse)"}],"source_content_type":"text/x-python","patch_set":12,"id":"5f7c97a3_537bd6bd","line":346,"range":{"start_line":346,"start_character":43,"end_line":346,"end_character":56},"in_reply_to":"5f7c97a3_623c0d30","updated":"2018-06-21 15:59:39.000000000","message":"Done","commit_id":"7ebcfdc9bf2a439a75db47277a49bb2432bd0663"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"15b666115a9bc94fbcfe99c3706c8de5162db705","unresolved":false,"context_lines":[{"line_number":346,"context_line":"        \"\"\"Return string representation of KeystoneToken.\"\"\""},{"line_number":347,"context_line":"        desc \u003d (\u0027\u003c%(type)s (audit_id\u003d%(audit_id)s, \u0027"},{"line_number":348,"context_line":"                \u0027audit_chain_id\u003d%(audit_ids)s) at %(loc)s\u003e\u0027)"},{"line_number":349,"context_line":"        self_cls_name \u003d reflection.get_class_name(self, fully_qualified\u003dFalse)"},{"line_number":350,"context_line":"        return desc % {\u0027type\u0027: self_cls_name,"},{"line_number":351,"context_line":"                       \u0027audit_id\u0027: self.audit_id,"},{"line_number":352,"context_line":"                       \u0027audit_ids\u0027: self.audit_ids,"}],"source_content_type":"text/x-python","patch_set":12,"id":"5f7c97a3_3d971848","line":349,"updated":"2018-06-20 21:07:05.000000000","message":"Does it even make sense to use this anymore?","commit_id":"7ebcfdc9bf2a439a75db47277a49bb2432bd0663"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"4e2f959cff3fd891799ab1b0a0a5d6feed6a07fe","unresolved":false,"context_lines":[{"line_number":346,"context_line":"        \"\"\"Return string representation of KeystoneToken.\"\"\""},{"line_number":347,"context_line":"        desc \u003d (\u0027\u003c%(type)s (audit_id\u003d%(audit_id)s, \u0027"},{"line_number":348,"context_line":"                \u0027audit_chain_id\u003d%(audit_ids)s) at %(loc)s\u003e\u0027)"},{"line_number":349,"context_line":"        self_cls_name \u003d reflection.get_class_name(self, fully_qualified\u003dFalse)"},{"line_number":350,"context_line":"        return desc % {\u0027type\u0027: self_cls_name,"},{"line_number":351,"context_line":"                       \u0027audit_id\u0027: self.audit_id,"},{"line_number":352,"context_line":"                       \u0027audit_ids\u0027: self.audit_ids,"}],"source_content_type":"text/x-python","patch_set":12,"id":"5f7c97a3_d678347f","line":349,"in_reply_to":"5f7c97a3_3d971848","updated":"2018-06-21 15:59:39.000000000","message":"I don\u0027t think it does, good catch. I removed it in place of self.__class__.__name__","commit_id":"7ebcfdc9bf2a439a75db47277a49bb2432bd0663"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"15b666115a9bc94fbcfe99c3706c8de5162db705","unresolved":false,"context_lines":[{"line_number":756,"context_line":"                    raise exception.Forbidden("},{"line_number":757,"context_line":"                        _(\u0027Trustee has no delegated roles.\u0027))"},{"line_number":758,"context_line":""},{"line_number":759,"context_line":"    def mint(self, token_id, issued_at):"},{"line_number":760,"context_line":"        self._validate_token_resources()"},{"line_number":761,"context_line":"        self._validate_token_user()"},{"line_number":762,"context_line":"        self._validate_system_scope()"}],"source_content_type":"text/x-python","patch_set":12,"id":"5f7c97a3_fd9520e4","line":759,"updated":"2018-06-20 21:07:05.000000000","message":"This could use a docstring","commit_id":"7ebcfdc9bf2a439a75db47277a49bb2432bd0663"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"4e2f959cff3fd891799ab1b0a0a5d6feed6a07fe","unresolved":false,"context_lines":[{"line_number":756,"context_line":"                    raise exception.Forbidden("},{"line_number":757,"context_line":"                        _(\u0027Trustee has no delegated roles.\u0027))"},{"line_number":758,"context_line":""},{"line_number":759,"context_line":"    def mint(self, token_id, issued_at):"},{"line_number":760,"context_line":"        self._validate_token_resources()"},{"line_number":761,"context_line":"        self._validate_token_user()"},{"line_number":762,"context_line":"        self._validate_system_scope()"}],"source_content_type":"text/x-python","patch_set":12,"id":"5f7c97a3_d60914dc","line":759,"in_reply_to":"5f7c97a3_fd9520e4","updated":"2018-06-21 15:59:39.000000000","message":"Done","commit_id":"7ebcfdc9bf2a439a75db47277a49bb2432bd0663"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"6883647894343392bb2452ae51540e8a6f8c18b1","unresolved":false,"context_lines":[{"line_number":475,"context_line":"        return self.trust_id is not None"},{"line_number":476,"context_line":""},{"line_number":477,"context_line":"    @property"},{"line_number":478,"context_line":"    def trust(self):"},{"line_number":479,"context_line":"        if not self.__trust:"},{"line_number":480,"context_line":"            if self.trust_id:"},{"line_number":481,"context_line":"                self.__trust \u003d PROVIDERS.trust_api.get_trust(self.trust_id)"},{"line_number":482,"context_line":"        return self.__trust"},{"line_number":483,"context_line":""},{"line_number":484,"context_line":"    @property"},{"line_number":485,"context_line":"    def trustor(self):"},{"line_number":486,"context_line":"        if not self.__trustor:"},{"line_number":487,"context_line":"            if self.trust:"},{"line_number":488,"context_line":"                self.__trustor \u003d PROVIDERS.identity_api.get_user("},{"line_number":489,"context_line":"                    self.trust[\u0027trustor_user_id\u0027]"},{"line_number":490,"context_line":"                )"},{"line_number":491,"context_line":"        return self.__trustor"},{"line_number":492,"context_line":""},{"line_number":493,"context_line":"    @property"},{"line_number":494,"context_line":"    def trustee(self):"},{"line_number":495,"context_line":"        if not self.__trustee:"},{"line_number":496,"context_line":"            if self.trust:"},{"line_number":497,"context_line":"                self.__trustee \u003d PROVIDERS.identity_api.get_user("},{"line_number":498,"context_line":"                    self.trust[\u0027trustee_user_id\u0027]"},{"line_number":499,"context_line":"                )"},{"line_number":500,"context_line":"        return self.__trustee"},{"line_number":501,"context_line":""},{"line_number":502,"context_line":"    @property"},{"line_number":503,"context_line":"    def trust_project(self):"}],"source_content_type":"text/x-python","patch_set":17,"id":"5f7c97a3_c6fe9003","line":500,"range":{"start_line":478,"start_character":0,"end_line":500,"end_character":29},"updated":"2018-06-29 18:41:42.000000000","message":"NIT: future patch, populate all the data if one is asked for. Limit the calls to \"providers\" where possible.\n\nThis applies to any lookups. Make the lookups and setting of values as smart as possible to limit the need to do PROVIDERS.xxxxx, it\u0027s a lot of business logic, but can be done behind the scenes in the future.","commit_id":"f35c8c100661c735c2c4a478c002697fd06fcadb"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"1190b386068e5638431cfb219482f61565b21626","unresolved":false,"context_lines":[{"line_number":475,"context_line":"        return self.trust_id is not None"},{"line_number":476,"context_line":""},{"line_number":477,"context_line":"    @property"},{"line_number":478,"context_line":"    def trust(self):"},{"line_number":479,"context_line":"        if not self.__trust:"},{"line_number":480,"context_line":"            if self.trust_id:"},{"line_number":481,"context_line":"                self.__trust \u003d PROVIDERS.trust_api.get_trust(self.trust_id)"},{"line_number":482,"context_line":"        return self.__trust"},{"line_number":483,"context_line":""},{"line_number":484,"context_line":"    @property"},{"line_number":485,"context_line":"    def trustor(self):"},{"line_number":486,"context_line":"        if not self.__trustor:"},{"line_number":487,"context_line":"            if self.trust:"},{"line_number":488,"context_line":"                self.__trustor \u003d PROVIDERS.identity_api.get_user("},{"line_number":489,"context_line":"                    self.trust[\u0027trustor_user_id\u0027]"},{"line_number":490,"context_line":"                )"},{"line_number":491,"context_line":"        return self.__trustor"},{"line_number":492,"context_line":""},{"line_number":493,"context_line":"    @property"},{"line_number":494,"context_line":"    def trustee(self):"},{"line_number":495,"context_line":"        if not self.__trustee:"},{"line_number":496,"context_line":"            if self.trust:"},{"line_number":497,"context_line":"                self.__trustee \u003d PROVIDERS.identity_api.get_user("},{"line_number":498,"context_line":"                    self.trust[\u0027trustee_user_id\u0027]"},{"line_number":499,"context_line":"                )"},{"line_number":500,"context_line":"        return self.__trustee"},{"line_number":501,"context_line":""},{"line_number":502,"context_line":"    @property"},{"line_number":503,"context_line":"    def trust_project(self):"}],"source_content_type":"text/x-python","patch_set":17,"id":"5f7c97a3_0c42993c","line":500,"range":{"start_line":478,"start_character":0,"end_line":500,"end_character":29},"in_reply_to":"5f7c97a3_c6fe9003","updated":"2018-07-11 13:44:46.000000000","message":"So just populate all of these when we get the trust? We\u0027d still need the property methods here wouldn\u0027t we?","commit_id":"f35c8c100661c735c2c4a478c002697fd06fcadb"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"6883647894343392bb2452ae51540e8a6f8c18b1","unresolved":false,"context_lines":[{"line_number":498,"context_line":"                    self.trust[\u0027trustee_user_id\u0027]"},{"line_number":499,"context_line":"                )"},{"line_number":500,"context_line":"        return self.__trustee"},{"line_number":501,"context_line":""},{"line_number":502,"context_line":"    @property"},{"line_number":503,"context_line":"    def trust_project(self):"},{"line_number":504,"context_line":"        if not self.__trust_project:"},{"line_number":505,"context_line":"            if self.trust:"},{"line_number":506,"context_line":"                self.__trust_project \u003d PROVIDERS.resource_api.get_project("},{"line_number":507,"context_line":"                    self.trust[\u0027project_id\u0027]"},{"line_number":508,"context_line":"                )"},{"line_number":509,"context_line":"        return self.__trust_project"},{"line_number":510,"context_line":""},{"line_number":511,"context_line":"    @property"},{"line_number":512,"context_line":"    def trust_project_domain(self):"},{"line_number":513,"context_line":"        if not self.__trust_project_domain:"},{"line_number":514,"context_line":"            if self.trust:"},{"line_number":515,"context_line":"                self.__trust_project_domain \u003d ("},{"line_number":516,"context_line":"                    PROVIDERS.resource_api.get_domain("},{"line_number":517,"context_line":"                        self.trust_project[\u0027domain_id\u0027]"},{"line_number":518,"context_line":"                    )"},{"line_number":519,"context_line":"                )"},{"line_number":520,"context_line":"        return self.__trust_project_domain"},{"line_number":521,"context_line":""},{"line_number":522,"context_line":"    def _get_system_roles(self):"},{"line_number":523,"context_line":"        roles \u003d []"}],"source_content_type":"text/x-python","patch_set":17,"id":"5f7c97a3_66053c10","line":520,"range":{"start_line":501,"start_character":0,"end_line":520,"end_character":42},"updated":"2018-06-29 18:41:42.000000000","message":"See above comment.","commit_id":"f35c8c100661c735c2c4a478c002697fd06fcadb"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"6883647894343392bb2452ae51540e8a6f8c18b1","unresolved":false,"context_lines":[{"line_number":811,"context_line":"        self._validate_project_scope()"},{"line_number":812,"context_line":"        self._validate_trust_scope()"},{"line_number":813,"context_line":""},{"line_number":814,"context_line":"        self.id \u003d token_id"},{"line_number":815,"context_line":"        self.issued_at \u003d issued_at"}],"source_content_type":"text/x-python","patch_set":17,"id":"5f7c97a3_86089827","line":815,"range":{"start_line":814,"start_character":0,"end_line":815,"end_character":34},"updated":"2018-06-29 18:41:42.000000000","message":"Suggest (future patch) make the whole structure immutable once id and issued_at are set.","commit_id":"f35c8c100661c735c2c4a478c002697fd06fcadb"},{"author":{"_account_id":15054,"name":"wangxiyuan","email":"wangxiyuan1007@gmail.com","username":"wangxiyuan"},"change_message_id":"b061f5475da683595839c9cd1dfe6e14ef64a0d8","unresolved":false,"context_lines":[{"line_number":711,"context_line":"            raise exception.DomainNotFound(msg)"},{"line_number":712,"context_line":""},{"line_number":713,"context_line":"    def _validate_token_user(self):"},{"line_number":714,"context_line":"        if CONF.trust.enabled and self.trust_scoped:"},{"line_number":715,"context_line":"            if self.user_id !\u003d self.trustee[\u0027id\u0027]:"},{"line_number":716,"context_line":"                raise exception.Forbidden(_(\u0027User is not a trustee.\u0027))"},{"line_number":717,"context_line":"            try:"}],"source_content_type":"text/x-python","patch_set":18,"id":"5f7c97a3_f75ed811","line":714,"range":{"start_line":714,"start_character":11,"end_line":714,"end_character":29},"updated":"2018-07-13 07:31:52.000000000","message":"sorry that the option was removed.","commit_id":"59627875e5e02a5f241bd72d66ccb67ee7199613"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"72181c5a6dc1934843e970614554bfd26f0b7be7","unresolved":false,"context_lines":[{"line_number":711,"context_line":"            raise exception.DomainNotFound(msg)"},{"line_number":712,"context_line":""},{"line_number":713,"context_line":"    def _validate_token_user(self):"},{"line_number":714,"context_line":"        if CONF.trust.enabled and self.trust_scoped:"},{"line_number":715,"context_line":"            if self.user_id !\u003d self.trustee[\u0027id\u0027]:"},{"line_number":716,"context_line":"                raise exception.Forbidden(_(\u0027User is not a trustee.\u0027))"},{"line_number":717,"context_line":"            try:"}],"source_content_type":"text/x-python","patch_set":18,"id":"5f7c97a3_9afb047a","line":714,"range":{"start_line":714,"start_character":11,"end_line":714,"end_character":29},"in_reply_to":"5f7c97a3_f75ed811","updated":"2018-07-13 13:49:21.000000000","message":"Good point, I thought I caught this but it looks like I  missed one.","commit_id":"59627875e5e02a5f241bd72d66ccb67ee7199613"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"f6faa90e9e4625e11e3b16cb54abed0ebc93164c","unresolved":false,"context_lines":[{"line_number":620,"context_line":"            )"},{"line_number":621,"context_line":"            for role in project_roles:"},{"line_number":622,"context_line":"                federated_roles.append(role)"},{"line_number":623,"context_line":"        # NOTE(lbragstad): Remove duplicate role references from a list of"},{"line_number":624,"context_line":"        # roles. It is often suggested that this be done with:"},{"line_number":625,"context_line":"        #"},{"line_number":626,"context_line":"        # roles \u003d [dict(t) for t in set([tuple(d.items()) for d in roles])]"},{"line_number":627,"context_line":"        #"},{"line_number":628,"context_line":"        # But that doesn\u0027t actually remove duplicates in all cases and"},{"line_number":629,"context_line":"        # causes transient failures because dictionaries are unordered"},{"line_number":630,"context_line":"        # objects. This means {\u0027id\u0027: 1, \u0027foo\u0027: \u0027bar\u0027} and {\u0027foo\u0027: \u0027bar\u0027,"},{"line_number":631,"context_line":"        # \u0027id\u0027: 1} won\u0027t actually resolve to a single entity in the above"},{"line_number":632,"context_line":"        # logic since they are both considered unique. By using `in` we\u0027re"},{"line_number":633,"context_line":"        # performing a containment check, which also does a deep comparison"},{"line_number":634,"context_line":"        # of the objects, which is what we want."},{"line_number":635,"context_line":"        for role in federated_roles:"},{"line_number":636,"context_line":"            if not isinstance(role, dict):"},{"line_number":637,"context_line":"                role \u003d PROVIDERS.role_api.get_role(role)"},{"line_number":638,"context_line":"            if role not in roles:"},{"line_number":639,"context_line":"                roles.append(role)"},{"line_number":640,"context_line":""},{"line_number":641,"context_line":"        return roles"},{"line_number":642,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"5f7c97a3_7fddc86b","line":639,"range":{"start_line":623,"start_character":0,"end_line":639,"end_character":34},"updated":"2018-07-24 21:45:44.000000000","message":"I wonder if this could use the util function[0] for this, but here checks if a role is not a dict, so perhaps not.\n\n[0] https://github.com/openstack/keystone/blob/master/keystone/common/utils.py#L122-L136\n\nIf so, it can always be changed in a later ps.","commit_id":"04a54966578c1fa17bb1b962769a87c1213ff21f"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"7e90bf1277dbab50cb3fb648b9896ee79596986d","unresolved":false,"context_lines":[{"line_number":794,"context_line":"                    raise exception.Forbidden("},{"line_number":795,"context_line":"                        _(\u0027Trustee has no delegated roles.\u0027))"},{"line_number":796,"context_line":""},{"line_number":797,"context_line":"    def mint(self, token_id, issued_at):"},{"line_number":798,"context_line":"        \"\"\"Set the ``id`` and ``issued_at`` attributes of a token."},{"line_number":799,"context_line":""},{"line_number":800,"context_line":"        The process of building a token requires setting attributes about the"}],"source_content_type":"text/x-python","patch_set":19,"id":"5f7c97a3_2b95c03d","line":797,"updated":"2018-07-13 15:31:59.000000000","message":"We should make sure we get a patch that makes the model immutable once this method is called (e.g. you can\u0027t change anything about the token after it has been minted).\n\nThis just takes a more defensive stance.","commit_id":"04a54966578c1fa17bb1b962769a87c1213ff21f"},{"author":{"_account_id":15054,"name":"wangxiyuan","email":"wangxiyuan1007@gmail.com","username":"wangxiyuan"},"change_message_id":"39d2d37d813ad8454f909c7181f2c706e7da1b93","unresolved":false,"context_lines":[{"line_number":794,"context_line":"                    raise exception.Forbidden("},{"line_number":795,"context_line":"                        _(\u0027Trustee has no delegated roles.\u0027))"},{"line_number":796,"context_line":""},{"line_number":797,"context_line":"    def mint(self, token_id, issued_at):"},{"line_number":798,"context_line":"        \"\"\"Set the ``id`` and ``issued_at`` attributes of a token."},{"line_number":799,"context_line":""},{"line_number":800,"context_line":"        The process of building a token requires setting attributes about the"}],"source_content_type":"text/x-python","patch_set":19,"id":"5f7c97a3_834b8126","line":797,"in_reply_to":"5f7c97a3_2b95c03d","updated":"2018-07-16 07:55:03.000000000","message":"++","commit_id":"04a54966578c1fa17bb1b962769a87c1213ff21f"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"f6faa90e9e4625e11e3b16cb54abed0ebc93164c","unresolved":false,"context_lines":[{"line_number":794,"context_line":"                    raise exception.Forbidden("},{"line_number":795,"context_line":"                        _(\u0027Trustee has no delegated roles.\u0027))"},{"line_number":796,"context_line":""},{"line_number":797,"context_line":"    def mint(self, token_id, issued_at):"},{"line_number":798,"context_line":"        \"\"\"Set the ``id`` and ``issued_at`` attributes of a token."},{"line_number":799,"context_line":""},{"line_number":800,"context_line":"        The process of building a token requires setting attributes about the"}],"source_content_type":"text/x-python","patch_set":19,"id":"5f7c97a3_bf41200b","line":797,"in_reply_to":"5f7c97a3_834b8126","updated":"2018-07-24 21:45:44.000000000","message":"agreed, minting in terms of something like a coin, means the item is made, stamped, and final.","commit_id":"04a54966578c1fa17bb1b962769a87c1213ff21f"}],"keystone/tests/unit/base_classes.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"32a81e0b236d3a057f7a0684ee1837da47fec027","unresolved":false,"context_lines":[{"line_number":49,"context_line":""},{"line_number":50,"context_line":"        self.bootstrapper \u003d bootstrap.Bootstrapper()"},{"line_number":51,"context_line":"        self.addCleanup(provider_api.ProviderAPIs._clear_registry_instances)"},{"line_number":52,"context_line":"        self.addCleanup(self.clean_default_domain)"},{"line_number":53,"context_line":"        self.bootstrapper.admin_password \u003d \u0027password\u0027"},{"line_number":54,"context_line":"        self.bootstrapper.admin_username \u003d \u0027admin\u0027"},{"line_number":55,"context_line":"        self.bootstrapper.project_name \u003d \u0027admin\u0027"}],"source_content_type":"text/x-python","patch_set":9,"id":"5f7c97a3_86489887","line":52,"updated":"2018-05-20 23:31:15.000000000","message":"Apparently this is needed to get the new token model tests passing with py35? Otherwise I get failures about the default domain being disabled for a test that it shouldn\u0027t be.","commit_id":"4d9084f8f73005fe73fec0e23a3e5c60b47e5a33"}],"keystone/tests/unit/token/test_token_model.py":[{"author":{"_account_id":15699,"name":"sonu","email":"sonu.bhumca11@gmail.com","username":"sonu.kumar"},"change_message_id":"cd22ac109f75c78f288ccf6443a0ee037decf329","unresolved":false,"context_lines":[{"line_number":189,"context_line":"        self.project_id \u003d self.bootstrapper.project_id"},{"line_number":190,"context_line":"        self.project_name \u003d self.bootstrapper.project_name"},{"line_number":191,"context_line":"        self.admin_role_id \u003d self.bootstrapper.admin_role_id"},{"line_number":192,"context_line":""},{"line_number":193,"context_line":"        self.token_id \u003d uuid.uuid4().hex"},{"line_number":194,"context_line":"        issued_at \u003d datetime.datetime.utcnow()"},{"line_number":195,"context_line":"        self.issued_at \u003d ks_utils.isotime(at\u003dissued_at, subsecond\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":7,"id":"5f7c97a3_8d969594","line":192,"updated":"2018-05-18 05:19:17.000000000","message":"extra space.","commit_id":"3ffa73cce05b832b37cf4d0478eccf92d5437406"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"4e33d01ff5f0cbeac12a29b93a1491376c160e81","unresolved":false,"context_lines":[{"line_number":189,"context_line":"        self.project_id \u003d self.bootstrapper.project_id"},{"line_number":190,"context_line":"        self.project_name \u003d self.bootstrapper.project_name"},{"line_number":191,"context_line":"        self.admin_role_id \u003d self.bootstrapper.admin_role_id"},{"line_number":192,"context_line":""},{"line_number":193,"context_line":"        self.token_id \u003d uuid.uuid4().hex"},{"line_number":194,"context_line":"        issued_at \u003d datetime.datetime.utcnow()"},{"line_number":195,"context_line":"        self.issued_at \u003d ks_utils.isotime(at\u003dissued_at, subsecond\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":7,"id":"5f7c97a3_1b12b1b2","line":192,"in_reply_to":"5f7c97a3_8d969594","updated":"2018-05-18 20:31:44.000000000","message":"Yep - I did that for vertical separation between variable groups.","commit_id":"3ffa73cce05b832b37cf4d0478eccf92d5437406"},{"author":{"_account_id":15699,"name":"sonu","email":"sonu.bhumca11@gmail.com","username":"sonu.kumar"},"change_message_id":"cd22ac109f75c78f288ccf6443a0ee037decf329","unresolved":false,"context_lines":[{"line_number":422,"context_line":"            exception.DomainNotFound, token.mint, self.token_id, self.issued_at"},{"line_number":423,"context_line":"        )"},{"line_number":424,"context_line":""},{"line_number":425,"context_line":"    def test_mint_trust_scoped_token(self):"},{"line_number":426,"context_line":"        trustee \u003d core.new_user_ref(CONF.identity.default_domain_id)"},{"line_number":427,"context_line":"        trustee \u003d PROVIDERS.identity_api.create_user(trustee)"},{"line_number":428,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"5f7c97a3_8d3f75b4","line":425,"range":{"start_line":425,"start_character":8,"end_line":425,"end_character":36},"updated":"2018-05-18 05:19:17.000000000","message":"seems trustor\u0027s domain is not enabled.","commit_id":"3ffa73cce05b832b37cf4d0478eccf92d5437406"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"4e33d01ff5f0cbeac12a29b93a1491376c160e81","unresolved":false,"context_lines":[{"line_number":422,"context_line":"            exception.DomainNotFound, token.mint, self.token_id, self.issued_at"},{"line_number":423,"context_line":"        )"},{"line_number":424,"context_line":""},{"line_number":425,"context_line":"    def test_mint_trust_scoped_token(self):"},{"line_number":426,"context_line":"        trustee \u003d core.new_user_ref(CONF.identity.default_domain_id)"},{"line_number":427,"context_line":"        trustee \u003d PROVIDERS.identity_api.create_user(trustee)"},{"line_number":428,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"5f7c97a3_9b1d61bf","line":425,"range":{"start_line":425,"start_character":8,"end_line":425,"end_character":36},"in_reply_to":"5f7c97a3_8d3f75b4","updated":"2018-05-18 20:31:44.000000000","message":"I think this happens when the default domain is used and possibly disabled in other tests.\n\nI\u0027ll update this to use a different domain instead of the default one.","commit_id":"3ffa73cce05b832b37cf4d0478eccf92d5437406"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"15b666115a9bc94fbcfe99c3706c8de5162db705","unresolved":false,"context_lines":[{"line_number":190,"context_line":"        self.project_name \u003d self.bootstrapper.project_name"},{"line_number":191,"context_line":"        self.admin_role_id \u003d self.bootstrapper.admin_role_id"},{"line_number":192,"context_line":"        self.member_role_id \u003d self.bootstrapper.member_role_id"},{"line_number":193,"context_line":"        self.reader_role_id \u003d self.bootstrapper.reader_role_id"},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"        self.token_id \u003d uuid.uuid4().hex"},{"line_number":196,"context_line":"        issued_at \u003d datetime.datetime.utcnow()"}],"source_content_type":"text/x-python","patch_set":12,"id":"5f7c97a3_bd0ec889","line":193,"updated":"2018-06-20 21:07:05.000000000","message":"It\u0027s not really clear what the bootstrap attributes have to do with TokenModel. Why doesn\u0027t this just create dummy, non-admin resources like our other tests do?","commit_id":"7ebcfdc9bf2a439a75db47277a49bb2432bd0663"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"4e2f959cff3fd891799ab1b0a0a5d6feed6a07fe","unresolved":false,"context_lines":[{"line_number":190,"context_line":"        self.project_name \u003d self.bootstrapper.project_name"},{"line_number":191,"context_line":"        self.admin_role_id \u003d self.bootstrapper.admin_role_id"},{"line_number":192,"context_line":"        self.member_role_id \u003d self.bootstrapper.member_role_id"},{"line_number":193,"context_line":"        self.reader_role_id \u003d self.bootstrapper.reader_role_id"},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"        self.token_id \u003d uuid.uuid4().hex"},{"line_number":196,"context_line":"        issued_at \u003d datetime.datetime.utcnow()"}],"source_content_type":"text/x-python","patch_set":12,"id":"5f7c97a3_f9cbe1a0","line":193,"in_reply_to":"5f7c97a3_bd0ec889","updated":"2018-06-21 15:59:39.000000000","message":"I opted to using the Bootstrap method here in favor of a couple different ways we duplicate the same process in test setup [0][1].\n\nThe token model changes don\u0027t have a hard dependency on using bootstrap, but I thought it would be a good opportunity to show an example of how we can re-use it in tests to provide us the same thing we do manually in a few places with setUp().\n\nI\u0027d like to try and make bootstrap the bedrock of our testing setUp, where applicable for tests that need it, and it should align our tests with what we tell operators to use (resulting in more rigorous testing of that tooling).\n\n[0] https://git.openstack.org/cgit/openstack/keystone/tree/keystone/tests/unit/test_v3.py?id\u003debd49159b41dbc2c97918f82aa860f87be7b5ed7#n240\n[1] https://git.openstack.org/cgit/openstack/keystone/tree/keystone/tests/unit/core.py?id\u003debd49159b41dbc2c97918f82aa860f87be7b5ed7#n710","commit_id":"7ebcfdc9bf2a439a75db47277a49bb2432bd0663"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"cf3e59d609f088d56be9b09b3096e6339c83a212","unresolved":false,"context_lines":[{"line_number":584,"context_line":""},{"line_number":585,"context_line":"        self.assertRaises("},{"line_number":586,"context_line":"            exception.Forbidden, token.mint, self.token_id, self.issued_at"},{"line_number":587,"context_line":"        )"}],"source_content_type":"text/x-python","patch_set":13,"id":"5f7c97a3_12b0e1fc","line":587,"updated":"2018-06-22 14:39:46.000000000","message":"We should add some unscoped and scoped federated token tests here, too.","commit_id":"db96a62f6dc2e0ebc0b7a6b72c69acfbf90d32b8"}]}
