Skip to content

Commit 2adfb59

Browse files
cojencotseaver
andauthored
feat: add getters and setters for encryption_key and kms_key_name (#409)
* fix: add getters and setters for attributes encryption_key and kms_key_name * fix docstring formatting * revise docstring Co-authored-by: Tres Seaver <[email protected]>
1 parent f090548 commit 2adfb59

File tree

2 files changed

+77
-7
lines changed

2 files changed

+77
-7
lines changed

google/cloud/storage/blob.py

+41-7
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,31 @@ def chunk_size(self, value):
254254
)
255255
self._chunk_size = value
256256

257+
@property
258+
def encryption_key(self):
259+
"""Retrieve the customer-supplied encryption key for the object.
260+
261+
:rtype: bytes or ``NoneType``
262+
:returns:
263+
The encryption key or ``None`` if no customer-supplied encryption key was used,
264+
or the blob's resource has not been loaded from the server.
265+
"""
266+
return self._encryption_key
267+
268+
@encryption_key.setter
269+
def encryption_key(self, value):
270+
"""Set the blob's encryption key.
271+
272+
See https://cloud.google.com/storage/docs/encryption#customer-supplied
273+
274+
To perform a key rotation for an encrypted blob, use :meth:`rewrite`.
275+
See https://cloud.google.com/storage/docs/encryption/using-customer-supplied-keys?hl=ca#rotating
276+
277+
:type value: bytes
278+
:param value: 32 byte encryption key for customer-supplied encryption.
279+
"""
280+
self._encryption_key = value
281+
257282
@staticmethod
258283
def path_helper(bucket_path, blob_name):
259284
"""Relative URL path for a blob.
@@ -347,25 +372,25 @@ def public_url(self):
347372
def from_string(cls, uri, client=None):
348373
"""Get a constructor for blob object by URI.
349374
350-
:type uri: str
351-
:param uri: The blob uri pass to get blob object.
375+
:type uri: str
376+
:param uri: The blob uri pass to get blob object.
352377
353378
:type client: :class:`~google.cloud.storage.client.Client`
354379
:param client:
355380
(Optional) The client to use. If not passed, falls back to the
356381
``client`` stored on the blob's bucket.
357382
358-
:rtype: :class:`google.cloud.storage.blob.Blob`
359-
:returns: The blob object created.
383+
:rtype: :class:`google.cloud.storage.blob.Blob`
384+
:returns: The blob object created.
360385
361-
Example:
362-
Get a constructor for blob object by URI..
386+
Example:
387+
Get a constructor for blob object by URI.
363388
364389
>>> from google.cloud import storage
365390
>>> from google.cloud.storage.blob import Blob
366391
>>> client = storage.Client()
367392
>>> blob = Blob.from_string("gs://bucket/object")
368-
"""
393+
"""
369394
from google.cloud.storage.bucket import Bucket
370395

371396
scheme, netloc, path, query, frag = urlsplit(uri)
@@ -3839,6 +3864,15 @@ def kms_key_name(self):
38393864
"""
38403865
return self._properties.get("kmsKeyName")
38413866

3867+
@kms_key_name.setter
3868+
def kms_key_name(self, value):
3869+
"""Set KMS encryption key for object.
3870+
3871+
:type value: str or ``NoneType``
3872+
:param value: new KMS key name (None to clear any existing key).
3873+
"""
3874+
self._patch_property("kmsKeyName", value)
3875+
38423876
storage_class = _scalar_property("storageClass")
38433877
"""Retrieve the storage class for the object.
38443878

tests/unit/test_blob.py

+36
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,42 @@ def test_acl_property(self):
262262
self.assertIsInstance(acl, ObjectACL)
263263
self.assertIs(acl, blob._acl)
264264

265+
def test_encryption_key_getter(self):
266+
BLOB_NAME = "blob-name"
267+
BUCKET = object()
268+
blob = self._make_one(BLOB_NAME, bucket=BUCKET)
269+
self.assertIsNone(blob.encryption_key)
270+
VALUE = object()
271+
blob._encryption_key = VALUE
272+
self.assertIs(blob.encryption_key, VALUE)
273+
274+
def test_encryption_key_setter(self):
275+
BLOB_NAME = "blob-name"
276+
BUCKET = object()
277+
blob = self._make_one(BLOB_NAME, bucket=BUCKET)
278+
self.assertIsNone(blob._encryption_key)
279+
key = b"12345678901234567890123456789012"
280+
blob.encryption_key = key
281+
self.assertEqual(blob._encryption_key, key)
282+
283+
def test_kms_key_name_getter(self):
284+
BLOB_NAME = "blob-name"
285+
BUCKET = object()
286+
blob = self._make_one(BLOB_NAME, bucket=BUCKET)
287+
self.assertIsNone(blob.kms_key_name)
288+
VALUE = object()
289+
blob._patch_property("kmsKeyName", VALUE)
290+
self.assertIs(blob.kms_key_name, VALUE)
291+
292+
def test_kms_key_name_setter(self):
293+
BLOB_NAME = "blob-name"
294+
BUCKET = object()
295+
blob = self._make_one(BLOB_NAME, bucket=BUCKET)
296+
self.assertIsNone(blob._properties.get("kmsKeyName"))
297+
kms_key_name = "cryptoKeys/test-key"
298+
blob.kms_key_name = kms_key_name
299+
self.assertEqual(blob._properties.get("kmsKeyName"), kms_key_name)
300+
265301
def test_path_bad_bucket(self):
266302
fake_bucket = object()
267303
name = u"blob-name"

0 commit comments

Comments
 (0)