)]}'
{"tests/fixtures/config/authorization/single-tenant/main.yaml":[{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"ed48aa3ae3d5c9775a50ae1250debbb69ece51f1","unresolved":false,"context_lines":[{"line_number":16,"context_line":"- admin-rule:"},{"line_number":17,"context_line":"    name: car_rule"},{"line_number":18,"context_line":"    conditions:"},{"line_number":19,"context_line":"      - vehicle.car: ecto-1"},{"line_number":20,"context_line":"- tenant:"},{"line_number":21,"context_line":"    name: tenant-one"},{"line_number":22,"context_line":"    admin-rules:"}],"source_content_type":"text/x-yaml","patch_set":35,"id":"7faddb67_7d660658","line":19,"range":{"start_line":19,"start_character":8,"end_line":19,"end_character":19},"updated":"2019-08-14 11:22:33.000000000","message":"It\u0027s possible I missed this earlier ... but why do we do vehicle.car here instead of:\n\n  - vehicle:\n      car: ecto-1\n\nAsking since the structure is {\u0027vehicle\u0027: {\u0027car\u0027: \u0027ecto-1\u0027}} on the other side.","commit_id":"2c7bb3999fc86132769a3a2e6afaaf4b5c0b9dac"},{"author":{"_account_id":7186,"name":"Matthieu Huin","email":"mhuin@redhat.com","username":"mhu"},"change_message_id":"1777f001df60cbf1d5c0f5d72b9de489a35bea7f","unresolved":false,"context_lines":[{"line_number":16,"context_line":"- admin-rule:"},{"line_number":17,"context_line":"    name: car_rule"},{"line_number":18,"context_line":"    conditions:"},{"line_number":19,"context_line":"      - vehicle.car: ecto-1"},{"line_number":20,"context_line":"- tenant:"},{"line_number":21,"context_line":"    name: tenant-one"},{"line_number":22,"context_line":"    admin-rules:"}],"source_content_type":"text/x-yaml","patch_set":35,"id":"7faddb67_c3a18caa","line":19,"range":{"start_line":19,"start_character":8,"end_line":19,"end_character":19},"in_reply_to":"7faddb67_7d660658","updated":"2019-08-27 09:34:41.000000000","message":"In a previous patch of the chain, I opted for an XPath-like definition but now taking a few steps away from it I realize simply using YAML itself could be enough.\nOr this could be interpreted as \"the \u0027vehicle\u0027 field must EXACTLY be {\u0027car\u0027: \u0027ecto-1\u0027}\" vs \"match the \u0027vehicle.car\u0027 Xpath pattern, and it must be \u0027ecto-1\u0027\". But that\u0027s probably overthinking.\n\nI\u0027ll address this in a follow-up, we can weigh the pros and cons of each approach there.","commit_id":"2c7bb3999fc86132769a3a2e6afaaf4b5c0b9dac"}],"tests/unit/test_web.py":[{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"02066c79cbe631bec53f84efea8eca15e83c6566","unresolved":false,"context_lines":[{"line_number":1555,"context_line":"                           headers\u003d{\u0027Authorization\u0027: \u0027Bearer %s\u0027 % token})"},{"line_number":1556,"context_line":"        self.assertEqual(401, req.status_code, req.text)"},{"line_number":1557,"context_line":""},{"line_number":1558,"context_line":"    def test_user_actions(self):"},{"line_number":1559,"context_line":"        \"\"\"Test that users get the right \u0027zuul.actions\u0027 trees\"\"\""},{"line_number":1560,"context_line":"        users \u003d ["},{"line_number":1561,"context_line":"            {\u0027authz\u0027: {\u0027iss\u0027: \u0027zuul_operator\u0027,"}],"source_content_type":"text/x-python","patch_set":33,"id":"7faddb67_2ba6cfac","line":1558,"updated":"2019-08-01 15:56:15.000000000","message":"When I run this locally, it hangs, so this is probably the cause of the test timeouts.  (I have no idea why the hard unit test timeout doesn\u0027t hit.)","commit_id":"79b86bcc708252e797719a343c563bb0494bc6db"}],"zuul/rpclistener.py":[{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"65e2442d2216fef961c1ddfecd95955f0821f21d","unresolved":false,"context_lines":[{"line_number":54,"context_line":"            \u0027key_get\u0027,"},{"line_number":55,"context_line":"            \u0027config_errors_list\u0027,"},{"line_number":56,"context_line":"            \u0027connection_list\u0027,"},{"line_number":57,"context_line":"            \u0027authorize_user\u0027,"},{"line_number":58,"context_line":"        ]"},{"line_number":59,"context_line":"        for func in functions:"},{"line_number":60,"context_line":"            f \u003d getattr(self, \u0027handle_%s\u0027 % func)"}],"source_content_type":"text/x-python","patch_set":33,"id":"7faddb67_6e10554f","line":57,"updated":"2019-08-01 16:18:51.000000000","message":"\u0027get_admin_tenants\u0027,","commit_id":"79b86bcc708252e797719a343c563bb0494bc6db"},{"author":{"_account_id":3099,"name":"David Shrewsbury","email":"dshrewsb@redhat.com","username":"dshrews"},"change_message_id":"3f288d7b87f1c38c202fc598bfb09c4b683e641a","unresolved":false,"context_lines":[{"line_number":283,"context_line":"            job_log_stream_address[\u0027port\u0027] \u003d build.worker.log_port"},{"line_number":284,"context_line":"        job.sendWorkComplete(json.dumps(job_log_stream_address))"},{"line_number":285,"context_line":""},{"line_number":286,"context_line":"    def _is_authorized(self, tenant, claims, debug\u003dFalse):"},{"line_number":287,"context_line":"        authorized \u003d False"},{"line_number":288,"context_line":"        if tenant:"},{"line_number":289,"context_line":"            rules \u003d tenant.authorization_rules"}],"source_content_type":"text/x-python","patch_set":35,"id":"7faddb67_ad5e9a42","line":286,"range":{"start_line":286,"start_character":45,"end_line":286,"end_character":57},"updated":"2019-08-13 17:29:01.000000000","message":"This seems like an odd pattern (within this code base at least) to control logging. The reason for it is not obvious to me. Is having this debug logging on in the get_admin_tenants case excessive?","commit_id":"2c7bb3999fc86132769a3a2e6afaaf4b5c0b9dac"},{"author":{"_account_id":7186,"name":"Matthieu Huin","email":"mhuin@redhat.com","username":"mhu"},"change_message_id":"1777f001df60cbf1d5c0f5d72b9de489a35bea7f","unresolved":false,"context_lines":[{"line_number":283,"context_line":"            job_log_stream_address[\u0027port\u0027] \u003d build.worker.log_port"},{"line_number":284,"context_line":"        job.sendWorkComplete(json.dumps(job_log_stream_address))"},{"line_number":285,"context_line":""},{"line_number":286,"context_line":"    def _is_authorized(self, tenant, claims, debug\u003dFalse):"},{"line_number":287,"context_line":"        authorized \u003d False"},{"line_number":288,"context_line":"        if tenant:"},{"line_number":289,"context_line":"            rules \u003d tenant.authorization_rules"}],"source_content_type":"text/x-python","patch_set":35,"id":"7faddb67_830e348a","line":286,"range":{"start_line":286,"start_character":45,"end_line":286,"end_character":57},"in_reply_to":"7faddb67_ad5e9a42","updated":"2019-08-27 09:34:41.000000000","message":"I\u0027ll rework this in the next patch. Looking back at this, I feel like actual authorization granting should be logged at higher level than going through a rule; the latter being actual debugging info to make sure the right rules are considered for a tenant.","commit_id":"2c7bb3999fc86132769a3a2e6afaaf4b5c0b9dac"}],"zuul/web/__init__.py":[{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"ed48aa3ae3d5c9775a50ae1250debbb69ece51f1","unresolved":false,"context_lines":[{"line_number":517,"context_line":"            for header, contents in e.getAdditionalHeaders().items():"},{"line_number":518,"context_line":"                cherrypy.response.headers[header] \u003d contents"},{"line_number":519,"context_line":"            cherrypy.response.status \u003d e.HTTPError"},{"line_number":520,"context_line":"            return \u0027\u003ch1\u003e%s\u003c/h1\u003e\u0027 % e.error_description"},{"line_number":521,"context_line":"        if \u0027zuul\u0027 in claims and \u0027admin\u0027 in claims.get(\u0027zuul\u0027, {}):"},{"line_number":522,"context_line":"            return {\u0027zuul\u0027: {\u0027admin\u0027: claims[\u0027zuul\u0027][\u0027admin\u0027]}, }"},{"line_number":523,"context_line":"        job \u003d self.rpc.submitJob(\u0027zuul:get_admin_tenants\u0027,"}],"source_content_type":"text/x-python","patch_set":35,"id":"7faddb67_fd63d63f","line":520,"range":{"start_line":520,"start_character":12,"end_line":520,"end_character":54},"updated":"2019-08-14 11:22:33.000000000","message":"I don\u0027t think we should return html in a method that is otherwise returning json. From an API user perspective that\u0027s often unpleasant. I\u0027d rather see the error_description (or even the whole error) in a json body here, that way CLI tools can render it easily in text, and web tools can render it easily in html.","commit_id":"2c7bb3999fc86132769a3a2e6afaaf4b5c0b9dac"},{"author":{"_account_id":7186,"name":"Matthieu Huin","email":"mhuin@redhat.com","username":"mhu"},"change_message_id":"1777f001df60cbf1d5c0f5d72b9de489a35bea7f","unresolved":false,"context_lines":[{"line_number":517,"context_line":"            for header, contents in e.getAdditionalHeaders().items():"},{"line_number":518,"context_line":"                cherrypy.response.headers[header] \u003d contents"},{"line_number":519,"context_line":"            cherrypy.response.status \u003d e.HTTPError"},{"line_number":520,"context_line":"            return \u0027\u003ch1\u003e%s\u003c/h1\u003e\u0027 % e.error_description"},{"line_number":521,"context_line":"        if \u0027zuul\u0027 in claims and \u0027admin\u0027 in claims.get(\u0027zuul\u0027, {}):"},{"line_number":522,"context_line":"            return {\u0027zuul\u0027: {\u0027admin\u0027: claims[\u0027zuul\u0027][\u0027admin\u0027]}, }"},{"line_number":523,"context_line":"        job \u003d self.rpc.submitJob(\u0027zuul:get_admin_tenants\u0027,"}],"source_content_type":"text/x-python","patch_set":35,"id":"7faddb67_036fa428","line":520,"range":{"start_line":520,"start_character":12,"end_line":520,"end_character":54},"in_reply_to":"7faddb67_fd63d63f","updated":"2019-08-27 09:34:41.000000000","message":"I based this on examples I saw in the RFCs for this kind of auth, but it\u0027s probably flexible. I\u0027ll switch to JSON","commit_id":"2c7bb3999fc86132769a3a2e6afaaf4b5c0b9dac"},{"author":{"_account_id":3099,"name":"David Shrewsbury","email":"dshrewsb@redhat.com","username":"dshrews"},"change_message_id":"d3120ace44ce371b21da4ae119d18508c4582373","unresolved":false,"context_lines":[{"line_number":533,"context_line":"            \u0027buildset\u0027: \u0027/api/tenant/{tenant}/buildset/{uuid}\u0027,"},{"line_number":534,"context_line":"            \u0027config_errors\u0027: \u0027/api/tenant/{tenant}/config-errors\u0027,"},{"line_number":535,"context_line":"            \u0027authorizations\u0027: \u0027/api/user/authorizations\u0027,"},{"line_number":536,"context_line":"            \u0027autohold\u0027: \u0027/api/tenant/{tenant}/project/{project:.*}/autohold\u0027,"},{"line_number":537,"context_line":"            \u0027autohold_list\u0027: \u0027/api/tenant/{tenant}/autohold\u0027,"},{"line_number":538,"context_line":"            \u0027enqueue\u0027: \u0027/api/tenant/{tenant}/project/{project:.*}/enqueue\u0027,"},{"line_number":539,"context_line":"            \u0027dequeue\u0027: \u0027/api/tenant/{tenant}/project/{project:.*}/dequeue\u0027,"},{"line_number":540,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":42,"id":"3fa7e38b_147ff5ab","line":537,"range":{"start_line":536,"start_character":0,"end_line":537,"end_character":61},"updated":"2019-10-03 18:48:04.000000000","message":"Not quite sure of the purpose of this, but since you\u0027re adding autohold stuff, what about autohold_by_request_id and autohold_delete?","commit_id":"d13f1ad36189c82d76992028eeaff40ada183735"},{"author":{"_account_id":7186,"name":"Matthieu Huin","email":"mhuin@redhat.com","username":"mhu"},"change_message_id":"a0b26ac1662d82bcf0a0b2ba7d7453ed73893497","unresolved":false,"context_lines":[{"line_number":533,"context_line":"            \u0027buildset\u0027: \u0027/api/tenant/{tenant}/buildset/{uuid}\u0027,"},{"line_number":534,"context_line":"            \u0027config_errors\u0027: \u0027/api/tenant/{tenant}/config-errors\u0027,"},{"line_number":535,"context_line":"            \u0027authorizations\u0027: \u0027/api/user/authorizations\u0027,"},{"line_number":536,"context_line":"            \u0027autohold\u0027: \u0027/api/tenant/{tenant}/project/{project:.*}/autohold\u0027,"},{"line_number":537,"context_line":"            \u0027autohold_list\u0027: \u0027/api/tenant/{tenant}/autohold\u0027,"},{"line_number":538,"context_line":"            \u0027enqueue\u0027: \u0027/api/tenant/{tenant}/project/{project:.*}/enqueue\u0027,"},{"line_number":539,"context_line":"            \u0027dequeue\u0027: \u0027/api/tenant/{tenant}/project/{project:.*}/dequeue\u0027,"},{"line_number":540,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":42,"id":"3fa7e38b_013fafd6","line":537,"range":{"start_line":536,"start_character":0,"end_line":537,"end_character":61},"in_reply_to":"3fa7e38b_147ff5ab","updated":"2019-10-04 09:24:17.000000000","message":"Not sure what this is for either, but I added these","commit_id":"d13f1ad36189c82d76992028eeaff40ada183735"},{"author":{"_account_id":7186,"name":"Matthieu Huin","email":"mhuin@redhat.com","username":"mhu"},"change_message_id":"486dea15754d123669e00f1781595455e86e3c50","unresolved":false,"context_lines":[{"line_number":505,"context_line":""},{"line_number":506,"context_line":"    @cherrypy.expose"},{"line_number":507,"context_line":"    @cherrypy.tools.json_out(content_type\u003d\u0027application/json; charset\u003dutf-8\u0027)"},{"line_number":508,"context_line":"    def index(self):"},{"line_number":509,"context_line":"        return {"},{"line_number":510,"context_line":"            \u0027info\u0027: \u0027/api/info\u0027,"},{"line_number":511,"context_line":"            \u0027connections\u0027: \u0027/api/connections\u0027,"},{"line_number":512,"context_line":"            \u0027tenants\u0027: \u0027/api/tenants\u0027,"},{"line_number":513,"context_line":"            \u0027tenant_info\u0027: \u0027/api/tenant/{tenant}/info\u0027,"},{"line_number":514,"context_line":"            \u0027status\u0027: \u0027/api/tenant/{tenant}/status\u0027,"},{"line_number":515,"context_line":"            \u0027status_change\u0027: \u0027/api/tenant/{tenant}/status/change/{change}\u0027,"},{"line_number":516,"context_line":"            \u0027jobs\u0027: \u0027/api/tenant/{tenant}/jobs\u0027,"},{"line_number":517,"context_line":"            \u0027job\u0027: \u0027/api/tenant/{tenant}/job/{job_name}\u0027,"},{"line_number":518,"context_line":"            \u0027projects\u0027: \u0027/api/tenant/{tenant}/projects\u0027,"},{"line_number":519,"context_line":"            \u0027project\u0027: \u0027/api/tenant/{tenant}/project/{project:.*}\u0027,"},{"line_number":520,"context_line":"            \u0027project_freeze_jobs\u0027: \u0027/api/tenant/{tenant}/pipeline/{pipeline}/\u0027"},{"line_number":521,"context_line":"                                   \u0027project/{project:.*}/branch/{branch:.*}/\u0027"},{"line_number":522,"context_line":"                                   \u0027freeze-jobs\u0027,"},{"line_number":523,"context_line":"            \u0027pipelines\u0027: \u0027/api/tenant/{tenant}/pipelines\u0027,"},{"line_number":524,"context_line":"            \u0027labels\u0027: \u0027/api/tenant/{tenant}/labels\u0027,"},{"line_number":525,"context_line":"            \u0027nodes\u0027: \u0027/api/tenant/{tenant}/nodes\u0027,"},{"line_number":526,"context_line":"            \u0027key\u0027: \u0027/api/tenant/{tenant}/key/{project:.*}.pub\u0027,"},{"line_number":527,"context_line":"            \u0027project_ssh_key\u0027: \u0027/api/tenant/{tenant}/project-ssh-key/\u0027"},{"line_number":528,"context_line":"                               \u0027{project:.*}.pub\u0027,"},{"line_number":529,"context_line":"            \u0027console_stream\u0027: \u0027/api/tenant/{tenant}/console-stream\u0027,"},{"line_number":530,"context_line":"            \u0027builds\u0027: \u0027/api/tenant/{tenant}/builds\u0027,"},{"line_number":531,"context_line":"            \u0027build\u0027: \u0027/api/tenant/{tenant}/build/{uuid}\u0027,"},{"line_number":532,"context_line":"            \u0027buildsets\u0027: \u0027/api/tenant/{tenant}/buildsets\u0027,"},{"line_number":533,"context_line":"            \u0027buildset\u0027: \u0027/api/tenant/{tenant}/buildset/{uuid}\u0027,"},{"line_number":534,"context_line":"            \u0027config_errors\u0027: \u0027/api/tenant/{tenant}/config-errors\u0027,"},{"line_number":535,"context_line":"            \u0027authorizations\u0027: \u0027/api/user/authorizations\u0027,"},{"line_number":536,"context_line":"            \u0027autohold\u0027: \u0027/api/tenant/{tenant}/project/{project:.*}/autohold\u0027,"},{"line_number":537,"context_line":"            \u0027autohold_list\u0027: \u0027/api/tenant/{tenant}/autohold\u0027,"},{"line_number":538,"context_line":"            \u0027autohold_by_request_id\u0027: \u0027/api/tenant/{tenant}/\u0027"},{"line_number":539,"context_line":"                                      \u0027autohold/{request_id}\u0027,"},{"line_number":540,"context_line":"            \u0027autohold_delete\u0027: \u0027/api/tenant/{tenant}/autohold/{request_id}\u0027,"},{"line_number":541,"context_line":"            \u0027enqueue\u0027: \u0027/api/tenant/{tenant}/project/{project:.*}/enqueue\u0027,"},{"line_number":542,"context_line":"            \u0027dequeue\u0027: \u0027/api/tenant/{tenant}/project/{project:.*}/dequeue\u0027,"},{"line_number":543,"context_line":"        }"},{"line_number":544,"context_line":""},{"line_number":545,"context_line":"    @cherrypy.expose"},{"line_number":546,"context_line":"    @cherrypy.tools.json_out(content_type\u003d\u0027application/json; charset\u003dutf-8\u0027)"}],"source_content_type":"text/x-python","patch_set":43,"id":"3fa7e38b_a10c9b42","line":543,"range":{"start_line":508,"start_character":0,"end_line":543,"end_character":9},"updated":"2019-10-04 09:25:55.000000000","message":"On a side note what is the purpose of this? Shouldn\u0027t it also mention the HTTP verb? A few of these endpoints are not just GET.","commit_id":"37d9fe338fbb2f21ae9179b5481d71cbff9815ef"}]}
