)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":11904,"name":"Sean McGinnis","email":"sean.mcginnis@gmail.com","username":"SeanM"},"change_message_id":"8fb039cf1f5c3d72af10f739f6b1fd5682205150","unresolved":false,"context_lines":[{"line_number":15,"context_line":"See https://bugs.python.org/issue9216."},{"line_number":16,"context_line":""},{"line_number":17,"context_line":"Some downstream versions of python already implement this keyword."},{"line_number":18,"context_line":"To permit Openstack to run in FIPS enabled systems with these versions"},{"line_number":19,"context_line":"of python, we add a simple encapsulation of hashlib.md5() here."},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"Once the issue is resolved in upstream python, we can remove this"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":5,"id":"9f560f44_54640fb9","line":18,"range":{"start_line":18,"start_character":10,"end_line":18,"end_character":19},"updated":"2020-09-09 16:25:18.000000000","message":"OpenStack ;)","commit_id":"22e86af25e2a778c94064b6e8ddc0c4eb2359874"}],"oslo_utils/secretutils.py":[{"author":{"_account_id":7973,"name":"Douglas Mendizábal","email":"dmendiza@redhat.com","username":"dougmendizabal"},"change_message_id":"15a44917e9e9f0f832772dc1053a8db00aef1e69","unresolved":false,"context_lines":[{"line_number":47,"context_line":"    constant_time_compare \u003d _constant_time_compare"},{"line_number":48,"context_line":""},{"line_number":49,"context_line":""},{"line_number":50,"context_line":"def _md5(data\u003dNone, usedforsecurity\u003dTrue):"},{"line_number":51,"context_line":"    \"\"\"Return an md5 hashlib object"},{"line_number":52,"context_line":""},{"line_number":53,"context_line":"    This function encapsulates a call to hashlib.md5()"}],"source_content_type":"text/x-python","patch_set":1,"id":"9f560f44_07d90682","line":50,"range":{"start_line":50,"start_character":4,"end_line":50,"end_character":5},"updated":"2020-09-04 20:12:07.000000000","message":"Remove the \u0027_\u0027 as this should be a public method that gets used by client code.","commit_id":"8ea4af5b957940c8077d71dc48bfbae31918bb8c"},{"author":{"_account_id":7973,"name":"Douglas Mendizábal","email":"dmendiza@redhat.com","username":"dougmendizabal"},"change_message_id":"87469e7bea8e912cf0670f4536b4a170dddd8039","unresolved":false,"context_lines":[{"line_number":55,"context_line":""},{"line_number":56,"context_line":"    Some python implementations, however, will allow callers to specify"},{"line_number":57,"context_line":"    permissible non-security related uses of MD5 through a usedoforsecurity"},{"line_number":58,"context_line":"    keyword.  In this case, MD5 invocation will be permitted."},{"line_number":59,"context_line":""},{"line_number":60,"context_line":"    Once this function becomes part of upstream Python, this function"},{"line_number":61,"context_line":"    will no longer be needed."}],"source_content_type":"text/x-python","patch_set":3,"id":"9f560f44_ca09d32b","line":58,"range":{"start_line":58,"start_character":4,"end_line":58,"end_character":12},"updated":"2020-09-04 21:39:45.000000000","message":"s/keyword/keyword argument/","commit_id":"162502a7932c2f280b5f393adf8c6a948c78706b"},{"author":{"_account_id":7973,"name":"Douglas Mendizábal","email":"dmendiza@redhat.com","username":"dougmendizabal"},"change_message_id":"87469e7bea8e912cf0670f4536b4a170dddd8039","unresolved":false,"context_lines":[{"line_number":57,"context_line":"    permissible non-security related uses of MD5 through a usedoforsecurity"},{"line_number":58,"context_line":"    keyword.  In this case, MD5 invocation will be permitted."},{"line_number":59,"context_line":""},{"line_number":60,"context_line":"    Once this function becomes part of upstream Python, this function"},{"line_number":61,"context_line":"    will no longer be needed."},{"line_number":62,"context_line":"    \"\"\""},{"line_number":63,"context_line":"    try:"}],"source_content_type":"text/x-python","patch_set":3,"id":"9f560f44_6a188775","line":60,"range":{"start_line":60,"start_character":39,"end_line":60,"end_character":54},"updated":"2020-09-04 21:39:45.000000000","message":"It may be worthwhile to reference the upstream Python FIPS issue here: https://bugs.python.org/issue9216","commit_id":"162502a7932c2f280b5f393adf8c6a948c78706b"},{"author":{"_account_id":7973,"name":"Douglas Mendizábal","email":"dmendiza@redhat.com","username":"dougmendizabal"},"change_message_id":"87469e7bea8e912cf0670f4536b4a170dddd8039","unresolved":false,"context_lines":[{"line_number":61,"context_line":"    will no longer be needed."},{"line_number":62,"context_line":"    \"\"\""},{"line_number":63,"context_line":"    try:"},{"line_number":64,"context_line":"        if data:"},{"line_number":65,"context_line":"            return hashlib.md5(data, usedforsecurity\u003dusedforsecurity)  # nosec"},{"line_number":66,"context_line":"        else:"},{"line_number":67,"context_line":"            return hashlib.md5(usedforsecurity\u003dusedforsecurity)  # nosec"}],"source_content_type":"text/x-python","patch_set":3,"id":"9f560f44_8a7a3b85","line":64,"range":{"start_line":64,"start_character":11,"end_line":64,"end_character":15},"updated":"2020-09-04 21:39:45.000000000","message":"Maybe we should check explicitly for\n\n    if data is None:\n\nhere?  That way other falsy values would still be passed.  e.g. Passing something like\n\n    secretutils.md5(b\u0027\u0027).digest()\n\nWon\u0027t throw away that empty byte string.\n\nOTOH, maybe we need a fancier way to tell whether the data arg was passed in or not?  If we want to emulate hashlib.md5 exaclty, then checking for None is not enough because:\n\n    hashlib.md5(None)  # raises TypeError\n\nbut,\n\n    secretutils.md5(None)  # returns an MD5 HASH object","commit_id":"162502a7932c2f280b5f393adf8c6a948c78706b"},{"author":{"_account_id":7973,"name":"Douglas Mendizábal","email":"dmendiza@redhat.com","username":"dougmendizabal"},"change_message_id":"9aeb24e219afb1cec0fea6e2b31f356201d53f09","unresolved":false,"context_lines":[{"line_number":66,"context_line":"    \"\"\""},{"line_number":67,"context_line":"    try:"},{"line_number":68,"context_line":"        # test if the usedforsecurity keyword argument is valid"},{"line_number":69,"context_line":"        _md5 \u003d hashlib.md5(usedforsecurity\u003dTrue)  # nosec"},{"line_number":70,"context_line":"        if data is _no_value:"},{"line_number":71,"context_line":"            return _md5"},{"line_number":72,"context_line":"    except TypeError:"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f560f44_c4235657","line":69,"range":{"start_line":69,"start_character":43,"end_line":69,"end_character":47},"updated":"2020-09-09 12:51:39.000000000","message":"s/True/usedforsecurity","commit_id":"e9b80da7bea3eee97b736be427b306ffe2839910"},{"author":{"_account_id":7973,"name":"Douglas Mendizábal","email":"dmendiza@redhat.com","username":"dougmendizabal"},"change_message_id":"eda8be2099660d6beb0ad8bda42d2e1da8f2fbc2","unresolved":false,"context_lines":[{"line_number":61,"context_line":"    keyword argument.  In this case, MD5 invocation will be permitted."},{"line_number":62,"context_line":""},{"line_number":63,"context_line":"    See https://bugs.python.org/issue9216 for the upstream Python issue."},{"line_number":64,"context_line":"    Once this function becomes part of upstream Python, this function"},{"line_number":65,"context_line":"    will no longer be needed."},{"line_number":66,"context_line":"    \"\"\""},{"line_number":67,"context_line":"    try:"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f560f44_a31ef3b7","line":64,"range":{"start_line":64,"start_character":14,"end_line":64,"end_character":22},"updated":"2020-09-10 22:04:25.000000000","message":"nit: s/function/parameter/","commit_id":"c90613d31a1cb0dd26a668656d726b1339626ccf"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"a77232f082a06c547525b343186c1eda991cc7fb","unresolved":false,"context_lines":[{"line_number":50,"context_line":"    constant_time_compare \u003d _constant_time_compare"},{"line_number":51,"context_line":""},{"line_number":52,"context_line":""},{"line_number":53,"context_line":"def md5(data\u003d_no_value, usedforsecurity\u003dTrue):"},{"line_number":54,"context_line":"    \"\"\"Return an md5 hashlib object"},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"    This function encapsulates a call to hashlib.md5()"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f560f44_9ea6670f","line":53,"range":{"start_line":53,"start_character":13,"end_line":53,"end_character":22},"updated":"2020-09-15 05:22:26.000000000","message":"Surely this could just be\n\n def md5(data\u003db\u0027\u0027, usedforsecurity\u003dTrue):\n\nno? Then we have a single (expected) type instead of needing a union this sentinel -- which will also remove the need for the if/else branches.","commit_id":"a8438e50517dc80b181fa71e3c08a6beb6c6ae63"},{"author":{"_account_id":7973,"name":"Douglas Mendizábal","email":"dmendiza@redhat.com","username":"dougmendizabal"},"change_message_id":"7600224253dfee88a41e9dcab8e5e628d0f0298f","unresolved":false,"context_lines":[{"line_number":47,"context_line":"    constant_time_compare \u003d _constant_time_compare"},{"line_number":48,"context_line":""},{"line_number":49,"context_line":""},{"line_number":50,"context_line":"def md5(data\u003db\u0027\u0027, usedforsecurity\u003dTrue):"},{"line_number":51,"context_line":"    \"\"\"Return an md5 hashlib object"},{"line_number":52,"context_line":""},{"line_number":53,"context_line":"    This function encapsulates a call to hashlib.md5()"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f560f44_0d5ea175","line":50,"range":{"start_line":50,"start_character":8,"end_line":50,"end_character":12},"updated":"2020-09-15 20:00:45.000000000","message":"I think it would be better to rename this parameter to \u0027string\u0027 to match the upstream hashlib.md5 signature.\n\n    Help on built-in function openssl_md5 in module _hashlib:\n\n    openssl_md5(string\u003db\u0027\u0027)\n        Returns a md5 hash object; optionally initialized with a string","commit_id":"6393077adfd3d407ab8bab1dd4c30761eee62ebb"},{"author":{"_account_id":7973,"name":"Douglas Mendizábal","email":"dmendiza@redhat.com","username":"dougmendizabal"},"change_message_id":"7600224253dfee88a41e9dcab8e5e628d0f0298f","unresolved":false,"context_lines":[{"line_number":64,"context_line":"    try:"},{"line_number":65,"context_line":"        # test if the usedforsecurity keyword argument is valid"},{"line_number":66,"context_line":"        _md5 \u003d hashlib.md5(usedforsecurity\u003dusedforsecurity)  # nosec"},{"line_number":67,"context_line":"        if data \u003d\u003d b\u0027\u0027:"},{"line_number":68,"context_line":"            return _md5"},{"line_number":69,"context_line":"    except TypeError:"},{"line_number":70,"context_line":"        # usedforsecurity keyword argument is not valid"},{"line_number":71,"context_line":"        return hashlib.md5(data)  # nosec"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f560f44_ad733516","line":68,"range":{"start_line":67,"start_character":0,"end_line":68,"end_character":23},"updated":"2020-09-15 20:00:45.000000000","message":"The function logic may be easier to read if we move this if statement outside of the try block right before the return in the last line.","commit_id":"6393077adfd3d407ab8bab1dd4c30761eee62ebb"},{"author":{"_account_id":7973,"name":"Douglas Mendizábal","email":"dmendiza@redhat.com","username":"dougmendizabal"},"change_message_id":"db4e4f9c43fadca16561b3278b9f5cbab9de2da7","unresolved":false,"context_lines":[{"line_number":64,"context_line":"    try:"},{"line_number":65,"context_line":"        # test if the usedforsecurity keyword argument is valid"},{"line_number":66,"context_line":"        _md5 \u003d hashlib.md5(usedforsecurity\u003dusedforsecurity)  # nosec"},{"line_number":67,"context_line":"        if data \u003d\u003d b\u0027\u0027:"},{"line_number":68,"context_line":"            return _md5"},{"line_number":69,"context_line":"    except TypeError:"},{"line_number":70,"context_line":"        # usedforsecurity keyword argument is not valid"},{"line_number":71,"context_line":"        return hashlib.md5(data)  # nosec"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f560f44_e8023b72","line":68,"range":{"start_line":67,"start_character":0,"end_line":68,"end_character":23},"in_reply_to":"9f560f44_88161f49","updated":"2020-09-15 20:58:02.000000000","message":"Yeah, we\u0027re calling md5 using only the \u0027usedforsecurity\u0027 parameter first to make sure the TypeError raised is due to that argument.\n\nThe `if` statement is really just an optimization to attempt to reuse the md5 object we create during that test.  It could be rewritten without an if statement as:\n\n    try:\n        _ \u003d hashlib.md5(usedforsecurity\u003dusedforsecurity)\n    except TypeError:\n        return hashlib.md5(data)\n    return hashlib.md5(data, usedforsecurity\u003dusedforsecurity)\n\nYour suggestion to use memoryview would work to get rid of the `if` as well, but it has the side effect of raising TypeErrors from the memoryview builtin instead of the hashlib.md5 function.\n\n    \u003e\u003e\u003e secretutils.md5(\u0027foo\u0027)\n    # when using memoryview would raise\n    TypeError: memoryview: a bytes-like object is required, not \u0027str\u0027\n    # as opposed to\n    TypeError: Unicode-objects must be encoded before hashing","commit_id":"6393077adfd3d407ab8bab1dd4c30761eee62ebb"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"7b9eb69f3a99e9ed1cd83edc4d32fc1d25adbf4e","unresolved":false,"context_lines":[{"line_number":64,"context_line":"    try:"},{"line_number":65,"context_line":"        # test if the usedforsecurity keyword argument is valid"},{"line_number":66,"context_line":"        _md5 \u003d hashlib.md5(usedforsecurity\u003dusedforsecurity)  # nosec"},{"line_number":67,"context_line":"        if data \u003d\u003d b\u0027\u0027:"},{"line_number":68,"context_line":"            return _md5"},{"line_number":69,"context_line":"    except TypeError:"},{"line_number":70,"context_line":"        # usedforsecurity keyword argument is not valid"},{"line_number":71,"context_line":"        return hashlib.md5(data)  # nosec"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f560f44_88161f49","line":68,"range":{"start_line":67,"start_character":0,"end_line":68,"end_character":23},"in_reply_to":"9f560f44_ad733516","updated":"2020-09-15 20:24:23.000000000","message":"Or just get rid of the if. I guess it\u0027s there because we can\u0027t easily distinguish between the TypeError raised because of a bad function keyword arg and the TypeError raised because of a bad argument type? How about something like\n\n with memoryview(data):  # Test that data supports buffer protocol\n     try:\n         return hashlib.md5(data, usedforsecurity\u003dusedforsecurity)\n     except TypeError:\n         return hashlib.md5(data)\n\n?","commit_id":"6393077adfd3d407ab8bab1dd4c30761eee62ebb"},{"author":{"_account_id":7973,"name":"Douglas Mendizábal","email":"dmendiza@redhat.com","username":"dougmendizabal"},"change_message_id":"a6ca8d9c84ca66676f6c8a53ee36e6fa3a04b88e","unresolved":false,"context_lines":[{"line_number":64,"context_line":"    try:"},{"line_number":65,"context_line":"        # test if the usedforsecurity keyword argument is valid"},{"line_number":66,"context_line":"        _md5 \u003d hashlib.md5(usedforsecurity\u003dusedforsecurity)  # nosec"},{"line_number":67,"context_line":"        if data \u003d\u003d b\u0027\u0027:"},{"line_number":68,"context_line":"            return _md5"},{"line_number":69,"context_line":"    except TypeError:"},{"line_number":70,"context_line":"        # usedforsecurity keyword argument is not valid"},{"line_number":71,"context_line":"        return hashlib.md5(data)  # nosec"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f560f44_488247a7","line":68,"range":{"start_line":67,"start_character":0,"end_line":68,"end_character":23},"in_reply_to":"9f560f44_e8023b72","updated":"2020-09-15 21:12:23.000000000","message":"Another option would be to just perform the inital runtime test once when the module is loaded:\n\n    try:\n        _ \u003d hashlib.md5(usedforsecurity\u003dFalse)\n        def md5(string\u003db\u0027\u0027, usedforsecurity\u003dTrue):\n            return hashlib.md5(string, usedforsecurity\u003dusedforsecurity)\n    except TypeError:\n        def md5(string\u003db\u0027\u0027, usedforsecurity\u003dTrue):\n            return hashlib.md5(string)\n\nThis way we wouldn\u0027t have to check every time the function is called.","commit_id":"6393077adfd3d407ab8bab1dd4c30761eee62ebb"}],"oslo_utils/tests/test_secretutils.py":[{"author":{"_account_id":7973,"name":"Douglas Mendizábal","email":"dmendiza@redhat.com","username":"dougmendizabal"},"change_message_id":"87469e7bea8e912cf0670f4536b4a170dddd8039","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"9f560f44_6a5087d6","line":95,"updated":"2020-09-04 21:39:45.000000000","message":"Consider adding some negative tests as well.  e.g.\n\n    def test_string_data_raises_type_error(self):\n        with self.assertRaises(TypeError):\n            md5 \u003d hashlib.md5(\u0027foo\u0027)\n        with self.assertRaises(TypeError):\n            md5 \u003d secretutils.md5(\u0027foo\u0027)","commit_id":"162502a7932c2f280b5f393adf8c6a948c78706b"}],"releasenotes/notes/add-md5-wrapper-7bf81c2464a7a224.yaml":[{"author":{"_account_id":11904,"name":"Sean McGinnis","email":"sean.mcginnis@gmail.com","username":"SeanM"},"change_message_id":"756ccfbd5a360ddfb21e23f5d24fbe5383d153f4","unresolved":false,"context_lines":[{"line_number":1,"context_line":"---"},{"line_number":2,"context_line":"prelude: \u003e"},{"line_number":3,"context_line":"    A wrapper for hashlib.md5() has been added to allow OpenStack to run on"},{"line_number":4,"context_line":"    systems where FIPS is enabled.  Under FIPS, md5 is disabled and calls to"},{"line_number":5,"context_line":"    hashlib.md5() will fail.  In most cases in OpenStack, though, md5 is not"}],"source_content_type":"text/x-yaml","patch_set":6,"id":"9f560f44_00351545","line":2,"range":{"start_line":2,"start_character":0,"end_line":2,"end_character":7},"updated":"2020-09-11 00:22:51.000000000","message":"Not sure if we need a separate prelude section for this, or just having this all under features would be good. But content looks great.","commit_id":"c90613d31a1cb0dd26a668656d726b1339626ccf"}]}
