)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":6914,"name":"Tatiana Ovchinnikova","email":"t.v.ovtchinnikova@gmail.com","username":"tmazur"},"change_message_id":"2562452df89561b481c3e683222654a8c3401fe8","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"d9c7d529_ab3659fa","updated":"2026-06-30 17:06:10.000000000","message":"Thank you for the patch! Let\u0027s start tracking this initiative properly: please add the following line into the commit message:\n\nPartially-Implements: blueprint removing-angularjs\n\n-1 to just mark it as an action item","commit_id":"cbf0fcab5f035a0ec5c1b8f28392287db38edd52"},{"author":{"_account_id":8648,"name":"Radomir Dopieralski","email":"openstack@dopieralski.pl","username":"thesheep"},"change_message_id":"d46333f818766cc4f2fdc709c90c4858d4f1783e","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"42c6d721_74c9f797","updated":"2026-07-17 06:56:29.000000000","message":"Let\u0027s explore this in followup patches. The code looks good otherwise, thank you for your contribution.","commit_id":"2d970b080ba8c57f6c97abfcda2891dcd17062fb"},{"author":{"_account_id":35133,"name":"Jan Jasek","email":"jjasek@redhat.com","username":"janjasek"},"change_message_id":"6738274b37f0f2b4f7b03f9160b4e896f2dea19d","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"4f5dab38_051e8a9a","updated":"2026-07-21 11:42:07.000000000","message":"Works in devstack, code looks good to me, thanks!","commit_id":"2d970b080ba8c57f6c97abfcda2891dcd17062fb"}],"openstack_dashboard/dashboards/project/images/images/tables.py":[{"author":{"_account_id":8648,"name":"Radomir Dopieralski","email":"openstack@dopieralski.pl","username":"thesheep"},"change_message_id":"2464f6e6ed6ae62b3688b562c3da1840577cadf9","unresolved":true,"context_lines":[{"line_number":230,"context_line":"            return False"},{"line_number":231,"context_line":"        if image.owner !\u003d request.user.tenant_id:"},{"line_number":232,"context_line":"            return False"},{"line_number":233,"context_line":"        return image.status \u003d\u003d \"active\""},{"line_number":234,"context_line":""},{"line_number":235,"context_line":"    def action(self, request, obj_id):"},{"line_number":236,"context_line":"        api.glance.image_deactivate(request, obj_id)"}],"source_content_type":"text/x-python","patch_set":6,"id":"2655a6f8_1cd0e6ea","line":233,"updated":"2026-07-15 15:30:46.000000000","message":"I think this should be an RBAC policy check -- the logic you have here matches the default policy, but this can be changed in a particular OpenStack install. I believe the policy for this is in glance and is called \"deactivate\". You will need to pass the image as the target to the check.","commit_id":"2d970b080ba8c57f6c97abfcda2891dcd17062fb"},{"author":{"_account_id":32432,"name":"Owen McGonagle","email":"omcgonag@redhat.com","username":"omcgonag"},"change_message_id":"42b42f6281db2943c2551ac9feb18342c50d5889","unresolved":true,"context_lines":[{"line_number":230,"context_line":"            return False"},{"line_number":231,"context_line":"        if image.owner !\u003d request.user.tenant_id:"},{"line_number":232,"context_line":"            return False"},{"line_number":233,"context_line":"        return image.status \u003d\u003d \"active\""},{"line_number":234,"context_line":""},{"line_number":235,"context_line":"    def action(self, request, obj_id):"},{"line_number":236,"context_line":"        api.glance.image_deactivate(request, obj_id)"}],"source_content_type":"text/x-python","patch_set":6,"id":"6f8e2535_115e0850","line":233,"in_reply_to":"0653f6f3_8b1f361c","updated":"2026-07-16 01:59:05.000000000","message":"I believe without the check on allowed() we de-activate button may appear on already de-activiated messages - I am testing that theory right now.","commit_id":"2d970b080ba8c57f6c97abfcda2891dcd17062fb"},{"author":{"_account_id":8648,"name":"Radomir Dopieralski","email":"openstack@dopieralski.pl","username":"thesheep"},"change_message_id":"4f69fdcc78b6991ba672a83057d08d5e20a15bf1","unresolved":true,"context_lines":[{"line_number":230,"context_line":"            return False"},{"line_number":231,"context_line":"        if image.owner !\u003d request.user.tenant_id:"},{"line_number":232,"context_line":"            return False"},{"line_number":233,"context_line":"        return image.status \u003d\u003d \"active\""},{"line_number":234,"context_line":""},{"line_number":235,"context_line":"    def action(self, request, obj_id):"},{"line_number":236,"context_line":"        api.glance.image_deactivate(request, obj_id)"}],"source_content_type":"text/x-python","patch_set":6,"id":"0653f6f3_8b1f361c","line":233,"in_reply_to":"2655a6f8_1cd0e6ea","updated":"2026-07-15 15:37:33.000000000","message":"Sorry, I didn\u0027t notice that you already have policy_rules defined on this action. In this case the allowed method should not be needed?","commit_id":"2d970b080ba8c57f6c97abfcda2891dcd17062fb"},{"author":{"_account_id":8648,"name":"Radomir Dopieralski","email":"openstack@dopieralski.pl","username":"thesheep"},"change_message_id":"1a6da4cfdc79ef19c7208d168326e84ba0688bd0","unresolved":true,"context_lines":[{"line_number":230,"context_line":"            return False"},{"line_number":231,"context_line":"        if image.owner !\u003d request.user.tenant_id:"},{"line_number":232,"context_line":"            return False"},{"line_number":233,"context_line":"        return image.status \u003d\u003d \"active\""},{"line_number":234,"context_line":""},{"line_number":235,"context_line":"    def action(self, request, obj_id):"},{"line_number":236,"context_line":"        api.glance.image_deactivate(request, obj_id)"}],"source_content_type":"text/x-python","patch_set":6,"id":"cf6d1bc8_7b0b112f","line":233,"in_reply_to":"6f8e2535_115e0850","updated":"2026-07-16 07:30:01.000000000","message":"Good point. But the owner check seems harmful, especially if the policy is changed to allow changing images that are not yours?","commit_id":"2d970b080ba8c57f6c97abfcda2891dcd17062fb"},{"author":{"_account_id":32432,"name":"Owen McGonagle","email":"omcgonag@redhat.com","username":"omcgonag"},"change_message_id":"e5c61868604bde9ffc4f9239118cd8f16792b6fb","unresolved":true,"context_lines":[{"line_number":230,"context_line":"            return False"},{"line_number":231,"context_line":"        if image.owner !\u003d request.user.tenant_id:"},{"line_number":232,"context_line":"            return False"},{"line_number":233,"context_line":"        return image.status \u003d\u003d \"active\""},{"line_number":234,"context_line":""},{"line_number":235,"context_line":"    def action(self, request, obj_id):"},{"line_number":236,"context_line":"        api.glance.image_deactivate(request, obj_id)"}],"source_content_type":"text/x-python","patch_set":6,"id":"dcb1da4a_79d776e8","line":233,"in_reply_to":"cf6d1bc8_7b0b112f","updated":"2026-07-16 15:38:21.000000000","message":"For reference, the admin panel overrides the owner check entirely -- it trusts RBAC policy. AdminDeleteImage and AdminEditImage both return True without owner checks:\n\nhttps://github.com/openstack/horizon/blob/master/openstack_dashboard/dashboards/admin/images/tables.py#L29-L41\n\n    class AdminDeleteImage(project_tables.DeleteImage):\n        def allowed(self, request, image\u003dNone):\n            if image and image.protected:\n                return False\n            return True   # No owner check\n\n    class AdminEditImage(project_tables.EditImage):\n        def allowed(self, request, image\u003dNone):\n            return True   # No owner check\n\nNotably, the admin panel does not have Deactivate/Reactivate actions at all today.\n\nIf a Glance policy is `changed to let users deactivate` images from other projects, the Deactivate button would still not appear in the project panel due to this check.\n\nI do not think removing the check is the right thing to do today:\n\n- DeleteImage (line 135) and EditImage (line 163) both have the same owner check\n- Removing it only from Deactivate/Reactivate would be inconsistent with the existing image actions\n\nThey use `PolicyTargetMixin` to pass resource ownership to the RBAC check, letting policy decide:\n\nhttps://github.com/openstack/horizon/blob/master/openstack_dashboard/dashboards/project/volumes/tables.py#L47\n\n    class VolumePolicyTargetMixin(policy.PolicyTargetMixin):\n        policy_target_attrs \u003d ((\"project_id\", \u0027os-vol-tenant-attr:tenant_id\u0027),)\n\nImage actions don\u0027t use this pattern today.\n\n`As a follow-up`, we could explore adopting PolicyTargetMixin for image actions -- that would let operators who modify the Glance policy to allow cross-project deactivation see the button appear correctly, without hardcoding ownership logic in allowed().","commit_id":"2d970b080ba8c57f6c97abfcda2891dcd17062fb"},{"author":{"_account_id":8648,"name":"Radomir Dopieralski","email":"openstack@dopieralski.pl","username":"thesheep"},"change_message_id":"2464f6e6ed6ae62b3688b562c3da1840577cadf9","unresolved":true,"context_lines":[{"line_number":262,"context_line":"            return True"},{"line_number":263,"context_line":"        if image.owner !\u003d request.user.tenant_id:"},{"line_number":264,"context_line":"            return False"},{"line_number":265,"context_line":"        return image.status \u003d\u003d \"deactivated\""},{"line_number":266,"context_line":""},{"line_number":267,"context_line":"    def action(self, request, obj_id):"},{"line_number":268,"context_line":"        api.glance.image_reactivate(request, obj_id)"}],"source_content_type":"text/x-python","patch_set":6,"id":"b2e36933_afdca76a","line":265,"updated":"2026-07-15 15:30:46.000000000","message":"Same here, the policy is called \"reactivate\".","commit_id":"2d970b080ba8c57f6c97abfcda2891dcd17062fb"},{"author":{"_account_id":32432,"name":"Owen McGonagle","email":"omcgonag@redhat.com","username":"omcgonag"},"change_message_id":"2c4cc512d4c3b2f63bfd5c6af82b81f0b63ad950","unresolved":true,"context_lines":[{"line_number":262,"context_line":"            return True"},{"line_number":263,"context_line":"        if image.owner !\u003d request.user.tenant_id:"},{"line_number":264,"context_line":"            return False"},{"line_number":265,"context_line":"        return image.status \u003d\u003d \"deactivated\""},{"line_number":266,"context_line":""},{"line_number":267,"context_line":"    def action(self, request, obj_id):"},{"line_number":268,"context_line":"        api.glance.image_reactivate(request, obj_id)"}],"source_content_type":"text/x-python","patch_set":6,"id":"8435322d_2748b47c","line":265,"in_reply_to":"b2e36933_afdca76a","updated":"2026-07-16 16:52:47.000000000","message":"I believe my last response above applies here also.","commit_id":"2d970b080ba8c57f6c97abfcda2891dcd17062fb"}]}
