)]}'
{"doc/source/overview_encryption.rst":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"fd03fa3a4c71ac16d9019db0a20d5e6fbd941e6b","unresolved":false,"context_lines":[{"line_number":190,"context_line":"    to be re-encrypted. Existing encrypted data will be decrypted using the"},{"line_number":191,"context_line":"    root secret that was active when that data was written. All previous active"},{"line_number":192,"context_line":"    root secrets must therefore remain in the middleware configuration in order"},{"line_number":193,"context_line":"    for decryption of existing data to succeed."},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"For example, the following keymaster configuration file specifies three root"},{"line_number":196,"context_line":"secrets, with the value of ``encryption_root_secret_2`` being the current"}],"source_content_type":"text/x-rst","patch_set":5,"id":"5f7c97a3_1d7a4eef","line":193,"updated":"2018-07-27 17:32:40.000000000","message":"Deserves another note, about how you need to do the config change in two stages to preserve availability.","commit_id":"d405c5a42f9fd46afd65f833b799e0a35976e0be"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"9e764e10778013a7c70a9973595591f51a06aba2","unresolved":false,"context_lines":[{"line_number":211,"context_line":"    new secret id and restart the proxy. Again, do this for all proxies. This"},{"line_number":212,"context_line":"    process ensures that all proxies will have the new key available for"},{"line_number":213,"context_line":"    *decryption* before any proxy uses it for *encryption*."},{"line_number":214,"context_line":""},{"line_number":215,"context_line":"Encryption middleware"},{"line_number":216,"context_line":"---------------------"},{"line_number":217,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"3f79a3b5_f375ee32","line":214,"updated":"2018-08-16 16:00:56.000000000","message":"these docs are good\n\nnote to self - we need to emphasize that the secret_id is written with the encryption data and can never change\n\n... maybe a uuid would be a better example","commit_id":"9589e75d9d5e2bac0b1274095989ec1830c2a379"}],"etc/proxy-server.conf-sample":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"bc8ada05ea452ad5909594a2d04356e5acf3f467","unresolved":false,"context_lines":[{"line_number":1054,"context_line":"# This is specified by the \u0027active_root_secret_id\u0027 option. If"},{"line_number":1055,"context_line":"# \u0027active_root_secret_id\u0027 is not specified then the root secret specified by"},{"line_number":1056,"context_line":"# \u0027encryption_root_secret\u0027 is considered to be the default. Once a root secret"},{"line_number":1057,"context_line":"# has been used as the default root secret it must remain in the config file in"},{"line_number":1058,"context_line":"# order that any objects that were encrypted with it may be subsequently"},{"line_number":1059,"context_line":"# decrypted."},{"line_number":1060,"context_line":"# encryption_root_secret_myid \u003d changeme"}],"source_content_type":"application/octet-stream","patch_set":3,"id":"5f7c97a3_7c178d9e","line":1057,"range":{"start_line":1057,"start_character":44,"end_line":1057,"end_character":76},"updated":"2018-07-09 19:14:25.000000000","message":"Might also be worth noting that the ID used must not change.","commit_id":"847e70d8f794b094029aebc98d69076b1537926a"}],"swift/common/middleware/crypto/crypto_utils.py":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"bc8ada05ea452ad5909594a2d04356e5acf3f467","unresolved":false,"context_lines":[{"line_number":168,"context_line":"        try:"},{"line_number":169,"context_line":"            keys \u003d fetch_crypto_keys(key_id\u003dkey_id)"},{"line_number":170,"context_line":"        except Exception as err:  # noqa"},{"line_number":171,"context_line":"            self.logger.exception(_("},{"line_number":172,"context_line":"                \u0027ERROR get_keys(): from callback: %s\u0027) % err)"},{"line_number":173,"context_line":"            raise HTTPInternalServerError("},{"line_number":174,"context_line":"                \"Unable to retrieve encryption keys.\")"}],"source_content_type":"text/x-python","patch_set":3,"id":"5f7c97a3_dc67c123","line":171,"range":{"start_line":171,"start_character":24,"end_line":171,"end_character":33},"updated":"2018-07-09 19:14:25.000000000","message":"Logging at exception seems a little much for an unknown key -- I\u0027m not sure the traceback really buys us much. One more argument for a UnknownKeyIdError?","commit_id":"847e70d8f794b094029aebc98d69076b1537926a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"bc8ada05ea452ad5909594a2d04356e5acf3f467","unresolved":false,"context_lines":[{"line_number":195,"context_line":"        # get a list of keys from the keymaster containing one dict of keys for"},{"line_number":196,"context_line":"        # each of the keymaster root secret ids"},{"line_number":197,"context_line":"        keys \u003d [self.get_keys(env)]"},{"line_number":198,"context_line":"        key_id \u003d keys[0].get(\u0027id\u0027, {})"},{"line_number":199,"context_line":"        for other_key_id in keys[0].get(\u0027all_ids\u0027, []):"},{"line_number":200,"context_line":"            if other_key_id \u003d\u003d key_id:"},{"line_number":201,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":3,"id":"5f7c97a3_dc402162","line":198,"range":{"start_line":198,"start_character":25,"end_line":198,"end_character":38},"updated":"2018-07-09 19:14:25.000000000","message":"\u0027id\u0027 should always be present, yeah?","commit_id":"847e70d8f794b094029aebc98d69076b1537926a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"fd03fa3a4c71ac16d9019db0a20d5e6fbd941e6b","unresolved":false,"context_lines":[{"line_number":198,"context_line":"        # get a list of keys from the keymaster containing one dict of keys for"},{"line_number":199,"context_line":"        # each of the keymaster root secret ids"},{"line_number":200,"context_line":"        keys \u003d [self.get_keys(env)]"},{"line_number":201,"context_line":"        key_id \u003d keys[0][\u0027id\u0027]"},{"line_number":202,"context_line":"        for other_key_id in keys[0].get(\u0027all_ids\u0027, []):"},{"line_number":203,"context_line":"            if other_key_id \u003d\u003d key_id:"},{"line_number":204,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":5,"id":"5f7c97a3_9dc41e43","line":201,"range":{"start_line":201,"start_character":8,"end_line":201,"end_character":14},"updated":"2018-07-27 17:32:40.000000000","message":"Maybe better as active_key_id?","commit_id":"d405c5a42f9fd46afd65f833b799e0a35976e0be"}],"swift/common/middleware/crypto/decrypter.py":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"09e57b28b12ff999335e2f58f38e539696a14bf8","unresolved":false,"context_lines":[{"line_number":44,"context_line":"        Extract a crypto_meta dict from a header."},{"line_number":45,"context_line":""},{"line_number":46,"context_line":"        :param header_name: name of header that may have crypto_meta"},{"line_number":47,"context_line":"        :param check: if True validate the crypto meta"},{"line_number":48,"context_line":"        :return: A dict containing crypto_meta items"},{"line_number":49,"context_line":"        :raises EncryptionException: if an error occurs while parsing the"},{"line_number":50,"context_line":"                                     crypto meta"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_dbbb3de2","line":47,"updated":"2018-06-25 22:14:01.000000000","message":"When would we *not* want this?","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"157107cf4860960ad0bc9d08022fa6ecaab36d5f","unresolved":false,"context_lines":[{"line_number":44,"context_line":"        Extract a crypto_meta dict from a header."},{"line_number":45,"context_line":""},{"line_number":46,"context_line":"        :param header_name: name of header that may have crypto_meta"},{"line_number":47,"context_line":"        :param check: if True validate the crypto meta"},{"line_number":48,"context_line":"        :return: A dict containing crypto_meta items"},{"line_number":49,"context_line":"        :raises EncryptionException: if an error occurs while parsing the"},{"line_number":50,"context_line":"                                     crypto meta"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_bc172e9d","line":47,"in_reply_to":"5f7c97a3_dbbb3de2","updated":"2018-06-27 17:43:41.000000000","message":"when the header is X-Object-Transient-Sysmeta-Crypto-Meta\n\nthat crypto meta does not store an IV because it is common to all metadata","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"09e57b28b12ff999335e2f58f38e539696a14bf8","unresolved":false,"context_lines":[{"line_number":83,"context_line":"            body\u003d\u0027Error decrypting %s\u0027 % self.server_type,"},{"line_number":84,"context_line":"            content_type\u003d\u0027text/plain\u0027)"},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"    def decrypt_value_with_meta(self, value, key, required\u003dFalse):"},{"line_number":87,"context_line":"        \"\"\""},{"line_number":88,"context_line":"        Base64-decode and decrypt a value if crypto meta can be extracted from"},{"line_number":89,"context_line":"        the value itself, otherwise return the value unmodified."}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_9b57055b","line":86,"updated":"2018-06-25 22:14:01.000000000","message":"I was kind of expecting this to be the spot to grow a call to get_decryption_keys...","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"09e57b28b12ff999335e2f58f38e539696a14bf8","unresolved":false,"context_lines":[{"line_number":216,"context_line":"            encrypted_etag \u003d self._response_header_value(etag_header)"},{"line_number":217,"context_line":"            if encrypted_etag:"},{"line_number":218,"context_line":"                decrypted_etag \u003d self._decrypt_header("},{"line_number":219,"context_line":"                    etag_header, encrypted_etag, put_keys[\u0027container\u0027])"},{"line_number":220,"context_line":"                mod_hdr_pairs.append((etag_header, decrypted_etag))"},{"line_number":221,"context_line":""},{"line_number":222,"context_line":"        # Decrypt all user metadata. Encrypted user metadata values are stored"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_2117a0f0","line":219,"updated":"2018-06-25 22:14:01.000000000","message":"Off-topic: Hrm. Now I\u0027m trying to remember why this doesn\u0027t have required\u003dTrue...","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"09e57b28b12ff999335e2f58f38e539696a14bf8","unresolved":false,"context_lines":[{"line_number":344,"context_line":"            \u0027X-Object-Sysmeta-Crypto-Body-Meta\u0027, True)"},{"line_number":345,"context_line":"        put_keys \u003d self.get_decryption_keys(req, put_crypto_meta)"},{"line_number":346,"context_line":"        post_crypto_meta \u003d self._read_crypto_meta("},{"line_number":347,"context_line":"            \u0027X-Object-Transient-Sysmeta-Crypto-Meta\u0027, False)"},{"line_number":348,"context_line":"        post_keys \u003d self.get_decryption_keys(req, post_crypto_meta)"},{"line_number":349,"context_line":""},{"line_number":350,"context_line":"        if put_keys is None and post_keys is None:"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_a1b17003","line":347,"range":{"start_line":347,"start_character":54,"end_line":347,"end_character":59},"updated":"2018-06-25 22:14:01.000000000","message":"OK, so this is the only spot that check may be False... why? It just checks cipher and IV length, yeah? Those seem like they should still apply...","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"157107cf4860960ad0bc9d08022fa6ecaab36d5f","unresolved":false,"context_lines":[{"line_number":344,"context_line":"            \u0027X-Object-Sysmeta-Crypto-Body-Meta\u0027, True)"},{"line_number":345,"context_line":"        put_keys \u003d self.get_decryption_keys(req, put_crypto_meta)"},{"line_number":346,"context_line":"        post_crypto_meta \u003d self._read_crypto_meta("},{"line_number":347,"context_line":"            \u0027X-Object-Transient-Sysmeta-Crypto-Meta\u0027, False)"},{"line_number":348,"context_line":"        post_keys \u003d self.get_decryption_keys(req, post_crypto_meta)"},{"line_number":349,"context_line":""},{"line_number":350,"context_line":"        if put_keys is None and post_keys is None:"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_3ccf9e28","line":347,"range":{"start_line":347,"start_character":54,"end_line":347,"end_character":59},"in_reply_to":"5f7c97a3_a1b17003","updated":"2018-06-27 17:43:41.000000000","message":"see above, no IV stored in X-Object-Transient-Sysmeta-Crypto-Meta","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"09e57b28b12ff999335e2f58f38e539696a14bf8","unresolved":false,"context_lines":[{"line_number":409,"context_line":"    def decrypt_obj_dict(self, req, obj_dict):"},{"line_number":410,"context_line":"        if \u0027hash\u0027 in obj_dict:"},{"line_number":411,"context_line":"            # each object\u0027s etag may have been encrypted with a different key"},{"line_number":412,"context_line":"            # so fetch keys based on its crypto meta"},{"line_number":413,"context_line":"            ciphertext, crypto_meta \u003d extract_crypto_meta(obj_dict[\u0027hash\u0027])"},{"line_number":414,"context_line":"            if crypto_meta:"},{"line_number":415,"context_line":"                self.crypto.check_crypto_meta(crypto_meta)"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_bbe521dd","line":412,"updated":"2018-06-25 22:14:01.000000000","message":"Presumably there\u0027s an expectation that many objects may share the same key -- who should be responsible for caching keys by id, the decrypter or keymaster?","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"157107cf4860960ad0bc9d08022fa6ecaab36d5f","unresolved":false,"context_lines":[{"line_number":409,"context_line":"    def decrypt_obj_dict(self, req, obj_dict):"},{"line_number":410,"context_line":"        if \u0027hash\u0027 in obj_dict:"},{"line_number":411,"context_line":"            # each object\u0027s etag may have been encrypted with a different key"},{"line_number":412,"context_line":"            # so fetch keys based on its crypto meta"},{"line_number":413,"context_line":"            ciphertext, crypto_meta \u003d extract_crypto_meta(obj_dict[\u0027hash\u0027])"},{"line_number":414,"context_line":"            if crypto_meta:"},{"line_number":415,"context_line":"                self.crypto.check_crypto_meta(crypto_meta)"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_fcab661a","line":412,"in_reply_to":"5f7c97a3_bbe521dd","updated":"2018-06-27 17:43:41.000000000","message":"the keymaster (in next patchset)","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"bc8ada05ea452ad5909594a2d04356e5acf3f467","unresolved":false,"context_lines":[{"line_number":416,"context_line":"            ciphertext, crypto_meta \u003d extract_crypto_meta(obj_dict[\u0027hash\u0027])"},{"line_number":417,"context_line":"            if crypto_meta:"},{"line_number":418,"context_line":"                self.crypto.check_crypto_meta(crypto_meta)"},{"line_number":419,"context_line":"                keys \u003d self.get_decryption_keys(req, crypto_meta)"},{"line_number":420,"context_line":"                obj_dict[\u0027hash\u0027] \u003d self.decrypt_value("},{"line_number":421,"context_line":"                    ciphertext, keys[\u0027container\u0027], crypto_meta)"},{"line_number":422,"context_line":"        return obj_dict"}],"source_content_type":"text/x-python","patch_set":3,"id":"5f7c97a3_1c621917","line":419,"updated":"2018-07-09 19:14:25.000000000","message":"It\u0027d be nice if losing the key for *one* object didn\u0027t hose the listing for the *entire* container -- I wonder if it\u0027d be worth catching errors here and setting\n\n obj_dict[\u0027hash\u0027] \u003d \u0027\u003ccannot be decrypted\u003e\u0027\n\nor something...","commit_id":"847e70d8f794b094029aebc98d69076b1537926a"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"77ea9bd8e122da0c90b776e62933371d2bfaf947","unresolved":false,"context_lines":[{"line_number":136,"context_line":"        Determine if a response should be decrypted, and if so then fetch keys."},{"line_number":137,"context_line":""},{"line_number":138,"context_line":"        :param req: a Request object"},{"line_number":139,"context_line":"        :param req: a dict of crypto metadata"},{"line_number":140,"context_line":"        :returns: a dict of decryption keys"},{"line_number":141,"context_line":"        \"\"\""},{"line_number":142,"context_line":"        if config_true_value(req.environ.get(\u0027swift.crypto.override\u0027)):"}],"source_content_type":"text/x-python","patch_set":6,"id":"5f7c97a3_2c0027ff","line":139,"range":{"start_line":139,"start_character":15,"end_line":139,"end_character":18},"updated":"2018-07-31 04:30:47.000000000","message":"crypto_meta","commit_id":"b789d0723b7153c7ff1f8d50a611183d34a23037"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"2ed5c8af54cbc44581c8ab652991b7f1bcef8f3a","unresolved":false,"context_lines":[{"line_number":136,"context_line":"        Determine if a response should be decrypted, and if so then fetch keys."},{"line_number":137,"context_line":""},{"line_number":138,"context_line":"        :param req: a Request object"},{"line_number":139,"context_line":"        :param req: a dict of crypto metadata"},{"line_number":140,"context_line":"        :returns: a dict of decryption keys"},{"line_number":141,"context_line":"        \"\"\""},{"line_number":142,"context_line":"        if config_true_value(req.environ.get(\u0027swift.crypto.override\u0027)):"}],"source_content_type":"text/x-python","patch_set":6,"id":"5f7c97a3_b0d8d850","line":139,"range":{"start_line":139,"start_character":15,"end_line":139,"end_character":18},"in_reply_to":"5f7c97a3_2c0027ff","updated":"2018-07-31 23:51:34.000000000","message":"Done","commit_id":"b789d0723b7153c7ff1f8d50a611183d34a23037"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"9e764e10778013a7c70a9973595591f51a06aba2","unresolved":false,"context_lines":[{"line_number":190,"context_line":"                result.append((new_prefix + short_name, decrypted_value))"},{"line_number":191,"context_line":"        return result"},{"line_number":192,"context_line":""},{"line_number":193,"context_line":"    def decrypt_resp_headers(self, put_keys, post_keys):"},{"line_number":194,"context_line":"        \"\"\""},{"line_number":195,"context_line":"        Find encrypted headers and replace with the decrypted versions."},{"line_number":196,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"3f79a3b5_760c6c93","line":193,"updated":"2018-08-16 16:00:56.000000000","message":"so previously you could have encrypted data and unencrypted metadata - but anything encrypted was encrypted with the same \"keys\"\n\nN.B. each individual secret will have a pair of object/container layer \"keys\" derived from it\n\nthis will get interesting if we add updatable metadata to the object layer","commit_id":"9589e75d9d5e2bac0b1274095989ec1830c2a379"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"9e764e10778013a7c70a9973595591f51a06aba2","unresolved":false,"context_lines":[{"line_number":301,"context_line":"            \u0027X-Object-Sysmeta-Crypto-Body-Meta\u0027, True)"},{"line_number":302,"context_line":"        put_keys \u003d self.get_decryption_keys(req, put_crypto_meta)"},{"line_number":303,"context_line":"        post_crypto_meta \u003d self._read_crypto_meta("},{"line_number":304,"context_line":"            \u0027X-Object-Transient-Sysmeta-Crypto-Meta\u0027, False)"},{"line_number":305,"context_line":"        post_keys \u003d self.get_decryption_keys(req, post_crypto_meta)"},{"line_number":306,"context_line":"        if put_keys is None and post_keys is None:"},{"line_number":307,"context_line":"            # skip decryption"}],"source_content_type":"text/x-python","patch_set":7,"id":"3f79a3b5_b4df40d5","line":304,"updated":"2018-08-16 16:00:56.000000000","message":"why don\u0027t we check here?\n\nI don\u0027t get it...\n\nproxy ERROR: Error decrypting object: Bad crypto meta: Missing \u0027iv\u0027 (txn: tx854b71d63f9641e198f54-005b759ee7)","commit_id":"9589e75d9d5e2bac0b1274095989ec1830c2a379"}],"swift/common/middleware/crypto/keymaster.py":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"09e57b28b12ff999335e2f58f38e539696a14bf8","unresolved":false,"context_lines":[{"line_number":167,"context_line":"        # anything else"},{"line_number":168,"context_line":"        return self.app(env, start_response)"},{"line_number":169,"context_line":""},{"line_number":170,"context_line":"    def create_key(self, key_id):"},{"line_number":171,"context_line":"        return hmac.new(self.root_secret, key_id,"},{"line_number":172,"context_line":"                        digestmod\u003dhashlib.sha256).digest()"},{"line_number":173,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_5b0ded3b","side":"PARENT","line":170,"range":{"start_line":170,"start_character":25,"end_line":170,"end_character":31},"updated":"2018-06-25 22:14:01.000000000","message":"Yeah, that was a horrible name even at the time.","commit_id":"1fa4b9e3feba75e56293aaf57352ec5add3551a4"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"09e57b28b12ff999335e2f58f38e539696a14bf8","unresolved":false,"context_lines":[{"line_number":68,"context_line":"            # using a specific root secret id"},{"line_number":69,"context_line":"            secret_id \u003d self.keymaster.default_secret_id"},{"line_number":70,"context_line":"        if secret_id in self._keys:"},{"line_number":71,"context_line":"            return self._keys[secret_id]"},{"line_number":72,"context_line":""},{"line_number":73,"context_line":"        keys \u003d {}"},{"line_number":74,"context_line":"        account_path \u003d os.path.join(os.sep, self.account)"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_5b888dc4","line":71,"updated":"2018-06-25 22:14:01.000000000","message":"Where does this get populated?","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"157107cf4860960ad0bc9d08022fa6ecaab36d5f","unresolved":false,"context_lines":[{"line_number":68,"context_line":"            # using a specific root secret id"},{"line_number":69,"context_line":"            secret_id \u003d self.keymaster.default_secret_id"},{"line_number":70,"context_line":"        if secret_id in self._keys:"},{"line_number":71,"context_line":"            return self._keys[secret_id]"},{"line_number":72,"context_line":""},{"line_number":73,"context_line":"        keys \u003d {}"},{"line_number":74,"context_line":"        account_path \u003d os.path.join(os.sep, self.account)"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_6d8c7e34","line":71,"in_reply_to":"5f7c97a3_5b888dc4","updated":"2018-06-27 17:43:41.000000000","message":"in the next patchset ;)","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"09e57b28b12ff999335e2f58f38e539696a14bf8","unresolved":false,"context_lines":[{"line_number":101,"context_line":"        return keys"},{"line_number":102,"context_line":""},{"line_number":103,"context_line":"    def handle_request(self, req, start_response):"},{"line_number":104,"context_line":"        req.environ[CRYPTO_KEY_CALLBACK] \u003d self.fetch_crypto_keys"},{"line_number":105,"context_line":"        resp \u003d self._app_call(req.environ)"},{"line_number":106,"context_line":"        start_response(self._response_status, self._response_headers,"},{"line_number":107,"context_line":"                       self._response_exc_info)"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_fe9dc7ba","line":104,"updated":"2018-06-25 22:14:01.000000000","message":"So this is still the primary interface the keymaster exposes -- what do we imagine the \"get all possible keys for this path\" interface being? We\u0027ll need that for If-Match/If-None-Match, yeah?","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"157107cf4860960ad0bc9d08022fa6ecaab36d5f","unresolved":false,"context_lines":[{"line_number":101,"context_line":"        return keys"},{"line_number":102,"context_line":""},{"line_number":103,"context_line":"    def handle_request(self, req, start_response):"},{"line_number":104,"context_line":"        req.environ[CRYPTO_KEY_CALLBACK] \u003d self.fetch_crypto_keys"},{"line_number":105,"context_line":"        resp \u003d self._app_call(req.environ)"},{"line_number":106,"context_line":"        start_response(self._response_status, self._response_headers,"},{"line_number":107,"context_line":"                       self._response_exc_info)"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_6ddf9e0b","line":104,"in_reply_to":"5f7c97a3_fe9dc7ba","updated":"2018-06-27 17:43:41.000000000","message":"fetch_crypto_keys(all\u003dTrue) ???","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"09e57b28b12ff999335e2f58f38e539696a14bf8","unresolved":false,"context_lines":[{"line_number":176,"context_line":"        \"\"\""},{"line_number":177,"context_line":"        if self.keymaster_config_path:"},{"line_number":178,"context_line":"            keymaster_opts \u003d [\u0027encryption_root_secret\u0027]"},{"line_number":179,"context_line":"            conf \u003d self._load_keymaster_config_file(conf, keymaster_opts)"},{"line_number":180,"context_line":""},{"line_number":181,"context_line":"        root_secrets \u003d {}"},{"line_number":182,"context_line":"        prefix \u003d \u0027encryption_root_secret\u0027"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_3b77d1d3","line":179,"range":{"start_line":179,"start_character":58,"end_line":179,"end_character":72},"updated":"2018-06-25 22:14:01.000000000","message":"So we\u0027re not going to check for the arbitrary encryption_root_secret_\u003ckey_id\u003e options?","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"157107cf4860960ad0bc9d08022fa6ecaab36d5f","unresolved":false,"context_lines":[{"line_number":176,"context_line":"        \"\"\""},{"line_number":177,"context_line":"        if self.keymaster_config_path:"},{"line_number":178,"context_line":"            keymaster_opts \u003d [\u0027encryption_root_secret\u0027]"},{"line_number":179,"context_line":"            conf \u003d self._load_keymaster_config_file(conf, keymaster_opts)"},{"line_number":180,"context_line":""},{"line_number":181,"context_line":"        root_secrets \u003d {}"},{"line_number":182,"context_line":"        prefix \u003d \u0027encryption_root_secret\u0027"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_759be8c7","line":179,"range":{"start_line":179,"start_character":58,"end_line":179,"end_character":72},"in_reply_to":"5f7c97a3_3b77d1d3","updated":"2018-06-27 17:43:41.000000000","message":"Done","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"09e57b28b12ff999335e2f58f38e539696a14bf8","unresolved":false,"context_lines":[{"line_number":193,"context_line":"                    \u0027%s option in %s must be a base64 encoding of at least 32 \u0027"},{"line_number":194,"context_line":"                    \u0027raw bytes\u0027 %"},{"line_number":195,"context_line":"                    (k, self.keymaster_config_path or \u0027proxy-server.conf\u0027))"},{"line_number":196,"context_line":"            root_secrets[suffix[1:] or None] \u003d secret"},{"line_number":197,"context_line":"        return root_secrets"},{"line_number":198,"context_line":""},{"line_number":199,"context_line":"    def __call__(self, env, start_response):"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_5b5f2d40","line":196,"range":{"start_line":196,"start_character":25,"end_line":196,"end_character":43},"updated":"2018-06-25 22:14:01.000000000","message":"So encryption_root_secret and encryption_root_secret_ both map to None?","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"157107cf4860960ad0bc9d08022fa6ecaab36d5f","unresolved":false,"context_lines":[{"line_number":193,"context_line":"                    \u0027%s option in %s must be a base64 encoding of at least 32 \u0027"},{"line_number":194,"context_line":"                    \u0027raw bytes\u0027 %"},{"line_number":195,"context_line":"                    (k, self.keymaster_config_path or \u0027proxy-server.conf\u0027))"},{"line_number":196,"context_line":"            root_secrets[suffix[1:] or None] \u003d secret"},{"line_number":197,"context_line":"        return root_secrets"},{"line_number":198,"context_line":""},{"line_number":199,"context_line":"    def __call__(self, env, start_response):"}],"source_content_type":"text/x-python","patch_set":1,"id":"5f7c97a3_f51ff8b5","line":196,"range":{"start_line":196,"start_character":25,"end_line":196,"end_character":43},"in_reply_to":"5f7c97a3_5b5f2d40","updated":"2018-06-27 17:43:41.000000000","message":"Done","commit_id":"a2ea3201237dff865c3124d46b62b04b4c03bd3b"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"bc8ada05ea452ad5909594a2d04356e5acf3f467","unresolved":false,"context_lines":[{"line_number":103,"context_line":"            keys[\u0027id\u0027] \u003d self._make_key_id(path, secret_id)"},{"line_number":104,"context_line":"            # pass back a list of key id dicts for all other secret ids in case"},{"line_number":105,"context_line":"            # the caller is interested, in which case the caller can call this"},{"line_number":106,"context_line":"            # method again for different secret ids; this avoided changing the"},{"line_number":107,"context_line":"            # return type of the callback or adding another callback. Note that"},{"line_number":108,"context_line":"            # the caller should assume no knowledge of the content of these key"},{"line_number":109,"context_line":"            # id dicts."},{"line_number":110,"context_line":"            keys[\u0027all_ids\u0027] \u003d [self._make_key_id(path, id_)"}],"source_content_type":"text/x-python","patch_set":3,"id":"5f7c97a3_34203249","line":107,"range":{"start_line":106,"start_character":53,"end_line":107,"end_character":41},"updated":"2018-07-09 19:14:25.000000000","message":"IDK, I kinda liked your other idea of having an `all` kwarg -- which would be a decent way to switch between returning a dict vs. a list...\n\nI guess maybe we\u0027d worry about making it hard for third-party keymasters to support both old and new swift, though?","commit_id":"847e70d8f794b094029aebc98d69076b1537926a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"bc8ada05ea452ad5909594a2d04356e5acf3f467","unresolved":false,"context_lines":[{"line_number":107,"context_line":"            # return type of the callback or adding another callback. Note that"},{"line_number":108,"context_line":"            # the caller should assume no knowledge of the content of these key"},{"line_number":109,"context_line":"            # id dicts."},{"line_number":110,"context_line":"            keys[\u0027all_ids\u0027] \u003d [self._make_key_id(path, id_)"},{"line_number":111,"context_line":"                               for id_ in self.keymaster.root_secret_ids]"},{"line_number":112,"context_line":"            self._keys[secret_id] \u003d keys"},{"line_number":113,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"5f7c97a3_bc59a55b","line":110,"range":{"start_line":110,"start_character":31,"end_line":110,"end_character":59},"updated":"2018-07-09 19:14:25.000000000","message":"It\u0027s still a little weird to me that these dicts all share the same\n\n \u0027v\u0027: \u00271\u0027, \u0027path\u0027: path\n\nkeys, but I guess we need a way to distinguish between \"give me the key that has no secret_id suffix\" and \"give me the default key id\". *shrug*","commit_id":"847e70d8f794b094029aebc98d69076b1537926a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"bc8ada05ea452ad5909594a2d04356e5acf3f467","unresolved":false,"context_lines":[{"line_number":168,"context_line":"                if ((km_opt.endswith(\u0027*\u0027) and opt.startswith(km_opt[:-1])) or"},{"line_number":169,"context_line":"                        opt \u003d\u003d km_opt):"},{"line_number":170,"context_line":"                    bad_opts.append(opt)"},{"line_number":171,"context_line":"            if bad_opts:"},{"line_number":172,"context_line":"                raise ValueError(\u0027keymaster_config_path is set, but there \u0027"},{"line_number":173,"context_line":"                                 \u0027are other config options specified: %s\u0027 %"},{"line_number":174,"context_line":"                                 \", \".join(bad_opts))"}],"source_content_type":"text/x-python","patch_set":3,"id":"5f7c97a3_1463b6ac","line":171,"updated":"2018-07-09 19:14:25.000000000","message":"Dedent, yeah?","commit_id":"847e70d8f794b094029aebc98d69076b1537926a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"bc8ada05ea452ad5909594a2d04356e5acf3f467","unresolved":false,"context_lines":[{"line_number":245,"context_line":"        :param secret_id: the id of the root secret from which the key should"},{"line_number":246,"context_line":"            be derived."},{"line_number":247,"context_line":"        :return: an encryption key."},{"line_number":248,"context_line":"        :raises KeyError: of the given secret_id is not recognised."},{"line_number":249,"context_line":"        \"\"\""},{"line_number":250,"context_line":"        try:"},{"line_number":251,"context_line":"            return hmac.new(self._root_secrets[secret_id], path,"}],"source_content_type":"text/x-python","patch_set":3,"id":"5f7c97a3_1c9459e7","line":248,"range":{"start_line":248,"start_character":16,"end_line":248,"end_character":24},"updated":"2018-07-09 19:14:25.000000000","message":"I wonder if this should get its own exception class...","commit_id":"847e70d8f794b094029aebc98d69076b1537926a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"fd03fa3a4c71ac16d9019db0a20d5e6fbd941e6b","unresolved":false,"context_lines":[{"line_number":144,"context_line":"        self._root_secrets \u003d self._get_root_secret(conf)"},{"line_number":145,"context_line":"        if not isinstance(self._root_secrets, dict):"},{"line_number":146,"context_line":"            self._root_secrets \u003d {None: self._root_secrets}"},{"line_number":147,"context_line":"        self.active_secret_id \u003d conf.get(\u0027active_root_secret_id\u0027) or None"},{"line_number":148,"context_line":"        if self.active_secret_id not in self._root_secrets:"},{"line_number":149,"context_line":"            raise ValueError(\u0027No secret loaded for active_root_secret_id %s\u0027 %"},{"line_number":150,"context_line":"                             self.active_secret_id)"}],"source_content_type":"text/x-python","patch_set":5,"id":"5f7c97a3_3db70a25","line":147,"range":{"start_line":147,"start_character":32,"end_line":147,"end_character":65},"updated":"2018-07-27 17:32:40.000000000","message":"Hmm... so this id *must* be in the proxy-server conf, and can\u0027t be loaded from the keymaster config?","commit_id":"d405c5a42f9fd46afd65f833b799e0a35976e0be"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"fd03fa3a4c71ac16d9019db0a20d5e6fbd941e6b","unresolved":false,"context_lines":[{"line_number":250,"context_line":"        \"\"\""},{"line_number":251,"context_line":"        try:"},{"line_number":252,"context_line":"            key \u003d self._root_secrets[secret_id]"},{"line_number":253,"context_line":"        except KeyError:"},{"line_number":254,"context_line":"            self.logger.warning(\u0027Unrecognised secret id: %s\u0027 % secret_id)"},{"line_number":255,"context_line":"            raise UnknownKeyIdException(secret_id)"},{"line_number":256,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":5,"id":"5f7c97a3_7dcb4272","line":253,"updated":"2018-07-27 17:32:40.000000000","message":"This could be an interesting opportunity for a KMIP or KMS keymaster to try to fetch an unknown key inline with a client request... or should the secret_id *always* be something operator-defined? (In which case, if we find an unknown secret_id, the external service probably wouldn\u0027t know what to do with it.)","commit_id":"d405c5a42f9fd46afd65f833b799e0a35976e0be"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"9e764e10778013a7c70a9973595591f51a06aba2","unresolved":false,"context_lines":[{"line_number":156,"context_line":"        self.active_secret_id \u003d conf.get(\u0027active_root_secret_id\u0027) or None"},{"line_number":157,"context_line":"        if self.active_secret_id not in self._root_secrets:"},{"line_number":158,"context_line":"            raise ValueError(\u0027No secret loaded for active_root_secret_id %s\u0027 %"},{"line_number":159,"context_line":"                             self.active_secret_id)"},{"line_number":160,"context_line":""},{"line_number":161,"context_line":"    @property"},{"line_number":162,"context_line":"    def root_secret(self):"}],"source_content_type":"text/x-python","patch_set":7,"id":"3f79a3b5_93e83ab3","line":159,"updated":"2018-08-16 16:00:56.000000000","message":"yes, perfect, don\u0027t even start","commit_id":"9589e75d9d5e2bac0b1274095989ec1830c2a379"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"77ea9bd8e122da0c90b776e62933371d2bfaf947","unresolved":false,"context_lines":[{"line_number":201,"context_line":"            if suffix and (suffix[0] !\u003d \u0027_\u0027 or len(suffix) \u003c 2):"},{"line_number":202,"context_line":"                raise ValueError(\u0027Malformed root secret option name %s\u0027 % k)"},{"line_number":203,"context_line":"            result.append((k, suffix[1:] or None, v))"},{"line_number":204,"context_line":"        return sorted(result)"},{"line_number":205,"context_line":""},{"line_number":206,"context_line":"    def _get_root_secret(self, conf):"},{"line_number":207,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":7,"id":"5f7c97a3_94fa8b0e","line":204,"updated":"2018-07-31 04:30:47.000000000","message":"This is probably only a NIT.\n\nI don\u0027t understand why this needs to be sorted? if it wasn\u0027t sorted we could simply use a generator to remove the result list _and_ only store the items inside conf.\n\nWith only a small number of root keys it probably doesn\u0027t matter, but who knows how big this will grow oneday. Also it simplifies the code a little. Something like: http://paste.openstack.org/show/726901/","commit_id":"9589e75d9d5e2bac0b1274095989ec1830c2a379"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"2ed5c8af54cbc44581c8ab652991b7f1bcef8f3a","unresolved":false,"context_lines":[{"line_number":201,"context_line":"            if suffix and (suffix[0] !\u003d \u0027_\u0027 or len(suffix) \u003c 2):"},{"line_number":202,"context_line":"                raise ValueError(\u0027Malformed root secret option name %s\u0027 % k)"},{"line_number":203,"context_line":"            result.append((k, suffix[1:] or None, v))"},{"line_number":204,"context_line":"        return sorted(result)"},{"line_number":205,"context_line":""},{"line_number":206,"context_line":"    def _get_root_secret(self, conf):"},{"line_number":207,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":7,"id":"5f7c97a3_b0945836","line":204,"in_reply_to":"5f7c97a3_94fa8b0e","updated":"2018-07-31 23:51:34.000000000","message":"Mainly I did it for testability -- though I suppose I could do sort(calls[1:]) over around https://review.openstack.org/#/c/586455/3/test/unit/common/middleware/crypto/test_kmip_keymaster.py@115 or something.\n\n\u003e who knows how big this will grow oneday\n\nMy expectation is that adding a new key would happen something like once a year, at most once a quarter. So I think we\u0027d be looking at something like tens, not hundreds -- and by the time that we have the problem of too many keys, I\u0027d really hope we\u0027d have a plan for how to re-encrypt all the metadata with the current active key.","commit_id":"9589e75d9d5e2bac0b1274095989ec1830c2a379"}],"test/unit/common/middleware/crypto/crypto_helpers.py":[{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"77ea9bd8e122da0c90b776e62933371d2bfaf947","unresolved":false,"context_lines":[{"line_number":27,"context_line":"                           \u0027container\u0027: \u0027This is a container key 12345678\u0027,"},{"line_number":28,"context_line":"                           \u0027object\u0027: \u0027This is an object key 1234567890\u0027}}"},{"line_number":29,"context_line":"    key_id \u003d key_id or {}"},{"line_number":30,"context_line":"    secret_id \u003d key_id.get(\u0027secret_id\u0027) or None"},{"line_number":31,"context_line":"    try:"},{"line_number":32,"context_line":"        keys \u003d dict(id_to_keys[secret_id])"},{"line_number":33,"context_line":"    except KeyError:"}],"source_content_type":"text/x-python","patch_set":7,"id":"5f7c97a3_343937ce","line":30,"range":{"start_line":30,"start_character":23,"end_line":30,"end_character":39},"updated":"2018-07-31 04:30:47.000000000","message":"Wont this return None by default?","commit_id":"9589e75d9d5e2bac0b1274095989ec1830c2a379"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"2ed5c8af54cbc44581c8ab652991b7f1bcef8f3a","unresolved":false,"context_lines":[{"line_number":27,"context_line":"                           \u0027container\u0027: \u0027This is a container key 12345678\u0027,"},{"line_number":28,"context_line":"                           \u0027object\u0027: \u0027This is an object key 1234567890\u0027}}"},{"line_number":29,"context_line":"    key_id \u003d key_id or {}"},{"line_number":30,"context_line":"    secret_id \u003d key_id.get(\u0027secret_id\u0027) or None"},{"line_number":31,"context_line":"    try:"},{"line_number":32,"context_line":"        keys \u003d dict(id_to_keys[secret_id])"},{"line_number":33,"context_line":"    except KeyError:"}],"source_content_type":"text/x-python","patch_set":7,"id":"5f7c97a3_50c86454","line":30,"range":{"start_line":30,"start_character":23,"end_line":30,"end_character":39},"in_reply_to":"5f7c97a3_343937ce","updated":"2018-07-31 23:51:34.000000000","message":"I think there may have been a concern about inputs like\n\n {\u0027secret_id\u0027: \u0027\u0027}\n\nSee https://review.openstack.org/#/c/577874/7/test/unit/common/middleware/crypto/test_decrypter.py@135 -- not sure it should come up in practice, though?","commit_id":"9589e75d9d5e2bac0b1274095989ec1830c2a379"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"9e764e10778013a7c70a9973595591f51a06aba2","unresolved":false,"context_lines":[{"line_number":31,"context_line":"    try:"},{"line_number":32,"context_line":"        keys \u003d dict(id_to_keys[secret_id])"},{"line_number":33,"context_line":"    except KeyError:"},{"line_number":34,"context_line":"        raise UnknownKeyIdException(secret_id)"},{"line_number":35,"context_line":"    keys[\u0027id\u0027] \u003d {\u0027v\u0027: \u0027fake\u0027, \u0027path\u0027: \u0027/a/c/fake\u0027}"},{"line_number":36,"context_line":"    if secret_id:"},{"line_number":37,"context_line":"        keys[\u0027id\u0027][\u0027secret_id\u0027] \u003d secret_id"}],"source_content_type":"text/x-python","patch_set":7,"id":"3f79a3b5_93159a4b","line":34,"updated":"2018-08-16 16:00:56.000000000","message":"This should be called UnknownSecretIdError","commit_id":"9589e75d9d5e2bac0b1274095989ec1830c2a379"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"5e0396ca00c1e632f8308f3bcd5ff4d21115f4c2","unresolved":false,"context_lines":[{"line_number":31,"context_line":"    try:"},{"line_number":32,"context_line":"        keys \u003d dict(id_to_keys[secret_id])"},{"line_number":33,"context_line":"    except KeyError:"},{"line_number":34,"context_line":"        raise UnknownKeyIdException(secret_id)"},{"line_number":35,"context_line":"    keys[\u0027id\u0027] \u003d {\u0027v\u0027: \u0027fake\u0027, \u0027path\u0027: \u0027/a/c/fake\u0027}"},{"line_number":36,"context_line":"    if secret_id:"},{"line_number":37,"context_line":"        keys[\u0027id\u0027][\u0027secret_id\u0027] \u003d secret_id"}],"source_content_type":"text/x-python","patch_set":7,"id":"3f79a3b5_81a18498","line":34,"in_reply_to":"3f79a3b5_93159a4b","updated":"2018-08-17 18:01:31.000000000","message":"Done","commit_id":"9589e75d9d5e2bac0b1274095989ec1830c2a379"}]}
