)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"c804d29d4aa7d2db735778712f334b231563c1b1","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"037b8e8f_fc2f2b85","updated":"2026-08-04 01:25:50.000000000","message":"FWIW I think we made X-Backend-Crypto-Cipher with the assumption that if this header was present, then said object would be encrypted. We probably need to add \u0027X-Backend-Crypto-Is-Encrypted\u0027 in the future when a caller actual needs to know 100% that the object is encrypted and not just the cipher","commit_id":"ed3a1aa47ad7b524013736d6af60db8fac2335f9"},{"author":{"_account_id":6968,"name":"Christian Schwede","email":"cschwede@nvidia.com","username":"cschwede"},"change_message_id":"2bb33589bc0b860a7aaec8de6d1cd822abc50ba5","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"f64b2bd2_945005d2","updated":"2026-08-20 06:53:39.000000000","message":"There is a corner case that we need to take into account: an empty object that has some unencrypted metadata. In this case we should not return a response that says otherwise.\n\nIdea how to change this in 1001615: sq? encryption: expose X-Backend-Crypto-Cipher on empty objects | https://review.opendev.org/c/openstack/swift/+/1001615 - please abandon if squashing in.","commit_id":"1fb76e52ddd3b42e5f0afdbd80ee47efefe62572"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ba65aa683914c8e60f39be94294b7c20f01f811a","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"9e77844e_3fc3f8f6","updated":"2026-08-21 05:27:58.000000000","message":"this is really hard - if we DON\u0027T call zero-byte objects \"encrypted\" there\u0027s literally no way for s3api to know the difference.\n\nit\u0027s sort of weird that we can\u0027t tell the difference between \"nothing encrypted\" and \"nothing to encrypt\" - but it doesn\u0027t justifies pretending `content_length:0 \u003d\u003d\u003d nothing to encrypt`\n\ne.g. a zero-byte PUT *with metadata* while encryption is disabled will NOT have encrypted metadata, and yet this change will always report it as \"encrypted\" just because the *body* had nothing to encrypt\n\nmaybe better:\n\n1001751: encryption: persist body cipher policy | https://review.opendev.org/c/openstack/swift/+/1001751","commit_id":"1fb76e52ddd3b42e5f0afdbd80ee47efefe62572"}],"swift/common/middleware/crypto/decrypter.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ba65aa683914c8e60f39be94294b7c20f01f811a","unresolved":true,"context_lines":[{"line_number":336,"context_line":"                body\u003d\u0027Error decrypting object\u0027,"},{"line_number":337,"context_line":"                content_type\u003d\u0027text/plain\u0027)"},{"line_number":338,"context_line":""},{"line_number":339,"context_line":"        if put_keys is None and post_keys is None:"},{"line_number":340,"context_line":"            # skip decryption"},{"line_number":341,"context_line":"            start_response(self._response_status, self._response_headers,"},{"line_number":342,"context_line":"                           self._response_exc_info)"}],"source_content_type":"text/x-python","patch_set":2,"id":"1ccd188c_b0edd85e","line":339,"updated":"2026-08-21 05:27:58.000000000","message":"N.B. you CAN (willl always?) have `put_keys` even if `put_crypto_meta` is None - same can happen with `put_keys` \u0026 `post_crypto_meta`\n\nit looks like you end up in `CryptoWSGIContext.get_keys` with `key_id\u003dNone` and it just sort of gives you the \"current\" key instead of the one used for encryption according to the metadata.","commit_id":"1fb76e52ddd3b42e5f0afdbd80ee47efefe62572"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ba65aa683914c8e60f39be94294b7c20f01f811a","unresolved":true,"context_lines":[{"line_number":375,"context_line":""},{"line_number":376,"context_line":"        # Expose encryption metadata for encrypted and empty objects."},{"line_number":377,"context_line":"        if ((put_crypto_meta and put_keys) or"},{"line_number":378,"context_line":"                self._response_header_value(\u0027Content-Length\u0027) \u003d\u003d \u00270\u0027) and \\"},{"line_number":379,"context_line":"                req.method in (\u0027GET\u0027, \u0027HEAD\u0027) and \\"},{"line_number":380,"context_line":"                is_success(self._get_status_int()):"},{"line_number":381,"context_line":"            cipher \u003d (put_crypto_meta or {}).get(\u0027cipher\u0027, self.crypto.cipher)"}],"source_content_type":"text/x-python","patch_set":2,"id":"5e89de1e_5de6ef10","line":378,"updated":"2026-08-21 05:27:58.000000000","message":"this feels like it might be too broad - I considered maybe\n\n```\nif is_success():\n    cipher \u003d (put_crypto_meta or post_crypto_meta)[\u0027cipher\u0027]\n    mod_resp_headers.append(...)\n```\n\nas a stronger hint, but it\u0027s only useful for zero-byte objects that happen to have user-metadata (e.g. swiftclient likes to add Mtime to PUTs)\n\nworse it might open up confusion for a POST update magically making an un-encrypted object report as encrypted.","commit_id":"1fb76e52ddd3b42e5f0afdbd80ee47efefe62572"}],"test/unit/common/middleware/crypto/test_decrypter.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ba65aa683914c8e60f39be94294b7c20f01f811a","unresolved":true,"context_lines":[{"line_number":171,"context_line":"        self.assertEqual(\u0027200 OK\u0027, resp.status)"},{"line_number":172,"context_line":"        self.assertEqual(b\u0027\u0027, resp.body)"},{"line_number":173,"context_line":"        self.assertEqual("},{"line_number":174,"context_line":"            Crypto.cipher, resp.headers[\u0027X-Backend-Crypto-Cipher\u0027])"},{"line_number":175,"context_line":""},{"line_number":176,"context_line":"    def test_HEAD_empty_object_exposes_crypto_cipher(self):"},{"line_number":177,"context_line":"        req \u003d Request.blank("}],"source_content_type":"text/x-python","patch_set":2,"id":"48901075_bf2803ca","line":174,"updated":"2026-08-21 05:27:58.000000000","message":"pretty sure this is proving with NO crypto metadata swift will still claim the object is encrypted\n\n\u003e is that required?\n\nfor aws s3 compatibility yes - I think aws SSE will sort of always report an object is encrypted even if it\u0027s zero bytes and has no metadata\n\n\u003e is that what we want?\n\nfor aws s3 compatibility no - if an object was written before SSE was turned on it shouldn\u0027t report as encrypted just because there\u0027s nothing to encrypt","commit_id":"1fb76e52ddd3b42e5f0afdbd80ee47efefe62572"},{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"ce07ac3250b4d66475eadf34d0c1ceb00d9dbc6a","unresolved":true,"context_lines":[{"line_number":171,"context_line":"        self.assertEqual(\u0027200 OK\u0027, resp.status)"},{"line_number":172,"context_line":"        self.assertEqual(b\u0027\u0027, resp.body)"},{"line_number":173,"context_line":"        self.assertEqual("},{"line_number":174,"context_line":"            Crypto.cipher, resp.headers[\u0027X-Backend-Crypto-Cipher\u0027])"},{"line_number":175,"context_line":""},{"line_number":176,"context_line":"    def test_HEAD_empty_object_exposes_crypto_cipher(self):"},{"line_number":177,"context_line":"        req \u003d Request.blank("}],"source_content_type":"text/x-python","patch_set":2,"id":"cf689f97_42f2b95f","line":174,"in_reply_to":"48901075_bf2803ca","updated":"2026-08-24 20:17:34.000000000","message":"\u003e if an object was written before SSE was turned on it shouldn\u0027t report as encrypted just because there\u0027s nothing to encrypt\n\nI think this is the right approach. It is hard since S3 always has encryption enabled at all times... but I think for our case, yes we should not report encryption if there was no encryption enabled at the time","commit_id":"1fb76e52ddd3b42e5f0afdbd80ee47efefe62572"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ba65aa683914c8e60f39be94294b7c20f01f811a","unresolved":true,"context_lines":[{"line_number":371,"context_line":"        self.assertEqual(\u0027encrypt me\u0027, resp.headers[\u0027x-object-meta-test\u0027])"},{"line_number":372,"context_line":"        self.assertEqual(\u0027do not encrypt me\u0027,"},{"line_number":373,"context_line":"                         resp.headers[\u0027x-object-sysmeta-test\u0027])"},{"line_number":374,"context_line":"        self.assertNotIn(\u0027X-Backend-Crypto-Cipher\u0027, resp.headers)"},{"line_number":375,"context_line":""},{"line_number":376,"context_line":"    def test_GET_412_response(self):"},{"line_number":377,"context_line":"        self._test_412_response(\u0027GET\u0027)"}],"source_content_type":"text/x-python","patch_set":2,"id":"3aad79f5_1c267a10","line":374,"updated":"2026-08-21 05:27:58.000000000","message":"I think it\u0027s pretty sus to respond with decrypted metadata and not include the backend (non client facing crypto-cipher) \n\n... reasonable to say \"we can always add it later if we want it\" - a stronger claim would be to say \"for any response it\u0027s ok to include crypto meta we can include the cipher\"","commit_id":"1fb76e52ddd3b42e5f0afdbd80ee47efefe62572"},{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"ce07ac3250b4d66475eadf34d0c1ceb00d9dbc6a","unresolved":true,"context_lines":[{"line_number":371,"context_line":"        self.assertEqual(\u0027encrypt me\u0027, resp.headers[\u0027x-object-meta-test\u0027])"},{"line_number":372,"context_line":"        self.assertEqual(\u0027do not encrypt me\u0027,"},{"line_number":373,"context_line":"                         resp.headers[\u0027x-object-sysmeta-test\u0027])"},{"line_number":374,"context_line":"        self.assertNotIn(\u0027X-Backend-Crypto-Cipher\u0027, resp.headers)"},{"line_number":375,"context_line":""},{"line_number":376,"context_line":"    def test_GET_412_response(self):"},{"line_number":377,"context_line":"        self._test_412_response(\u0027GET\u0027)"}],"source_content_type":"text/x-python","patch_set":2,"id":"fa2a02ca_751fc042","line":374,"in_reply_to":"3aad79f5_1c267a10","updated":"2026-08-24 20:17:34.000000000","message":"\u003e \"for any response it\u0027s ok to include crypto meta we can include the cipher\"\n\nYes I think this is better, I guess we are on the stance of if we get a cipher, it makes the most sense that the object is actually using encryption. We could 100% put us in a whole in the future if we try to say \"errmm... actually its just the cipher, it doesn\u0027t mean the object is actually encrypted ☝️\" that already sounds like \"then why did you give me it in the first place???\"\n\nTl;dr yea looking more into it, we need to have a stronger approach","commit_id":"1fb76e52ddd3b42e5f0afdbd80ee47efefe62572"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ba65aa683914c8e60f39be94294b7c20f01f811a","unresolved":true,"context_lines":[{"line_number":396,"context_line":"        self.assertEqual(\u0027encrypt me\u0027, resp.headers[\u0027x-object-meta-test\u0027])"},{"line_number":397,"context_line":"        self.assertEqual(\u0027do not encrypt me\u0027,"},{"line_number":398,"context_line":"                         resp.headers[\u0027x-object-sysmeta-test\u0027])"},{"line_number":399,"context_line":"        self.assertNotIn(\u0027X-Backend-Crypto-Cipher\u0027, resp.headers)"},{"line_number":400,"context_line":""},{"line_number":401,"context_line":"    def test_GET_304_response(self):"},{"line_number":402,"context_line":"        self._test_304_response(\u0027GET\u0027)"}],"source_content_type":"text/x-python","patch_set":2,"id":"acd878e8_33f6dafa","line":399,"updated":"2026-08-21 05:27:58.000000000","message":"also sus; same reason","commit_id":"1fb76e52ddd3b42e5f0afdbd80ee47efefe62572"}],"test/unit/common/middleware/s3api/test_obj.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ba65aa683914c8e60f39be94294b7c20f01f811a","unresolved":true,"context_lines":[{"line_number":35,"context_line":""},{"line_number":36,"context_line":"from test.unit.common.middleware.s3api import S3ApiTestCase, S3ApiTestCaseAcl"},{"line_number":37,"context_line":"from test.unit.common.middleware.crypto.crypto_helpers import \\"},{"line_number":38,"context_line":"    fake_get_crypto_meta, fetch_crypto_keys"},{"line_number":39,"context_line":"from swift.common.middleware.s3api.s3request import SigV4Request"},{"line_number":40,"context_line":"from swift.common.middleware.s3api.subresource import ACL, User, encode_acl, \\"},{"line_number":41,"context_line":"    Owner, Grant"}],"source_content_type":"text/x-python","patch_set":2,"id":"0ea0a920_692ba59f","line":38,"updated":"2026-08-21 05:27:58.000000000","message":"this is encoding a kind of \"one way\" dependency of s3api\u0027s test suite on crypto\n\nI think there is reasonably a case to be made this dependency should go this way, but you could make it more reversable using an isolated test module.","commit_id":"1fb76e52ddd3b42e5f0afdbd80ee47efefe62572"},{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"ce07ac3250b4d66475eadf34d0c1ceb00d9dbc6a","unresolved":true,"context_lines":[{"line_number":35,"context_line":""},{"line_number":36,"context_line":"from test.unit.common.middleware.s3api import S3ApiTestCase, S3ApiTestCaseAcl"},{"line_number":37,"context_line":"from test.unit.common.middleware.crypto.crypto_helpers import \\"},{"line_number":38,"context_line":"    fake_get_crypto_meta, fetch_crypto_keys"},{"line_number":39,"context_line":"from swift.common.middleware.s3api.s3request import SigV4Request"},{"line_number":40,"context_line":"from swift.common.middleware.s3api.subresource import ACL, User, encode_acl, \\"},{"line_number":41,"context_line":"    Owner, Grant"}],"source_content_type":"text/x-python","patch_set":2,"id":"faf6d796_e66952d7","line":38,"in_reply_to":"0ea0a920_692ba59f","updated":"2026-08-24 20:17:34.000000000","message":"\u003e using an isolated test module\n\nThis might be better and more clearer I think, using the actual encryption middleware too","commit_id":"1fb76e52ddd3b42e5f0afdbd80ee47efefe62572"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ba65aa683914c8e60f39be94294b7c20f01f811a","unresolved":true,"context_lines":[{"line_number":42,"context_line":"from swift.common.middleware.s3api.etree import fromstring"},{"line_number":43,"context_line":"from swift.common.middleware.s3api.utils import S3Timestamp"},{"line_number":44,"context_line":"from swift.common.middleware.versioned_writes.object_versioning import \\"},{"line_number":45,"context_line":"    DELETE_MARKER_CONTENT_TYPE"},{"line_number":46,"context_line":"from swift.common.utils import md5"},{"line_number":47,"context_line":""},{"line_number":48,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"919f1eb4_f37d3ecb","line":45,"updated":"2026-08-21 05:27:58.000000000","message":"... but given prior art (e.g. ProxyLoggingMiddleware) I don\u0027t think I\u0027d try to justify the technical investment for more isolation/portability as ncessary.","commit_id":"1fb76e52ddd3b42e5f0afdbd80ee47efefe62572"},{"author":{"_account_id":38368,"name":"Christian Ohanaja","display_name":"Christian Ohanaja","email":"cohanaja@nvidia.com","username":"cohanaja"},"change_message_id":"844cb5c677c2d4dd0565af7873f47e47090ca3da","unresolved":true,"context_lines":[{"line_number":2187,"context_line":"            \u0027GET\u0027, \u0027/v1/AUTH_test/bucket/empty-object\u0027, swob.HTTPOk,"},{"line_number":2188,"context_line":"            {\u0027Content-Length\u0027: \u00270\u0027, \u0027Etag\u0027: md5(b\u0027\u0027).hexdigest()}, b\u0027\u0027)"},{"line_number":2189,"context_line":""},{"line_number":2190,"context_line":"        get_req \u003d Request.blank("},{"line_number":2191,"context_line":"            \u0027/bucket/empty-object\u0027,"},{"line_number":2192,"context_line":"            environ\u003d{"},{"line_number":2193,"context_line":"                \u0027REQUEST_METHOD\u0027: \u0027GET\u0027,"}],"source_content_type":"text/x-python","patch_set":2,"id":"cc28543f_d312b5e1","line":2190,"updated":"2026-08-17 21:37:58.000000000","message":"You could probably reduce the GET and HEAD tests to a simple loop, outside that change looks good!\n\n```\nfor method in (\u0027GET\u0027, \u0027HEAD\u0027):\n            req \u003d Request.blank(\n                \u0027/bucket/empty-object\u0027,\n                environ\u003d{\n                    \u0027REQUEST_METHOD\u0027: method,\n                    CRYPTO_KEY_CALLBACK: fetch_crypto_keys,\n                },\n                headers\u003d{\u0027Authorization\u0027: \u0027AWS test:tester:hmac\u0027,\n                         \u0027Date\u0027: self.get_date_header()})\n            status, headers, body \u003d self.call_s3api(req)\n\n            self.assertEqual(\u0027200 OK\u0027, status)\n            self.assertEqual(b\u0027\u0027, body)\n            self.assertEqual(\n                \u0027AES256\u0027, headers[\u0027x-amz-server-side-encryption\u0027])\n```","commit_id":"1fb76e52ddd3b42e5f0afdbd80ee47efefe62572"}]}
