From e38003426f6d051ea74ffa7131e548897a445e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?McCoy=20Pati=C3=B1o?= Date: Thu, 5 Nov 2020 18:06:24 -0800 Subject: [PATCH 1/2] Add parse_key_vault_secret_id method/tests --- .../azure-keyvault-secrets/CHANGELOG.md | 4 + .../azure/keyvault/secrets/__init__.py | 12 +- .../azure/keyvault/secrets/_models.py | 4 +- .../azure/keyvault/secrets/_parse_id.py | 28 ++++ .../keyvault/secrets/_shared/__init__.py | 42 +++-- ..._id.test_parse_secret_id_with_version.yaml | 146 ++++++++++++++++++ .../tests/test_parse_id.py | 62 ++++++++ 7 files changed, 285 insertions(+), 13 deletions(-) create mode 100644 sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_parse_id.py create mode 100644 sdk/keyvault/azure-keyvault-secrets/tests/recordings/test_parse_id.test_parse_secret_id_with_version.yaml create mode 100644 sdk/keyvault/azure-keyvault-secrets/tests/test_parse_id.py diff --git a/sdk/keyvault/azure-keyvault-secrets/CHANGELOG.md b/sdk/keyvault/azure-keyvault-secrets/CHANGELOG.md index 7d60250d6f86..363e3be72235 100644 --- a/sdk/keyvault/azure-keyvault-secrets/CHANGELOG.md +++ b/sdk/keyvault/azure-keyvault-secrets/CHANGELOG.md @@ -4,6 +4,10 @@ ### Fixed - Correct typing for async paging methods +### Added +- Added method `parse_key_vault_secret_id` that parses out a full ID returned by Key Vault, so users can easily +access the secret's `name`, `vault_url`, and `version`. + ## 4.2.0 (2020-08-11) ### Fixed - Values of `x-ms-keyvault-region` and `x-ms-keyvault-service-version` headers diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/__init__.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/__init__.py index 3f6e1c5ff4fc..e2885143bebd 100644 --- a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/__init__.py +++ b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/__init__.py @@ -3,10 +3,20 @@ # Licensed under the MIT License. # ------------------------------------ from ._models import DeletedSecret, KeyVaultSecret, SecretProperties +from ._parse_id import parse_key_vault_secret_id +from ._shared import KeyVaultResourceId from ._shared.client_base import ApiVersion from ._client import SecretClient -__all__ = ["ApiVersion", "SecretClient", "KeyVaultSecret", "SecretProperties", "DeletedSecret"] +__all__ = [ + "ApiVersion", + "SecretClient", + "KeyVaultSecret", + "SecretProperties", + "DeletedSecret", + "parse_key_vault_secret_id", + "KeyVaultResourceId" +] from ._version import VERSION __version__ = VERSION diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_models.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_models.py index 0f022470b6e6..fdddcaa8cbde 100644 --- a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_models.py +++ b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_models.py @@ -2,7 +2,7 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------ -from ._shared import parse_vault_id +from ._shared import parse_key_vault_id try: from typing import TYPE_CHECKING @@ -23,7 +23,7 @@ def __init__(self, attributes, vault_id, **kwargs): # type: (_models.SecretAttributes, str, **Any) -> None self._attributes = attributes self._id = vault_id - self._vault_id = parse_vault_id(vault_id) + self._vault_id = parse_key_vault_id(vault_id) self._content_type = kwargs.get("content_type", None) self._key_id = kwargs.get("key_id", None) self._managed = kwargs.get("managed", None) diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_parse_id.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_parse_id.py new file mode 100644 index 000000000000..8e549b31054f --- /dev/null +++ b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_parse_id.py @@ -0,0 +1,28 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +from ._shared import parse_key_vault_id, KeyVaultResourceId + + +def parse_key_vault_secret_id(source_id): + # type: (str) -> KeyVaultResourceId + """Parses a secret's full ID into a class with parsed contents as attributes. + :param str source_id: the full original identifier of a secret + :returns: Returns a parsed secret ID as a :class:`KeyVaultResourceId` + :rtype: ~azure.keyvault.secrets.KeyVaultResourceId + :raises: ValueError + Example: + .. literalinclude:: ../tests/test_parse_id.py + :start-after: [START parse_key_vault_secret_id] + :end-before: [END parse_key_vault_secret_id] + :language: python + :caption: Parse a secret's ID + :dedent: 8 + """ + parsed_id = parse_key_vault_id(source_id) + + return KeyVaultResourceId( + name=parsed_id.name, source_id=parsed_id.source_id, vault_url=parsed_id.vault_url, version=parsed_id.version + ) diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_shared/__init__.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_shared/__init__.py index e13f15a61c71..02e858d1a488 100644 --- a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_shared/__init__.py +++ b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_shared/__init__.py @@ -2,19 +2,22 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------ -from collections import namedtuple - try: import urllib.parse as parse except ImportError: # pylint:disable=import-error import urlparse as parse # type: ignore +from typing import TYPE_CHECKING from .challenge_auth_policy import ChallengeAuthPolicy, ChallengeAuthPolicyBase from .client_base import KeyVaultClientBase from .http_challenge import HttpChallenge from . import http_challenge_cache as HttpChallengeCache +if TYPE_CHECKING: + # pylint: disable=unused-import + from typing import Optional + __all__ = [ "ChallengeAuthPolicy", @@ -24,25 +27,44 @@ "KeyVaultClientBase", ] -_VaultId = namedtuple("VaultId", ["vault_url", "collection", "name", "version"]) +class KeyVaultResourceId(): + """Represents a Key Vault identifier and its parsed contents. + :param str source_id: The complete identifier received from Key Vault + :param str vault_url: The vault URL + :param str name: The name extracted from the ID + :param str version: The version extracted from the ID + """ + + def __init__( + self, + source_id, # type: str + vault_url, # type: str + name, # type: str + version=None # type: Optional[str] + ): + self.source_id = source_id + self.vault_url = vault_url + self.name = name + self.version = version -def parse_vault_id(url): +def parse_key_vault_id(source_id): + # type: (str) -> KeyVaultResourceId try: - parsed_uri = parse.urlparse(url) + parsed_uri = parse.urlparse(source_id) except Exception: # pylint: disable=broad-except - raise ValueError("'{}' is not not a valid url".format(url)) + raise ValueError("'{}' is not not a valid url".format(source_id)) if not (parsed_uri.scheme and parsed_uri.hostname): - raise ValueError("'{}' is not not a valid url".format(url)) + raise ValueError("'{}' is not not a valid url".format(source_id)) path = list(filter(None, parsed_uri.path.split("/"))) if len(path) < 2 or len(path) > 3: - raise ValueError("'{}' is not not a valid vault url".format(url)) + raise ValueError("'{}' is not not a valid vault url".format(source_id)) - return _VaultId( + return KeyVaultResourceId( + source_id=source_id, vault_url="{}://{}".format(parsed_uri.scheme, parsed_uri.hostname), - collection=path[0], name=path[1], version=path[2] if len(path) == 3 else None, ) diff --git a/sdk/keyvault/azure-keyvault-secrets/tests/recordings/test_parse_id.test_parse_secret_id_with_version.yaml b/sdk/keyvault/azure-keyvault-secrets/tests/recordings/test_parse_id.test_parse_secret_id_with_version.yaml new file mode 100644 index 000000000000..2cb4527f842c --- /dev/null +++ b/sdk/keyvault/azure-keyvault-secrets/tests/recordings/test_parse_id.test_parse_secret_id_with_version.yaml @@ -0,0 +1,146 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + Content-Type: + - application/json + User-Agent: + - azsdk-python-keyvault-secrets/4.2.1 Python/3.5.3 (Windows-10-10.0.19041-SP0) + method: PUT + uri: https://vaultname.vault.azure.net/secrets/secretce671360?api-version=7.1 + response: + body: + string: '{"error":{"code":"Unauthorized","message":"Request is missing a Bearer + or PoP token."}}' + headers: + cache-control: + - no-cache + content-length: + - '87' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 06 Nov 2020 01:59:17 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000;includeSubDomains + www-authenticate: + - Bearer authorization="https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47", + resource="https://vault.azure.net" + x-content-type-options: + - nosniff + x-ms-keyvault-network-info: + - conn_type=Ipv4;addr=162.211.216.102;act_addr_fam=InterNetwork; + x-ms-keyvault-region: + - westus + x-ms-keyvault-service-version: + - 1.2.58.0 + x-powered-by: + - ASP.NET + status: + code: 401 + message: Unauthorized +- request: + body: '{"value": "secret_value"}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '25' + Content-Type: + - application/json + User-Agent: + - azsdk-python-keyvault-secrets/4.2.1 Python/3.5.3 (Windows-10-10.0.19041-SP0) + method: PUT + uri: https://vaultname.vault.azure.net/secrets/secretce671360?api-version=7.1 + response: + body: + string: '{"value":"secret_value","id":"https://vaultname.vault.azure.net/secrets/secretce671360/82b4c68fbf654bff953bd26a4a5f5f1e","attributes":{"enabled":true,"created":1604627958,"updated":1604627958,"recoveryLevel":"Recoverable+Purgeable","recoverableDays":90}}' + headers: + cache-control: + - no-cache + content-length: + - '269' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 06 Nov 2020 01:59:17 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000;includeSubDomains + x-content-type-options: + - nosniff + x-ms-keyvault-network-info: + - conn_type=Ipv4;addr=162.211.216.102;act_addr_fam=InterNetwork; + x-ms-keyvault-region: + - westus + x-ms-keyvault-service-version: + - 1.2.58.0 + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-keyvault-secrets/4.2.1 Python/3.5.3 (Windows-10-10.0.19041-SP0) + method: GET + uri: https://vaultname.vault.azure.net/secrets/secretce671360/?api-version=7.1 + response: + body: + string: '{"value":"secret_value","id":"https://vaultname.vault.azure.net/secrets/secretce671360/82b4c68fbf654bff953bd26a4a5f5f1e","attributes":{"enabled":true,"created":1604627958,"updated":1604627958,"recoveryLevel":"Recoverable+Purgeable","recoverableDays":90}}' + headers: + cache-control: + - no-cache + content-length: + - '269' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 06 Nov 2020 01:59:17 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000;includeSubDomains + x-content-type-options: + - nosniff + x-ms-keyvault-network-info: + - conn_type=Ipv4;addr=162.211.216.102;act_addr_fam=InterNetwork; + x-ms-keyvault-region: + - westus + x-ms-keyvault-service-version: + - 1.2.58.0 + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/keyvault/azure-keyvault-secrets/tests/test_parse_id.py b/sdk/keyvault/azure-keyvault-secrets/tests/test_parse_id.py new file mode 100644 index 000000000000..fb88f6d11600 --- /dev/null +++ b/sdk/keyvault/azure-keyvault-secrets/tests/test_parse_id.py @@ -0,0 +1,62 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------- +import functools +from azure.keyvault.secrets import SecretClient, parse_key_vault_secret_id +from devtools_testutils import ResourceGroupPreparer, KeyVaultPreparer + +from _shared.preparer import KeyVaultClientPreparer as _KeyVaultClientPreparer +from _shared.test_case import KeyVaultTestCase + +# pre-apply the client_cls positional argument so it needn't be explicitly passed below +KeyVaultClientPreparer = functools.partial(_KeyVaultClientPreparer, SecretClient) + + +class TestParseId(KeyVaultTestCase): + @ResourceGroupPreparer(random_name_enabled=True) + @KeyVaultPreparer() + @KeyVaultClientPreparer() + def test_parse_secret_id_with_version(self, client): + secret_name = self.get_resource_name("secret") + secret_value = "secret_value" + # create secret + created_secret = client.set_secret(secret_name, secret_value) + + # [START parse_key_vault_secret_id] + secret = client.get_secret(secret_name) + parsed_secret_id = parse_key_vault_secret_id(secret.id) + + print(parsed_secret_id.name) + print(parsed_secret_id.vault_url) + print(parsed_secret_id.version) + print(parsed_secret_id.source_id) + # [END parse_key_vault_secret_id] + self.assertEqual(parsed_secret_id.name, secret_name) + self.assertEqual(parsed_secret_id.vault_url, client.vault_url) + self.assertEqual(parsed_secret_id.version, secret.properties.version) + self.assertEqual(parsed_secret_id.source_id, secret.id) + + def test_parse_secret_id_with_pending_version(self): + source_id = "https://keyvault-name.vault.azure.net/secrets/secret-name/pending" + parsed_secret_id = parse_key_vault_secret_id(source_id) + + self.assertEqual(parsed_secret_id.name, "secret-name") + self.assertEqual(parsed_secret_id.vault_url, "https://keyvault-name.vault.azure.net") + self.assertEqual(parsed_secret_id.version, "pending") + self.assertEqual( + parsed_secret_id.source_id, + "https://keyvault-name.vault.azure.net/secrets/secret-name/pending", + ) + + def test_parse_deleted_secret_id(self): + source_id = "https://keyvault-name.vault.azure.net/deletedsecrets/deleted-secret" + parsed_secret_id = parse_key_vault_secret_id(source_id) + + self.assertEqual(parsed_secret_id.name, "deleted-secret") + self.assertEqual(parsed_secret_id.vault_url, "https://keyvault-name.vault.azure.net") + self.assertIsNone(parsed_secret_id.version) + self.assertEqual( + parsed_secret_id.source_id, + "https://keyvault-name.vault.azure.net/deletedsecrets/deleted-secret", + ) From 607bd498f96d204e43f5f05592c351075d29d0a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?McCoy=20Pati=C3=B1o?= Date: Fri, 6 Nov 2020 15:52:47 -0800 Subject: [PATCH 2/2] Apply feedback from keys library --- .../azure/keyvault/secrets/_parse_id.py | 1 + .../keyvault/secrets/_shared/__init__.py | 11 ++-- ..._id.test_parse_secret_id_with_version.yaml | 10 ++-- .../tests/test_parse_id.py | 60 ++++++++----------- 4 files changed, 38 insertions(+), 44 deletions(-) diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_parse_id.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_parse_id.py index 8e549b31054f..d7a3374ce118 100644 --- a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_parse_id.py +++ b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_parse_id.py @@ -9,6 +9,7 @@ def parse_key_vault_secret_id(source_id): # type: (str) -> KeyVaultResourceId """Parses a secret's full ID into a class with parsed contents as attributes. + :param str source_id: the full original identifier of a secret :returns: Returns a parsed secret ID as a :class:`KeyVaultResourceId` :rtype: ~azure.keyvault.secrets.KeyVaultResourceId diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_shared/__init__.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_shared/__init__.py index 02e858d1a488..578deccfb147 100644 --- a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_shared/__init__.py +++ b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_shared/__init__.py @@ -29,11 +29,12 @@ class KeyVaultResourceId(): """Represents a Key Vault identifier and its parsed contents. - :param str source_id: The complete identifier received from Key Vault - :param str vault_url: The vault URL - :param str name: The name extracted from the ID - :param str version: The version extracted from the ID - """ + + :param str source_id: The complete identifier received from Key Vault + :param str vault_url: The vault URL + :param str name: The name extracted from the ID + :param str version: The version extracted from the ID + """ def __init__( self, diff --git a/sdk/keyvault/azure-keyvault-secrets/tests/recordings/test_parse_id.test_parse_secret_id_with_version.yaml b/sdk/keyvault/azure-keyvault-secrets/tests/recordings/test_parse_id.test_parse_secret_id_with_version.yaml index 2cb4527f842c..65ac7c1dede3 100644 --- a/sdk/keyvault/azure-keyvault-secrets/tests/recordings/test_parse_id.test_parse_secret_id_with_version.yaml +++ b/sdk/keyvault/azure-keyvault-secrets/tests/recordings/test_parse_id.test_parse_secret_id_with_version.yaml @@ -28,7 +28,7 @@ interactions: content-type: - application/json; charset=utf-8 date: - - Fri, 06 Nov 2020 01:59:17 GMT + - Fri, 06 Nov 2020 23:51:37 GMT expires: - '-1' pragma: @@ -70,7 +70,7 @@ interactions: uri: https://vaultname.vault.azure.net/secrets/secretce671360?api-version=7.1 response: body: - string: '{"value":"secret_value","id":"https://vaultname.vault.azure.net/secrets/secretce671360/82b4c68fbf654bff953bd26a4a5f5f1e","attributes":{"enabled":true,"created":1604627958,"updated":1604627958,"recoveryLevel":"Recoverable+Purgeable","recoverableDays":90}}' + string: '{"value":"secret_value","id":"https://vaultname.vault.azure.net/secrets/secretce671360/0fb32b11fdbf47eb9973e04a064a5b3f","attributes":{"enabled":true,"created":1604706698,"updated":1604706698,"recoveryLevel":"Recoverable+Purgeable","recoverableDays":90}}' headers: cache-control: - no-cache @@ -79,7 +79,7 @@ interactions: content-type: - application/json; charset=utf-8 date: - - Fri, 06 Nov 2020 01:59:17 GMT + - Fri, 06 Nov 2020 23:51:38 GMT expires: - '-1' pragma: @@ -114,7 +114,7 @@ interactions: uri: https://vaultname.vault.azure.net/secrets/secretce671360/?api-version=7.1 response: body: - string: '{"value":"secret_value","id":"https://vaultname.vault.azure.net/secrets/secretce671360/82b4c68fbf654bff953bd26a4a5f5f1e","attributes":{"enabled":true,"created":1604627958,"updated":1604627958,"recoveryLevel":"Recoverable+Purgeable","recoverableDays":90}}' + string: '{"value":"secret_value","id":"https://vaultname.vault.azure.net/secrets/secretce671360/0fb32b11fdbf47eb9973e04a064a5b3f","attributes":{"enabled":true,"created":1604706698,"updated":1604706698,"recoveryLevel":"Recoverable+Purgeable","recoverableDays":90}}' headers: cache-control: - no-cache @@ -123,7 +123,7 @@ interactions: content-type: - application/json; charset=utf-8 date: - - Fri, 06 Nov 2020 01:59:17 GMT + - Fri, 06 Nov 2020 23:51:38 GMT expires: - '-1' pragma: diff --git a/sdk/keyvault/azure-keyvault-secrets/tests/test_parse_id.py b/sdk/keyvault/azure-keyvault-secrets/tests/test_parse_id.py index fb88f6d11600..efd2b239692a 100644 --- a/sdk/keyvault/azure-keyvault-secrets/tests/test_parse_id.py +++ b/sdk/keyvault/azure-keyvault-secrets/tests/test_parse_id.py @@ -2,21 +2,17 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------- -import functools from azure.keyvault.secrets import SecretClient, parse_key_vault_secret_id from devtools_testutils import ResourceGroupPreparer, KeyVaultPreparer -from _shared.preparer import KeyVaultClientPreparer as _KeyVaultClientPreparer +from _shared.preparer import KeyVaultClientPreparer from _shared.test_case import KeyVaultTestCase -# pre-apply the client_cls positional argument so it needn't be explicitly passed below -KeyVaultClientPreparer = functools.partial(_KeyVaultClientPreparer, SecretClient) - class TestParseId(KeyVaultTestCase): @ResourceGroupPreparer(random_name_enabled=True) @KeyVaultPreparer() - @KeyVaultClientPreparer() + @KeyVaultClientPreparer(SecretClient) def test_parse_secret_id_with_version(self, client): secret_name = self.get_resource_name("secret") secret_value = "secret_value" @@ -32,31 +28,27 @@ def test_parse_secret_id_with_version(self, client): print(parsed_secret_id.version) print(parsed_secret_id.source_id) # [END parse_key_vault_secret_id] - self.assertEqual(parsed_secret_id.name, secret_name) - self.assertEqual(parsed_secret_id.vault_url, client.vault_url) - self.assertEqual(parsed_secret_id.version, secret.properties.version) - self.assertEqual(parsed_secret_id.source_id, secret.id) - - def test_parse_secret_id_with_pending_version(self): - source_id = "https://keyvault-name.vault.azure.net/secrets/secret-name/pending" - parsed_secret_id = parse_key_vault_secret_id(source_id) - - self.assertEqual(parsed_secret_id.name, "secret-name") - self.assertEqual(parsed_secret_id.vault_url, "https://keyvault-name.vault.azure.net") - self.assertEqual(parsed_secret_id.version, "pending") - self.assertEqual( - parsed_secret_id.source_id, - "https://keyvault-name.vault.azure.net/secrets/secret-name/pending", - ) - - def test_parse_deleted_secret_id(self): - source_id = "https://keyvault-name.vault.azure.net/deletedsecrets/deleted-secret" - parsed_secret_id = parse_key_vault_secret_id(source_id) - - self.assertEqual(parsed_secret_id.name, "deleted-secret") - self.assertEqual(parsed_secret_id.vault_url, "https://keyvault-name.vault.azure.net") - self.assertIsNone(parsed_secret_id.version) - self.assertEqual( - parsed_secret_id.source_id, - "https://keyvault-name.vault.azure.net/deletedsecrets/deleted-secret", - ) + assert parsed_secret_id.name == secret_name + assert parsed_secret_id.vault_url == client.vault_url + assert parsed_secret_id.version == secret.properties.version + assert parsed_secret_id.source_id == secret.id + + +def test_parse_secret_id_with_pending_version(): + source_id = "https://keyvault-name.vault.azure.net/secrets/secret-name/pending" + parsed_secret_id = parse_key_vault_secret_id(source_id) + + assert parsed_secret_id.name == "secret-name" + assert parsed_secret_id.vault_url == "https://keyvault-name.vault.azure.net" + assert parsed_secret_id.version == "pending" + assert parsed_secret_id.source_id == "https://keyvault-name.vault.azure.net/secrets/secret-name/pending" + + +def test_parse_deleted_secret_id(): + source_id = "https://keyvault-name.vault.azure.net/deletedsecrets/deleted-secret" + parsed_secret_id = parse_key_vault_secret_id(source_id) + + assert parsed_secret_id.name == "deleted-secret" + assert parsed_secret_id.vault_url == "https://keyvault-name.vault.azure.net" + assert parsed_secret_id.version is None + assert parsed_secret_id.source_id == "https://keyvault-name.vault.azure.net/deletedsecrets/deleted-secret"