proxygen-cli 2.1.10__tar.gz → 2.1.11__tar.gz

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.
Files changed (36) hide show
  1. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/PKG-INFO +6 -7
  2. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/README.md +6 -6
  3. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/cli/command_credentials.py +4 -8
  4. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/lib/auth.py +18 -16
  5. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/lib/constants.py +3 -0
  6. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/lib/credentials.py +10 -2
  7. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/test/command_credentials_test.py +117 -2
  8. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/pyproject.toml +1 -1
  9. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/__init__.py +0 -0
  10. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/cli/command_docker.py +0 -0
  11. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/cli/command_instance.py +0 -0
  12. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/cli/command_main.py +0 -0
  13. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/cli/command_pytest_nhsd_apim_token.py +0 -0
  14. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/cli/command_secret.py +0 -0
  15. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/cli/command_settings.py +0 -0
  16. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/cli/command_spec.py +0 -0
  17. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/lib/dot_proxygen.py +0 -0
  18. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/lib/output.py +0 -0
  19. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/lib/proxygen_api.py +0 -0
  20. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/lib/settings.py +0 -0
  21. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/lib/spec.py +0 -0
  22. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/lib/spec_server.py +0 -0
  23. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/lib/version.py +0 -0
  24. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/test/__init__.py +0 -0
  25. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/test/command_instance_test.py +0 -0
  26. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/test/command_main_test.py +0 -0
  27. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/test/command_pytest_nhsd_apim_token_test.py +0 -0
  28. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/test/command_secret_test.py +0 -0
  29. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/test/command_settings_test.py +0 -0
  30. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/test/command_spec_test.py +0 -0
  31. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/test/conftest.py +0 -0
  32. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/test/fixtures/client.key +0 -0
  33. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/test/fixtures/client.pem +0 -0
  34. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/test/fixtures/secret.txt +0 -0
  35. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/test/mock_private_key.py +0 -0
  36. {proxygen_cli-2.1.10 → proxygen_cli-2.1.11}/proxygen_cli/test/validate_cli_version_test.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: proxygen-cli
3
- Version: 2.1.10
3
+ Version: 2.1.11
4
4
  Summary: CLI for interacting with NHSD APIM's proxygen service
5
5
  Home-page: https://github.com/NHSDigital/proxygen-cli
6
6
  Author: Ben Strutt
@@ -38,15 +38,15 @@ After installation, the `proxygen` executable is available. Typing `proxygen` di
38
38
 
39
39
  ### Credentials
40
40
 
41
- The CLI requires client credentials, which can be obtained from the `platforms-api-producer-support` Slack channel.
41
+ The Proxygen CLI client credentials `client_id`, `client_secret` are setup as part of proxygen CLI package.
42
42
 
43
- All users should also have individual credentials. `proxygen-cli` needs to know about them.
44
- You can setup the credentials in `proxygen-cli` using:
43
+ All users should have individual credentials. `proxygen-cli` needs to know about them. You can setup your user credentials in proxygen-cli using:
45
44
  ```
46
45
  proxygen credentials set
47
46
  ```
48
- This command prompts you to enter your `client_id`, `client_secret`, `username`, and `password`.
49
- To update credentials in the future, use:
47
+ This command prompts you to enter your `username`, and `password`.
48
+
49
+ To update any credentials `client_id`/ `client_secret`/ `username`/ `password` in the future, use:
50
50
  ```
51
51
  proxygen credentials set <KEY> <VALUE>
52
52
  ```
@@ -109,4 +109,3 @@ Use the following command to obtain the pytest-nhsd-apim token:
109
109
  ```
110
110
  $(proxygen pytest_nhsd_apim get_token)
111
111
  ```
112
-
@@ -13,15 +13,15 @@ After installation, the `proxygen` executable is available. Typing `proxygen` di
13
13
 
14
14
  ### Credentials
15
15
 
16
- The CLI requires client credentials, which can be obtained from the `platforms-api-producer-support` Slack channel.
16
+ The Proxygen CLI client credentials `client_id`, `client_secret` are setup as part of proxygen CLI package.
17
17
 
18
- All users should also have individual credentials. `proxygen-cli` needs to know about them.
19
- You can setup the credentials in `proxygen-cli` using:
18
+ All users should have individual credentials. `proxygen-cli` needs to know about them. You can setup your user credentials in proxygen-cli using:
20
19
  ```
21
20
  proxygen credentials set
22
21
  ```
23
- This command prompts you to enter your `client_id`, `client_secret`, `username`, and `password`.
24
- To update credentials in the future, use:
22
+ This command prompts you to enter your `username`, and `password`.
23
+
24
+ To update any credentials `client_id`/ `client_secret`/ `username`/ `password` in the future, use:
25
25
  ```
26
26
  proxygen credentials set <KEY> <VALUE>
27
27
  ```
@@ -83,4 +83,4 @@ When testing using the pytest-nhsd-apim python testing package, an apigee manage
83
83
  Use the following command to obtain the pytest-nhsd-apim token:
84
84
  ```
85
85
  $(proxygen pytest_nhsd_apim get_token)
86
- ```
86
+ ```
@@ -2,6 +2,7 @@ import json
2
2
  import click
3
3
  import yaml
4
4
  import pydantic
5
+ import os
5
6
 
6
7
  from proxygen_cli.lib import output
7
8
  from proxygen_cli.lib.credentials import (
@@ -10,7 +11,6 @@ from proxygen_cli.lib.dot_proxygen import credentials_file
10
11
 
11
12
  CHOICE_OF_CREDENTIAL_KEYS = click.Choice(Credentials.__fields__.keys())
12
13
 
13
-
14
14
  @click.group()
15
15
  def credentials():
16
16
  """Get/set credentials."""
@@ -55,20 +55,16 @@ def set(custom_pairs, force):
55
55
 
56
56
  current_credentials = _yaml_credentials_file_source(None)
57
57
 
58
- # Check if base credentials are set
58
+ # Check if user credentials are set
59
59
  base_credentials_set = all(
60
60
  current_credentials.get(field) is not None
61
- for field in ["client_id", "client_secret", "username", "password"]
61
+ for field in ["username", "password"]
62
62
  )
63
63
 
64
64
  if not base_credentials_set or force:
65
- client_id = click.prompt("Enter client_id")
66
- client_secret = click.prompt("Enter client_secret", default="", show_default=False)
67
65
  username = click.prompt("Enter username", default="", show_default=False)
68
66
  password = click.prompt("Enter password", default="", show_default=False)
69
67
 
70
- current_credentials["client_id"] = client_id
71
- current_credentials["client_secret"] = client_secret
72
68
  current_credentials["username"] = username
73
69
  current_credentials["password"] = password
74
70
 
@@ -98,4 +94,4 @@ def rm(key):
98
94
  current_credentials = _yaml_credentials_file_source(None)
99
95
  current_credentials.pop(key, None)
100
96
  with credentials_file().open("w") as f:
101
- yaml.safe_dump(current_credentials, f)
97
+ yaml.safe_dump(current_credentials, f)
@@ -1,5 +1,4 @@
1
1
  """Proxygen test utility functions"""
2
- import functools
3
2
  import hashlib
4
3
  import json
5
4
  import uuid
@@ -72,9 +71,7 @@ def access_token():
72
71
  return token_data["access_token"]
73
72
 
74
73
 
75
- def _get_token_data_from_refresh_token(
76
- refresh_token: str
77
- ):
74
+ def _get_token_data_from_refresh_token(refresh_token: str):
78
75
  CREDENTIALS = get_credentials()
79
76
  token_response = requests.post(
80
77
  f"{CREDENTIALS.base_url}/protocol/openid-connect/token",
@@ -92,7 +89,7 @@ def _get_token_data_from_refresh_token(
92
89
  def _get_token_data_from_user_login():
93
90
  session = requests.Session()
94
91
  CREDENTIALS = get_credentials()
95
- redirect_uri = f"{CREDENTIALS.base_url}/protocol/openid-connect/callback"
92
+ redirect_uri = f"{CREDENTIALS.base_url}/callback"
96
93
  login_page_resp = session.get(
97
94
  f"{CREDENTIALS.base_url}/protocol/openid-connect/auth",
98
95
  params={
@@ -105,7 +102,9 @@ def _get_token_data_from_user_login():
105
102
  )
106
103
 
107
104
  if login_page_resp.status_code != 200:
108
- raise RuntimeError(f"Login page get request status was {login_page_resp.status_code} expected to be 200")
105
+ raise RuntimeError(
106
+ f"Login page get request status was {login_page_resp.status_code} expected to be 200"
107
+ )
109
108
 
110
109
  login_form = html.fromstring(login_page_resp.content.decode()).get_element_by_id(
111
110
  "kc-form-login"
@@ -118,7 +117,11 @@ def _get_token_data_from_user_login():
118
117
  "Accept": "application/json",
119
118
  "Content-Type": "application/x-www-form-urlencoded",
120
119
  },
121
- data={"username": CREDENTIALS.username, "password": CREDENTIALS.password, "credentialId": ""},
120
+ data={
121
+ "username": CREDENTIALS.username,
122
+ "password": CREDENTIALS.password,
123
+ "credentialId": "",
124
+ },
122
125
  )
123
126
 
124
127
  http_error_msg = "Invalid username or password"
@@ -147,9 +150,6 @@ def _get_token_data_from_user_login():
147
150
  return token_response.json()
148
151
 
149
152
 
150
-
151
-
152
-
153
153
  def _get_token_data_from_machine_user():
154
154
  CREDENTIALS = get_credentials()
155
155
  aud = CREDENTIALS.base_url
@@ -164,10 +164,10 @@ def _get_token_data_from_machine_user():
164
164
  "exp": int(time()) + 300, # 5mins in the future
165
165
  }
166
166
 
167
- additional_jwt_headers = {
168
- 'kid': CREDENTIALS.key_id
169
- }
170
- client_assertion = jwt.encode(claims, private_key, algorithm="RS512", headers=additional_jwt_headers)
167
+ additional_jwt_headers = {"kid": CREDENTIALS.key_id}
168
+ client_assertion = jwt.encode(
169
+ claims, private_key, algorithm="RS512", headers=additional_jwt_headers
170
+ )
171
171
  token_response = requests.post(
172
172
  token_endpoint,
173
173
  data={
@@ -177,5 +177,7 @@ def _get_token_data_from_machine_user():
177
177
  },
178
178
  )
179
179
  if token_response.status_code != 200:
180
- raise RuntimeError(f"Token response was {token_response.status_code} expected 200")
181
- return token_response.json()
180
+ raise RuntimeError(
181
+ f"Token response was {token_response.status_code} expected 200"
182
+ )
183
+ return token_response.json()
@@ -16,3 +16,6 @@ LITERAL_SECRET_TYPES = Literal[
16
16
  "apikey",
17
17
  "mtls"
18
18
  ]
19
+
20
+ PROXYGEN_CLIENT_ID = ""
21
+ PROXYGEN_CLIENT_SECRET = ""
@@ -5,7 +5,6 @@ import yaml
5
5
  import sys
6
6
  import os
7
7
 
8
- import click
9
8
  from pydantic import (
10
9
  BaseSettings,
11
10
  validator,
@@ -14,6 +13,12 @@ from pydantic import (
14
13
  )
15
14
 
16
15
  from . import dot_proxygen
16
+ from . import constants
17
+
18
+ data = {
19
+ "client_id": constants.PROXYGEN_CLIENT_ID,
20
+ "client_secret": constants.PROXYGEN_CLIENT_SECRET,
21
+ }
17
22
 
18
23
 
19
24
  def _yaml_credentials_file_source(_):
@@ -26,7 +31,8 @@ def create_yaml_credentials_file():
26
31
  file_path = os.path.expanduser("~/.proxygen/credentials.yaml")
27
32
 
28
33
  if not os.path.exists(file_path):
29
- with open(file_path, 'w'):
34
+ with open(file_path, "w"):
35
+ yaml.dump(data, file_path)
30
36
  pass
31
37
 
32
38
 
@@ -113,6 +119,8 @@ class Credentials(BaseSettings):
113
119
 
114
120
 
115
121
  _CREDENTIALS = None
122
+
123
+
116
124
  def initialise_credentials():
117
125
  global _CREDENTIALS
118
126
  try:
@@ -2,12 +2,14 @@ from unittest.mock import patch
2
2
 
3
3
  import yaml
4
4
  import pytest
5
+ import os
5
6
  from click.testing import CliRunner
6
7
  from pydantic.error_wrappers import ValidationError
7
8
 
8
9
  import proxygen_cli.cli.command_credentials as cmd_credentials
9
10
  from proxygen_cli.lib.credentials import Credentials
10
-
11
+ CLIENT_ID = os.environ["PROXYGEN_CLIENT_ID"]
12
+ CLIENT_SECRET = os.environ["PROXYGEN_CLIENT_SECRET"]
11
13
 
12
14
  def get_test_credentials(**kwargs):
13
15
  base_credentials = {
@@ -26,6 +28,119 @@ def get_test_credentials(**kwargs):
26
28
 
27
29
  return "\n".join(text_format_credentials)
28
30
 
31
+ #get mock values for credentials.yaml file
32
+ def get_test_proxygen_client_credentials(**kwargs):
33
+ client_credentials = {
34
+ "base_url": "https://mock-keycloak-url.nhs.uk",
35
+ "client_id": CLIENT_ID,
36
+ "client_secret": CLIENT_SECRET,
37
+ "password": "mock-password",
38
+ "username": "mock-user",
39
+ }
40
+
41
+ updated_credentials = client_credentials | kwargs
42
+
43
+ text_format_credentials = [
44
+ f"{key}: {value}" for key, value in updated_credentials.items()
45
+ ]
46
+
47
+ return "\n".join(text_format_credentials)
48
+
49
+ #set username and password must be successful
50
+ def test_set_proxygen_user_credential(patch_config, credentials_file):
51
+ mock_credentials = get_test_proxygen_client_credentials()
52
+
53
+ with patch_config(credentials=mock_credentials):
54
+ runner = CliRunner()
55
+ runner.invoke(cmd_credentials.set, ["username", "new-username"] )
56
+
57
+ expected_credentials = "\n".join(
58
+ [
59
+ "base_url: https://mock-keycloak-url.nhs.uk",
60
+ "client_id: "+CLIENT_ID,
61
+ "client_secret: "+CLIENT_SECRET,
62
+ "password: mock-password",
63
+ "username: new-username",
64
+ ]
65
+ )
66
+
67
+ # Check the file has been written to
68
+ assert credentials_file() == expected_credentials
69
+
70
+
71
+ #overwrite username and password must be successful, with client id and secret values unmodified
72
+ def test_update_proxygen_user_credentials(patch_config, credentials_file):
73
+ mock_credentials = get_test_proxygen_client_credentials()
74
+
75
+ # Convert mock_credentials to a dictionary
76
+ mock_credentials_dict = yaml.safe_load(mock_credentials)
77
+
78
+ # Set an initial value for the username and password field
79
+ initial_username = "old-username"
80
+ mock_credentials_dict["username"] = initial_username
81
+
82
+ initial_password = "old-password"
83
+ mock_credentials_dict["password"] = initial_password
84
+
85
+ with patch_config(credentials=mock_credentials):
86
+ runner = CliRunner()
87
+ runner.invoke(cmd_credentials.set, ["username", "new-username123"])
88
+ runner.invoke(cmd_credentials.set, ["password", "new-password123"])
89
+
90
+ expected_credentials = "\n".join(
91
+ [
92
+ "base_url: https://mock-keycloak-url.nhs.uk",
93
+ "client_id: "+CLIENT_ID,
94
+ "client_secret: "+CLIENT_SECRET,
95
+ "password: new-password123",
96
+ "username: new-username123",
97
+ ]
98
+ )
99
+
100
+ # Check the file has been written to
101
+ assert credentials_file() == expected_credentials
102
+
103
+ #overwrite client id and secret must be successful
104
+ def test_update_proxygen_client_credentials(patch_config, credentials_file):
105
+ mock_credentials = get_test_proxygen_client_credentials()
106
+
107
+ # Convert mock_credentials to a dictionary
108
+ mock_credentials_dict = yaml.safe_load(mock_credentials)
109
+ print("HELLO")
110
+ print(mock_credentials_dict)
111
+ # Set an initial value for the username and password field
112
+ initial_clientid = "old-clientid"
113
+ mock_credentials_dict["username"] = initial_clientid
114
+
115
+ initial_clientsecret = "old-clientsecret"
116
+ mock_credentials_dict["password"] = initial_clientsecret
117
+
118
+ with patch_config(credentials=mock_credentials):
119
+ runner = CliRunner()
120
+ runner.invoke(cmd_credentials.set, ["client_id", "new-clientid123"])
121
+ runner.invoke(cmd_credentials.set, ["client_secret", "new-clientsecret123"])
122
+
123
+ expected_credentials = "\n".join(
124
+ [
125
+ "base_url: https://mock-keycloak-url.nhs.uk",
126
+ "client_id: new-clientid123",
127
+ "client_secret: new-clientsecret123",
128
+ "password: mock-password",
129
+ "username: mock-user",
130
+ ]
131
+ )
132
+
133
+ # Check the file has been written to
134
+ assert credentials_file() == expected_credentials
135
+
136
+
137
+ #verify error for missing proxygen username and password
138
+ def test_missing_proxygen_user_credentials(update_config):
139
+ mock_credentials = get_test_proxygen_client_credentials(username="",password="")
140
+ update_config(credentials=mock_credentials)
141
+
142
+ with pytest.raises(ValidationError):
143
+ Credentials()
29
144
 
30
145
  def test_missing_credentials(update_config):
31
146
  mock_credentials = get_test_credentials(username="")
@@ -206,4 +321,4 @@ def test_remove_invalid_setting(patch_config):
206
321
  runner = CliRunner()
207
322
  result = runner.invoke(cmd_credentials.rm, ["invalid"])
208
323
 
209
- assert "'invalid' is not one of 'base_url'" in result.output.strip()
324
+ assert "'invalid' is not one of 'base_url'" in result.output.strip()
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "proxygen-cli"
3
- version = "2.1.10"
3
+ version = "2.1.11"
4
4
  description = "CLI for interacting with NHSD APIM's proxygen service"
5
5
  authors = ["Ben Strutt <ben.strutt1@nhs.net>"]
6
6
  readme = "README.md"