proximl 0.5.11__py3-none-any.whl → 0.5.12__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- proximl/cli/project/credential.py +128 -0
- proximl/projects/credentials.py +71 -0
- {proximl-0.5.11.dist-info → proximl-0.5.12.dist-info}/METADATA +1 -1
- {proximl-0.5.11.dist-info → proximl-0.5.12.dist-info}/RECORD +11 -6
- tests/integration/projects/test_projects_credentials_integration.py +45 -0
- tests/unit/cli/projects/test_cli_project_credential_unit.py +26 -0
- tests/unit/projects/test_project_credentials_unit.py +100 -0
- {proximl-0.5.11.dist-info → proximl-0.5.12.dist-info}/LICENSE +0 -0
- {proximl-0.5.11.dist-info → proximl-0.5.12.dist-info}/WHEEL +0 -0
- {proximl-0.5.11.dist-info → proximl-0.5.12.dist-info}/entry_points.txt +0 -0
- {proximl-0.5.11.dist-info → proximl-0.5.12.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import os
|
|
3
|
+
import json
|
|
4
|
+
import base64
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from proximl.cli import pass_config
|
|
7
|
+
from proximl.cli.project import project
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@project.group()
|
|
11
|
+
@pass_config
|
|
12
|
+
def credential(config):
|
|
13
|
+
"""proxiML project credential commands."""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@credential.command()
|
|
18
|
+
@pass_config
|
|
19
|
+
def list(config):
|
|
20
|
+
"""List credentials."""
|
|
21
|
+
data = [
|
|
22
|
+
["TYPE", "KEY ID", "UPDATED AT"],
|
|
23
|
+
[
|
|
24
|
+
"-" * 80,
|
|
25
|
+
"-" * 80,
|
|
26
|
+
"-" * 80,
|
|
27
|
+
],
|
|
28
|
+
]
|
|
29
|
+
project = config.proximl.run(config.proximl.client.projects.get_current())
|
|
30
|
+
credentials = config.proximl.run(project.credentials.list())
|
|
31
|
+
|
|
32
|
+
for credential in credentials:
|
|
33
|
+
data.append(
|
|
34
|
+
[
|
|
35
|
+
credential.type,
|
|
36
|
+
credential.key_id,
|
|
37
|
+
credential.updated_at.isoformat(timespec="seconds"),
|
|
38
|
+
]
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
for row in data:
|
|
42
|
+
click.echo(
|
|
43
|
+
"{: >13.11} {: >37.35} {: >28.26}" "".format(*row),
|
|
44
|
+
file=config.stdout,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@credential.command()
|
|
49
|
+
@click.argument(
|
|
50
|
+
"type",
|
|
51
|
+
type=click.Choice(
|
|
52
|
+
[
|
|
53
|
+
"aws",
|
|
54
|
+
"azure",
|
|
55
|
+
"docker",
|
|
56
|
+
"gcp",
|
|
57
|
+
"huggingface",
|
|
58
|
+
"kaggle",
|
|
59
|
+
"ngc",
|
|
60
|
+
"wasabi",
|
|
61
|
+
],
|
|
62
|
+
case_sensitive=False,
|
|
63
|
+
),
|
|
64
|
+
)
|
|
65
|
+
@pass_config
|
|
66
|
+
def put(config, type):
|
|
67
|
+
"""
|
|
68
|
+
Set a credential.
|
|
69
|
+
|
|
70
|
+
A credential is uploaded.
|
|
71
|
+
"""
|
|
72
|
+
project = config.proximl.run(config.proximl.client.projects.get_current())
|
|
73
|
+
|
|
74
|
+
tenant = None
|
|
75
|
+
|
|
76
|
+
if type in ["aws", "wasabi"]:
|
|
77
|
+
credential_id = click.prompt(
|
|
78
|
+
"Enter the credential ID", type=str, hide_input=False
|
|
79
|
+
)
|
|
80
|
+
secret = click.prompt("Enter the secret credential", type=str, hide_input=True)
|
|
81
|
+
elif type == "azure":
|
|
82
|
+
credential_id = click.prompt(
|
|
83
|
+
"Enter the Application (client) ID", type=str, hide_input=False
|
|
84
|
+
)
|
|
85
|
+
tenant = click.prompt(
|
|
86
|
+
"Enter the Directory (tenant) ley", type=str, hide_input=False
|
|
87
|
+
)
|
|
88
|
+
secret = click.prompt("Enter the client secret", type=str, hide_input=True)
|
|
89
|
+
elif type in ["docker", "huggingface"]:
|
|
90
|
+
credential_id = click.prompt("Enter the username", type=str, hide_input=False)
|
|
91
|
+
secret = click.prompt("Enter the access token", type=str, hide_input=True)
|
|
92
|
+
elif type in ["gcp", "kaggle"]:
|
|
93
|
+
file_name = click.prompt(
|
|
94
|
+
"Enter the path of the credentials file",
|
|
95
|
+
type=click.Path(
|
|
96
|
+
exists=True, file_okay=True, dir_okay=False, resolve_path=True
|
|
97
|
+
),
|
|
98
|
+
hide_input=False,
|
|
99
|
+
)
|
|
100
|
+
credential_id = os.path.basename(file_name)
|
|
101
|
+
with open(file_name) as f:
|
|
102
|
+
secret = json.load(f)
|
|
103
|
+
secret = json.dumps(secret)
|
|
104
|
+
elif type == "ngc":
|
|
105
|
+
credential_id = "$oauthtoken"
|
|
106
|
+
secret = click.prompt("Enter the access token", type=str, hide_input=True)
|
|
107
|
+
else:
|
|
108
|
+
raise click.UsageError("Unsupported credential type")
|
|
109
|
+
|
|
110
|
+
return config.proximl.run(
|
|
111
|
+
project.credentials.put(
|
|
112
|
+
type=type, credential_id=credential_id, secret=secret, tenant=tenant
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@credential.command()
|
|
118
|
+
@click.argument("name", type=click.STRING)
|
|
119
|
+
@pass_config
|
|
120
|
+
def remove(config, name):
|
|
121
|
+
"""
|
|
122
|
+
Remove a credential.
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
"""
|
|
126
|
+
project = config.proximl.run(config.proximl.client.projects.get_current())
|
|
127
|
+
|
|
128
|
+
return config.proximl.run(project.credential.remove(name))
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from dateutil import parser, tz
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ProjectCredentials(object):
|
|
8
|
+
def __init__(self, proximl, project_id):
|
|
9
|
+
self.proximl = proximl
|
|
10
|
+
self.project_id = project_id
|
|
11
|
+
|
|
12
|
+
async def list(self, **kwargs):
|
|
13
|
+
resp = await self.proximl._query(
|
|
14
|
+
f"/project/{self.project_id}/credentials", "GET", kwargs
|
|
15
|
+
)
|
|
16
|
+
credentials = [ProjectCredential(self.proximl, **service) for service in resp]
|
|
17
|
+
return credentials
|
|
18
|
+
|
|
19
|
+
async def put(self, type, key_id, secret, tenant=None, **kwargs):
|
|
20
|
+
data = dict(key_id=key_id, secret=secret, tenant=tenant)
|
|
21
|
+
payload = {k: v for k, v in data.items() if v is not None}
|
|
22
|
+
logging.info(f"Creating Project Credential {type}")
|
|
23
|
+
resp = await self.proximl._query(
|
|
24
|
+
f"/project/{self.project_id}/credential/{type}", "PUT", None, payload
|
|
25
|
+
)
|
|
26
|
+
credential = ProjectCredential(self.proximl, **resp)
|
|
27
|
+
logging.info(f"Created Project Credential {type} in project {self.project_id}")
|
|
28
|
+
|
|
29
|
+
return credential
|
|
30
|
+
|
|
31
|
+
async def remove(self, type, **kwargs):
|
|
32
|
+
await self.proximl._query(
|
|
33
|
+
f"/project/{self.project_id}/credential/{type}", "DELETE", kwargs
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ProjectCredential:
|
|
38
|
+
def __init__(self, proximl, **kwargs):
|
|
39
|
+
self.proximl = proximl
|
|
40
|
+
self._entity = kwargs
|
|
41
|
+
self._type = self._entity.get("type")
|
|
42
|
+
self._project_uuid = self._entity.get("project_uuid")
|
|
43
|
+
self._key_id = self._entity.get("key_id")
|
|
44
|
+
self._updated_at = self._entity.get("updatedAt")
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def type(self) -> str:
|
|
48
|
+
return self._type
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def project_uuid(self) -> str:
|
|
52
|
+
return self._project_uuid
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def key_id(self) -> str:
|
|
56
|
+
return self._key_id
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def updated_at(self) -> datetime:
|
|
60
|
+
timestamp = parser.isoparse(self._updated_at)
|
|
61
|
+
timezone = tz.tzlocal()
|
|
62
|
+
return timestamp.astimezone(timezone)
|
|
63
|
+
|
|
64
|
+
def __str__(self):
|
|
65
|
+
return json.dumps({k: v for k, v in self._entity.items()})
|
|
66
|
+
|
|
67
|
+
def __repr__(self):
|
|
68
|
+
return f"ProjectCredential( proximl , **{self._entity.__repr__()})"
|
|
69
|
+
|
|
70
|
+
def __bool__(self):
|
|
71
|
+
return bool(self._type)
|
|
@@ -34,6 +34,7 @@ proximl/cli/cloudbender/service.py,sha256=6NuwlFULJLtOmMy9OFA8GkW4MLvNemAcd_KitQ
|
|
|
34
34
|
proximl/cli/job/__init__.py,sha256=s8mU2PvCWDcv4gGT3EmjHn8MIZlXBAoayoZKmnKpXnY,6545
|
|
35
35
|
proximl/cli/job/create.py,sha256=sGvbenY0yxvxHo-FZVbdw8FaZx5D4ekTCjD7P4YHG4g,34288
|
|
36
36
|
proximl/cli/project/__init__.py,sha256=nSU_qBNVPezVA_Uu54ha37PAfCmTsIclXptEvIwiRME,1904
|
|
37
|
+
proximl/cli/project/credential.py,sha256=5vPI6VBIo_YyvAzfUa9ARmz-LUnkdIVW0zbko9t0Q38,3443
|
|
37
38
|
proximl/cli/project/data_connector.py,sha256=CKF4snfrzDmeDXb4au8nV2W9jTweRMDZ89U2GAlBedQ,1411
|
|
38
39
|
proximl/cli/project/datastore.py,sha256=YusrUTKY_qIwEOBN2gXOUoKCUp2qbWTKzquKc0DcUsE,1336
|
|
39
40
|
proximl/cli/project/key.py,sha256=23ugcWOAxNJvC8VzG3FsEUWJ1_FZANnhq66cO04ZEVY,3203
|
|
@@ -50,6 +51,7 @@ proximl/cloudbender/providers.py,sha256=KLO4Pc8yeW8TpSDICgTw3NxN44_0s4HptVsR2hHc
|
|
|
50
51
|
proximl/cloudbender/regions.py,sha256=6doBdfMXIQI-uexzvwmNg2ATDzruatw-ixviZSMjonU,5157
|
|
51
52
|
proximl/cloudbender/services.py,sha256=km3KcIgaRRVb3iuZEIn6ONIekuyXhBgk_brAFJcMMl4,5126
|
|
52
53
|
proximl/projects/__init__.py,sha256=6NKCcHtQMeGB1IyU-djANphfnDX6MEkrXUM5Fyq9fWg,75
|
|
54
|
+
proximl/projects/credentials.py,sha256=hWz6EUEAgltkAQMDjQVsFlVvfWUbZfY3KoWpldnCrXY,2255
|
|
53
55
|
proximl/projects/data_connectors.py,sha256=559yJ-9qmva2JcNReuCyUQxdrSRIEROcGX5BDVr8ySs,1662
|
|
54
56
|
proximl/projects/datastores.py,sha256=zAmKX9CibeS7PSXVvExk0SVrEo9Zq83kz6CQw0GoHck,1560
|
|
55
57
|
proximl/projects/keys.py,sha256=yT5pgv1mGm50CaORf-HnsbDULad69G9I_QpVMN0zcuE,2157
|
|
@@ -69,6 +71,7 @@ tests/integration/cloudbender/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
|
|
|
69
71
|
tests/integration/cloudbender/test_providers_integration.py,sha256=gFqPQom-Cn1iZC50_ChQ2us2_f4tIPATQSAUcWdf7ss,1473
|
|
70
72
|
tests/integration/projects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
71
73
|
tests/integration/projects/conftest.py,sha256=o7rBOFGvcmZ3q0fy7jCIm2CBqn_ULojPP1XFBBUPEVQ,242
|
|
74
|
+
tests/integration/projects/test_projects_credentials_integration.py,sha256=_JqE2sGN09gZpvhtMRFjBPXumJ-PqKl8iXOgcYHlvSY,1636
|
|
72
75
|
tests/integration/projects/test_projects_data_connectors_integration.py,sha256=ag6w2FFQYNlAdV83rOqat0FVZnP4JFhDunCvRwMJdzo,1630
|
|
73
76
|
tests/integration/projects/test_projects_datastores_integration.py,sha256=DCHFnCYguhtrZvfTeWgKpPxlkeAXxVfE3IWkM4KjgAc,1469
|
|
74
77
|
tests/integration/projects/test_projects_integration.py,sha256=wlRLxZkMnJZHlNPaeRFjAeyUlMfbgdrrFEI2eMBcoUI,1241
|
|
@@ -105,6 +108,7 @@ tests/unit/cli/cloudbender/test_cli_provider_unit.py,sha256=jCnFnqZuLzuDx9u3kLyj
|
|
|
105
108
|
tests/unit/cli/cloudbender/test_cli_region_unit.py,sha256=mEAU0z_gKDM-e5J_V8igXmiU4qjrOfzJJRtKRNWdeBs,1262
|
|
106
109
|
tests/unit/cli/cloudbender/test_cli_service_unit.py,sha256=7gFaD-Ox22Gevvk6Sn8zGNp_k3jemwgDX3Yqx8yYN3I,1311
|
|
107
110
|
tests/unit/cli/projects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
111
|
+
tests/unit/cli/projects/test_cli_project_credential_unit.py,sha256=wehwquMGwUzwc8iH0bWletS3-kwIXKshoOuXHhJxRUc,943
|
|
108
112
|
tests/unit/cli/projects/test_cli_project_data_connector_unit.py,sha256=RlqgHOUkFv3bmc19pUtGNVD0W1UWBJSDfaI_lzN0ZEA,993
|
|
109
113
|
tests/unit/cli/projects/test_cli_project_datastore_unit.py,sha256=6UMgFwqxBtH65VeWTzXzaXhVfCRoG3Tef6aflqcDlV4,936
|
|
110
114
|
tests/unit/cli/projects/test_cli_project_key_unit.py,sha256=Xb-O4cltVMNvHpSoPtIdfY4hmXUiMv-z5ixY49FKKyM,894
|
|
@@ -121,15 +125,16 @@ tests/unit/cloudbender/test_providers_unit.py,sha256=y63VCqHXb4Yu8sh0kW30-ojRvv9
|
|
|
121
125
|
tests/unit/cloudbender/test_regions_unit.py,sha256=9bvP268gpNyygjh1IEpSSiUt2aP6okv7QOsV1XoaIS0,6299
|
|
122
126
|
tests/unit/cloudbender/test_services_unit.py,sha256=V1JHfqNcLjz7d3qtVxPBCKzd5_lcL5iwhvWqQ0kw0J0,5220
|
|
123
127
|
tests/unit/projects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
128
|
+
tests/unit/projects/test_project_credentials_unit.py,sha256=y528DyvIm7uc5mFuwiUPjOMO1dkVcMEeYQqzMmKLOuk,3480
|
|
124
129
|
tests/unit/projects/test_project_data_connectors_unit.py,sha256=Yx2yCUgcuN_KfTKynZxse0Nx8jRrSlMygI7R8a-NjE4,3385
|
|
125
130
|
tests/unit/projects/test_project_datastores_unit.py,sha256=WZMKkhpEg2dcevJqT7k6QRcYJF6FJfq177BDk2GWOBk,3129
|
|
126
131
|
tests/unit/projects/test_project_keys_unit.py,sha256=n5Y2rKaenHA6JQFlViE1_dZ00FZ0PhM3C7rQtkuiRGM,3161
|
|
127
132
|
tests/unit/projects/test_project_secrets_unit.py,sha256=VE9L91FJodcwVGizfF65WYMiHZaF0s2AdW1aiJ3z7xA,3276
|
|
128
133
|
tests/unit/projects/test_project_services_unit.py,sha256=PzeNuJRuAG7RkrPWX0FfgFTt6-63FviecrDY06rLQ6A,3331
|
|
129
134
|
tests/unit/projects/test_projects_unit.py,sha256=lTGdKOCN2bjzGORhaDVVlnzJBuEItUDGN36MsyQjDo4,3823
|
|
130
|
-
proximl-0.5.
|
|
131
|
-
proximl-0.5.
|
|
132
|
-
proximl-0.5.
|
|
133
|
-
proximl-0.5.
|
|
134
|
-
proximl-0.5.
|
|
135
|
-
proximl-0.5.
|
|
135
|
+
proximl-0.5.12.dist-info/LICENSE,sha256=ADFxLEZDxKY0j4MdyUd5GNuhQ18rnWH5rOz1ZG7yiOA,1069
|
|
136
|
+
proximl-0.5.12.dist-info/METADATA,sha256=4s3w6gTC6i3GAVUnj4Hw_7NEyO1AH6E4YqkqXo1heXM,7345
|
|
137
|
+
proximl-0.5.12.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
|
138
|
+
proximl-0.5.12.dist-info/entry_points.txt,sha256=HmI311IIabkZReMCXu-nGbvIEW-KfaduAOyfiSqt5SY,63
|
|
139
|
+
proximl-0.5.12.dist-info/top_level.txt,sha256=-TWqc9tAaxmWmW4c7uYsmzPEYUIoh6z02xxqPbv7Kys,23
|
|
140
|
+
proximl-0.5.12.dist-info/RECORD,,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import sys
|
|
3
|
+
import asyncio
|
|
4
|
+
from pytest import mark, fixture
|
|
5
|
+
|
|
6
|
+
pytestmark = [mark.sdk, mark.integration, mark.projects]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@mark.create
|
|
10
|
+
@mark.asyncio
|
|
11
|
+
class ProjectCredentialsTests:
|
|
12
|
+
@fixture(scope="class")
|
|
13
|
+
async def project_credential(self, project):
|
|
14
|
+
project_credential = await project.credentials.put(
|
|
15
|
+
type="aws", key_id="ASFHALKF", secret="IUHKLHKAHF"
|
|
16
|
+
)
|
|
17
|
+
yield project_credential
|
|
18
|
+
await project.credentials.remove(type="aws")
|
|
19
|
+
|
|
20
|
+
async def test_list_project_credentials(self, project, project_credential):
|
|
21
|
+
credentials = await project.credentials.list()
|
|
22
|
+
assert len(credentials) > 0
|
|
23
|
+
|
|
24
|
+
async def test_project_credential_properties(self, project, project_credential):
|
|
25
|
+
assert isinstance(project_credential.project_uuid, str)
|
|
26
|
+
assert isinstance(project_credential.type, str)
|
|
27
|
+
assert isinstance(project_credential.key_id, str)
|
|
28
|
+
assert project_credential.type == "aws"
|
|
29
|
+
assert project.id == project_credential.project_uuid
|
|
30
|
+
|
|
31
|
+
async def test_project_credential_str(self, project_credential):
|
|
32
|
+
string = str(project_credential)
|
|
33
|
+
regex = r"^{.*\"type\": \"" + project_credential.type + r"\".*}$"
|
|
34
|
+
assert isinstance(string, str)
|
|
35
|
+
assert re.match(regex, string)
|
|
36
|
+
|
|
37
|
+
async def test_project_credential_repr(self, project_credential):
|
|
38
|
+
string = repr(project_credential)
|
|
39
|
+
regex = (
|
|
40
|
+
r"^ProjectCredential\( proximl , \*\*{.*'type': '"
|
|
41
|
+
+ project_credential.type
|
|
42
|
+
+ r"'.*}\)$"
|
|
43
|
+
)
|
|
44
|
+
assert isinstance(string, str)
|
|
45
|
+
assert re.match(regex, string)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import json
|
|
3
|
+
import click
|
|
4
|
+
from unittest.mock import AsyncMock, patch, create_autospec
|
|
5
|
+
from pytest import mark, fixture, raises
|
|
6
|
+
|
|
7
|
+
pytestmark = [mark.cli, mark.unit, mark.projects]
|
|
8
|
+
|
|
9
|
+
from proximl.cli.project import credential as specimen
|
|
10
|
+
from proximl.projects import (
|
|
11
|
+
Project,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_list_credentials(runner, mock_project_credentials):
|
|
16
|
+
with patch("proximl.cli.ProxiML", new=AsyncMock) as mock_proximl:
|
|
17
|
+
project = create_autospec(Project)
|
|
18
|
+
mock_proximl.projects = AsyncMock()
|
|
19
|
+
mock_proximl.projects.get = AsyncMock(return_value=project)
|
|
20
|
+
mock_proximl.projects.get_current = AsyncMock(return_value=project)
|
|
21
|
+
project.credentials = AsyncMock()
|
|
22
|
+
project.credentials.list = AsyncMock(return_value=mock_project_credentials)
|
|
23
|
+
result = runner.invoke(specimen, ["list"])
|
|
24
|
+
print(result)
|
|
25
|
+
assert result.exit_code == 0
|
|
26
|
+
project.credentials.list.assert_called_once()
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
from unittest.mock import AsyncMock, patch
|
|
5
|
+
from pytest import mark, fixture, raises
|
|
6
|
+
from aiohttp import WSMessage, WSMsgType
|
|
7
|
+
|
|
8
|
+
import proximl.projects.credentials as specimen
|
|
9
|
+
from proximl.exceptions import (
|
|
10
|
+
ApiError,
|
|
11
|
+
SpecificationError,
|
|
12
|
+
ProxiMLException,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
pytestmark = [mark.sdk, mark.unit, mark.projects]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@fixture
|
|
19
|
+
def project_credentials(mock_proximl):
|
|
20
|
+
yield specimen.ProjectCredentials(mock_proximl, project_id="1")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@fixture
|
|
24
|
+
def project_credential(mock_proximl):
|
|
25
|
+
yield specimen.ProjectCredential(
|
|
26
|
+
mock_proximl, project_uuid="proj-id-1", type="aws", key_id="AIYHGFSDLK"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ProjectCredentialsTests:
|
|
31
|
+
@mark.asyncio
|
|
32
|
+
async def test_project_credentials_list(self, project_credentials, mock_proximl):
|
|
33
|
+
api_response = [
|
|
34
|
+
{"project_uuid": "proj-id-1", "type": "aws", "key_id": "AIYHGFSDLK"},
|
|
35
|
+
{"project_uuid": "proj-id-1", "type": "gcp", "key_id": "credentials.json"},
|
|
36
|
+
]
|
|
37
|
+
mock_proximl._query = AsyncMock(return_value=api_response)
|
|
38
|
+
resp = await project_credentials.list()
|
|
39
|
+
mock_proximl._query.assert_called_once_with(
|
|
40
|
+
"/project/1/credentials", "GET", dict()
|
|
41
|
+
)
|
|
42
|
+
assert len(resp) == 2
|
|
43
|
+
|
|
44
|
+
@mark.asyncio
|
|
45
|
+
async def test_remove_project_credential(
|
|
46
|
+
self,
|
|
47
|
+
project_credentials,
|
|
48
|
+
mock_proximl,
|
|
49
|
+
):
|
|
50
|
+
api_response = dict()
|
|
51
|
+
mock_proximl._query = AsyncMock(return_value=api_response)
|
|
52
|
+
await project_credentials.remove("aws")
|
|
53
|
+
mock_proximl._query.assert_called_once_with(
|
|
54
|
+
"/project/1/credential/aws", "DELETE", dict()
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
@mark.asyncio
|
|
58
|
+
async def test_put_project_credential(self, project_credentials, mock_proximl):
|
|
59
|
+
requested_config = dict(type="aws", key_id="AIUDHADA", secret="ASKHJSLKF")
|
|
60
|
+
expected_payload = dict(key_id="AIUDHADA", secret="ASKHJSLKF")
|
|
61
|
+
api_response = {
|
|
62
|
+
"project_uuid": "project-id-1",
|
|
63
|
+
"type": "aws",
|
|
64
|
+
"key_id": "AIUDHADA",
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
mock_proximl._query = AsyncMock(return_value=api_response)
|
|
68
|
+
response = await project_credentials.put(**requested_config)
|
|
69
|
+
mock_proximl._query.assert_called_once_with(
|
|
70
|
+
"/project/1/credential/aws", "PUT", None, expected_payload
|
|
71
|
+
)
|
|
72
|
+
assert response.type == "aws"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class ProjectCredentialTests:
|
|
76
|
+
def test_project_credential_properties(self, project_credential):
|
|
77
|
+
assert isinstance(project_credential.type, str)
|
|
78
|
+
assert isinstance(project_credential.key_id, str)
|
|
79
|
+
assert isinstance(project_credential.project_uuid, str)
|
|
80
|
+
|
|
81
|
+
def test_project_credential_str(self, project_credential):
|
|
82
|
+
string = str(project_credential)
|
|
83
|
+
regex = r"^{.*\"type\": \"" + project_credential.type + r"\".*}$"
|
|
84
|
+
assert isinstance(string, str)
|
|
85
|
+
assert re.match(regex, string)
|
|
86
|
+
|
|
87
|
+
def test_project_credential_repr(self, project_credential):
|
|
88
|
+
string = repr(project_credential)
|
|
89
|
+
regex = (
|
|
90
|
+
r"^ProjectCredential\( proximl , \*\*{.*'type': '"
|
|
91
|
+
+ project_credential.type
|
|
92
|
+
+ r"'.*}\)$"
|
|
93
|
+
)
|
|
94
|
+
assert isinstance(string, str)
|
|
95
|
+
assert re.match(regex, string)
|
|
96
|
+
|
|
97
|
+
def test_project_credential_bool(self, project_credential, mock_proximl):
|
|
98
|
+
empty_project_credential = specimen.ProjectCredential(mock_proximl)
|
|
99
|
+
assert bool(project_credential)
|
|
100
|
+
assert not bool(empty_project_credential)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|