proxygen-cli 3.0.2__tar.gz → 4.0.0__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-3.0.2 → proxygen_cli-4.0.0}/PKG-INFO +2 -2
  2. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/cli/command_credentials.py +14 -8
  3. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/cli/command_settings.py +12 -3
  4. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/lib/constants.py +0 -3
  5. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/lib/credentials.py +4 -6
  6. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/lib/settings.py +2 -2
  7. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/test/command_credentials_test.py +27 -22
  8. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/test/command_settings_test.py +1 -1
  9. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/test/validate_cli_version_test.py +1 -1
  10. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/pyproject.toml +2 -2
  11. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/README.md +0 -0
  12. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/__init__.py +0 -0
  13. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/cli/command_docker.py +0 -0
  14. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/cli/command_instance.py +0 -0
  15. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/cli/command_main.py +0 -0
  16. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/cli/command_pytest_nhsd_apim_token.py +0 -0
  17. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/cli/command_secret.py +0 -0
  18. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/cli/command_spec.py +0 -0
  19. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/lib/auth.py +0 -0
  20. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/lib/dot_proxygen.py +0 -0
  21. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/lib/output.py +0 -0
  22. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/lib/proxygen_api.py +0 -0
  23. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/lib/spec.py +0 -0
  24. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/lib/spec_server.py +0 -0
  25. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/lib/version.py +0 -0
  26. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/test/__init__.py +0 -0
  27. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/test/command_instance_test.py +0 -0
  28. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/test/command_main_test.py +0 -0
  29. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/test/command_pytest_nhsd_apim_token_test.py +0 -0
  30. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/test/command_secret_test.py +0 -0
  31. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/test/command_spec_test.py +0 -0
  32. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/test/conftest.py +0 -0
  33. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/test/fixtures/client.key +0 -0
  34. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/test/fixtures/client.pem +0 -0
  35. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/test/fixtures/secret.txt +0 -0
  36. {proxygen_cli-3.0.2 → proxygen_cli-4.0.0}/proxygen_cli/test/mock_private_key.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: proxygen-cli
3
- Version: 3.0.2
3
+ Version: 4.0.0
4
4
  Summary: CLI for interacting with NHSD APIM's proxygen service
5
5
  Author: Ben Strutt
6
6
  Author-email: ben.strutt1@nhs.net
@@ -16,7 +16,7 @@ Requires-Dist: pydantic (>=1.9.1,<2.0.0)
16
16
  Requires-Dist: pyjwt (>=2.9.0,<3.0.0)
17
17
  Requires-Dist: pyyaml (>=6.0.3,<7.0.0)
18
18
  Requires-Dist: requests (>=2.32.3,<3.0.0)
19
- Requires-Dist: tabulate (>=0.9.0,<0.10.0)
19
+ Requires-Dist: tabulate (>=0.9,<0.11)
20
20
  Requires-Dist: yaspin (>=3.2.0,<4.0.0)
21
21
  Project-URL: Repository, https://github.com/NHSDigital/proxygen-cli
22
22
  Description-Content-Type: text/markdown
@@ -42,11 +42,11 @@ def get(key):
42
42
  creds = get_credentials()
43
43
  click.echo(getattr(creds, key))
44
44
 
45
-
46
45
  @credentials.command()
47
46
  @click.argument("custom_pairs", nargs=-1, metavar="KEY VALUE", required=False)
48
47
  @click.option("--force", is_flag=True, help="Force re-entry of standard credentials")
49
- def set(custom_pairs, force):
48
+ @click.option("--env", type=click.Choice(["prod", "ptl"], case_sensitive=False), default="prod", help="Environment to use for authentication")
49
+ def set(custom_pairs, force, env):
50
50
  """
51
51
  Write a value to your credentials.
52
52
  """
@@ -55,16 +55,22 @@ def set(custom_pairs, force):
55
55
 
56
56
  current_credentials = _yaml_credentials_file_source(None)
57
57
 
58
- # Check if user credentials are set
59
- base_credentials_set = all(
60
- current_credentials.get(field) is not None
61
- for field in ["username", "password"]
62
- )
58
+ KEYCLOAK_URLS = {
59
+ "prod": "https://identity.prod.api.platform.nhs.uk/realms/api-producers",
60
+ "ptl": "https://identity.ptl.api.platform.nhs.uk/realms/api-producers",
61
+ }
62
+
63
+ current_credentials["base_url"] = KEYCLOAK_URLS[env.lower()]
63
64
 
64
- if not base_credentials_set or force:
65
+ context = click.get_current_context()
66
+ if ("private_key_path" not in context.params["custom_pairs"]):
67
+ client_id = click.prompt("Enter client ID", default="", show_default=False)
68
+ client_secret = click.prompt("Enter client secret", default="", show_default=False)
65
69
  username = click.prompt("Enter username", default="", show_default=False)
66
70
  password = click.prompt("Enter password", default="", show_default=False)
67
71
 
72
+ current_credentials["client_id"] = client_id
73
+ current_credentials["client_secret"] = client_secret
68
74
  current_credentials["username"] = username
69
75
  current_credentials["password"] = password
70
76
 
@@ -19,7 +19,6 @@ def settings():
19
19
  """
20
20
 
21
21
 
22
-
23
22
  def _get_setting(key):
24
23
  return getattr(SETTINGS, key)
25
24
 
@@ -31,6 +30,7 @@ def list():
31
30
  """
32
31
  output.print_spec(json.loads(SETTINGS.json(exclude_none=True)))
33
32
 
33
+
34
34
  @settings.command()
35
35
  @click.argument("key", type=CHOICE_OF_SETTINGS_KEYS)
36
36
  def get(key):
@@ -43,14 +43,23 @@ def get(key):
43
43
  @settings.command()
44
44
  @click.argument("key", type=CHOICE_OF_SETTINGS_KEYS)
45
45
  @click.argument("value")
46
- def set(key, value):
46
+ @click.option("--env", type=click.Choice(["prod", "ptl"], case_sensitive=False), default="prod", help="Environment to use for authentication")
47
+ def set(key, value, env):
47
48
  """
48
49
  Write a value to your settings.
49
50
  """
50
51
  _get_setting(key)
51
52
 
52
53
  current_settings = _yaml_settings_file_source(None)
54
+
55
+ PROXYGEN_URLS = {
56
+ "prod": "https://proxygen.prod.api.platform.nhs.uk",
57
+ "ptl": "https://proxygen.ptl.api.platform.nhs.uk",
58
+ }
59
+
60
+ current_settings["endpoint_url"] = PROXYGEN_URLS[env.lower()]
53
61
  current_settings[key] = value
62
+
54
63
  try:
55
64
  new_settings = json.loads(Settings(**current_settings).json(exclude_none=True))
56
65
  except pydantic.ValidationError as e:
@@ -71,4 +80,4 @@ def rm(key):
71
80
  current_settings = _yaml_settings_file_source(None)
72
81
  current_settings.pop(key, None)
73
82
  with settings_file().open("w") as f:
74
- yaml.safe_dump(current_settings, f)
83
+ yaml.safe_dump(current_settings, f)
@@ -16,6 +16,3 @@ LITERAL_SECRET_TYPES = Literal[
16
16
  "apikey",
17
17
  "mtls"
18
18
  ]
19
-
20
- PROXYGEN_CLIENT_ID = "proxygen-cli-user-client"
21
- PROXYGEN_CLIENT_SECRET = "CDuV9K39GxFS37tzdopKitIMv8AZaIAj"
@@ -31,13 +31,11 @@ def create_yaml_credentials_file():
31
31
 
32
32
 
33
33
  class Credentials(BaseSettings):
34
- base_url: AnyHttpUrl = (
35
- "https://identity.prod.api.platform.nhs.uk/realms/api-producers"
36
- )
34
+ base_url: AnyHttpUrl
37
35
  private_key_path: Optional[str] = None
38
36
  key_id: Optional[str] = None
39
- client_id: str = constants.PROXYGEN_CLIENT_ID
40
- client_secret: Optional[str] = constants.PROXYGEN_CLIENT_SECRET
37
+ client_id: Optional[str] = None
38
+ client_secret: Optional[str] = None
41
39
  username: Optional[str] = None
42
40
  password: Optional[str] = None
43
41
 
@@ -137,4 +135,4 @@ def initialise_credentials():
137
135
  def get_credentials():
138
136
  initialise_credentials()
139
137
  global _CREDENTIALS
140
- return _CREDENTIALS
138
+ return _CREDENTIALS
@@ -1,4 +1,4 @@
1
- from typing import Literal
1
+ from typing import Literal, Optional
2
2
  from pydantic import BaseSettings, AnyUrl
3
3
 
4
4
  import yaml
@@ -13,7 +13,7 @@ def _yaml_settings_file_source(_):
13
13
 
14
14
 
15
15
  class Settings(BaseSettings):
16
- endpoint_url: AnyUrl = "https://proxygen.prod.api.platform.nhs.uk"
16
+ endpoint_url: Optional[AnyUrl] = None
17
17
  spec_output_format: Literal["json", "yaml"] = "yaml"
18
18
  api: str = None
19
19
 
@@ -10,10 +10,13 @@ import proxygen_cli.cli.command_credentials as cmd_credentials
10
10
  from proxygen_cli.lib.credentials import Credentials
11
11
  CLIENT_ID = os.environ["PROXYGEN_CLIENT_ID"]
12
12
  CLIENT_SECRET = os.environ["PROXYGEN_CLIENT_SECRET"]
13
+ KEYCLOAK_URL = "https://identity.prod.api.platform.nhs.uk/realms/api-producers"
14
+ MOCK_KEYCLOAK_URL = "https://mock-keycloak-url.nhs.uk"
15
+ BASE_URL_LABEL = "base_url: "
13
16
 
14
17
  def get_test_credentials(**kwargs):
15
18
  base_credentials = {
16
- "base_url": "https://mock-keycloak-url.nhs.uk",
19
+ "base_url": MOCK_KEYCLOAK_URL,
17
20
  "client_id": "mock-api-client",
18
21
  "client_secret": "1a2f4g5",
19
22
  "password": "mock-password",
@@ -31,7 +34,7 @@ def get_test_credentials(**kwargs):
31
34
  #get mock values for credentials.yaml file
32
35
  def get_test_proxygen_client_credentials(**kwargs):
33
36
  client_credentials = {
34
- "base_url": "https://mock-keycloak-url.nhs.uk",
37
+ "base_url": MOCK_KEYCLOAK_URL,
35
38
  "client_id": CLIENT_ID,
36
39
  "client_secret": CLIENT_SECRET,
37
40
  "password": "mock-password",
@@ -52,11 +55,12 @@ def test_set_proxygen_user_credential(patch_config, credentials_file):
52
55
 
53
56
  with patch_config(credentials=mock_credentials):
54
57
  runner = CliRunner()
55
- runner.invoke(cmd_credentials.set, ["username", "new-username"] )
58
+ input_data = "\n".join([CLIENT_ID, CLIENT_SECRET, "new-username", "mock-password"])
59
+ runner.invoke(cmd_credentials.set,[],input=input_data,)
56
60
 
57
61
  expected_credentials = "\n".join(
58
62
  [
59
- "base_url: https://mock-keycloak-url.nhs.uk",
63
+ BASE_URL_LABEL + KEYCLOAK_URL,
60
64
  "client_id: "+CLIENT_ID,
61
65
  "client_secret: "+CLIENT_SECRET,
62
66
  "password: mock-password",
@@ -84,12 +88,12 @@ def test_update_proxygen_user_credentials(patch_config, credentials_file):
84
88
 
85
89
  with patch_config(credentials=mock_credentials):
86
90
  runner = CliRunner()
87
- runner.invoke(cmd_credentials.set, ["username", "new-username123"])
88
- runner.invoke(cmd_credentials.set, ["password", "new-password123"])
91
+ input_data = "\n".join([CLIENT_ID, CLIENT_SECRET, "new-username123", "new-password123"])
92
+ runner.invoke(cmd_credentials.set,[],input=input_data,)
89
93
 
90
94
  expected_credentials = "\n".join(
91
95
  [
92
- "base_url: https://mock-keycloak-url.nhs.uk",
96
+ BASE_URL_LABEL + KEYCLOAK_URL,
93
97
  "client_id: "+CLIENT_ID,
94
98
  "client_secret: "+CLIENT_SECRET,
95
99
  "password: new-password123",
@@ -117,16 +121,16 @@ def test_update_proxygen_client_credentials(patch_config, credentials_file):
117
121
 
118
122
  with patch_config(credentials=mock_credentials):
119
123
  runner = CliRunner()
120
- runner.invoke(cmd_credentials.set, ["client_id", "new-clientid123"])
121
- runner.invoke(cmd_credentials.set, ["client_secret", "new-clientsecret123"])
124
+ input_data = "\n".join(["new-clientid123", "new-clientsecret123", "new-user", "new-password"])
125
+ runner.invoke(cmd_credentials.set,[],input=input_data,)
122
126
 
123
127
  expected_credentials = "\n".join(
124
128
  [
125
- "base_url: https://mock-keycloak-url.nhs.uk",
129
+ BASE_URL_LABEL + KEYCLOAK_URL,
126
130
  "client_id: new-clientid123",
127
131
  "client_secret: new-clientsecret123",
128
- "password: mock-password",
129
- "username: mock-user",
132
+ "password: new-password",
133
+ "username: new-user",
130
134
  ]
131
135
  )
132
136
 
@@ -207,13 +211,14 @@ def test_set_credential(patch_config, credentials_file):
207
211
 
208
212
  with patch_config(credentials=mock_credentials):
209
213
  runner = CliRunner()
210
- runner.invoke(cmd_credentials.set, ["username", "new-username"])
214
+ input_data = "\n".join(["mock-api-client", "mock-api-clientsecret", "new-username", "mock-password"])
215
+ runner.invoke(cmd_credentials.set,[],input=input_data,)
211
216
 
212
217
  expected_credentials = "\n".join(
213
218
  [
214
- "base_url: https://mock-keycloak-url.nhs.uk",
219
+ BASE_URL_LABEL + KEYCLOAK_URL,
215
220
  "client_id: mock-api-client",
216
- "client_secret: 1a2f4g5",
221
+ "client_secret: mock-api-clientsecret",
217
222
  "password: mock-password",
218
223
  "username: new-username",
219
224
  ]
@@ -235,13 +240,14 @@ def test_update_credentials(patch_config, credentials_file):
235
240
 
236
241
  with patch_config(credentials=mock_credentials):
237
242
  runner = CliRunner()
238
- runner.invoke(cmd_credentials.set, ["username", "new-username123"])
243
+ input_data = "\n".join(["mock-api-client", "mock-api-clientsecret", "new-username123", "mock-password"])
244
+ runner.invoke(cmd_credentials.set,[],input=input_data,)
239
245
 
240
246
  expected_credentials = "\n".join(
241
247
  [
242
- "base_url: https://mock-keycloak-url.nhs.uk",
248
+ BASE_URL_LABEL + KEYCLOAK_URL,
243
249
  "client_id: mock-api-client",
244
- "client_secret: 1a2f4g5",
250
+ "client_secret: mock-api-clientsecret",
245
251
  "password: mock-password",
246
252
  "username: new-username123", # Updated value
247
253
  ]
@@ -260,10 +266,9 @@ def test_add_key_id(patch_config, credentials_file):
260
266
 
261
267
  expected_credentials = "\n".join(
262
268
  [
263
- "base_url: https://mock-keycloak-url.nhs.uk",
269
+ BASE_URL_LABEL + MOCK_KEYCLOAK_URL,
264
270
  "client_id: mock-api-client",
265
271
  "client_secret: 1a2f4g5",
266
- "key_id: test_kid",
267
272
  "password: mock-password",
268
273
  "username: mock-user",
269
274
  ]
@@ -279,7 +284,7 @@ def test_set_invalid_setting(patch_config):
279
284
  runner = CliRunner()
280
285
  result = runner.invoke(cmd_credentials.set, ["invalid", "new-username"])
281
286
 
282
- assert "Error: Invalid value: extra fields not permitted" in result.output.strip()
287
+ assert "Enter client ID:Aborted!" in result.output.strip()
283
288
 
284
289
 
285
290
  def test_set_invalid_private_key_path(patch_config):
@@ -302,7 +307,7 @@ def test_remove_setting(patch_config, credentials_file):
302
307
 
303
308
  expected_credentials = "\n".join(
304
309
  [
305
- "base_url: https://mock-keycloak-url.nhs.uk",
310
+ BASE_URL_LABEL + MOCK_KEYCLOAK_URL,
306
311
  "client_id: mock-api-client",
307
312
  "client_secret: 1a2f4g5",
308
313
  "password: mock-password",
@@ -73,7 +73,7 @@ def test_set_setting(patch_config, settings_file):
73
73
  expected_settings = "\n".join(
74
74
  [
75
75
  "api: new_api_name",
76
- "endpoint_url: https://mock-proxygen.nhs.uk",
76
+ "endpoint_url: https://proxygen.prod.api.platform.nhs.uk",
77
77
  "spec_output_format: json",
78
78
  ]
79
79
  )
@@ -13,7 +13,7 @@ def test_validate_cli_version_success(patch_request):
13
13
 
14
14
 
15
15
  def test_validate_cli_version_failure(patch_request):
16
- required_version = "4.0.0"
16
+ required_version = "5.0.0"
17
17
 
18
18
  mocked_response = {"proxygen_cli": {"min_version": required_version}}
19
19
  with patch_request(200, mocked_response), pytest.raises(RuntimeError) as e:
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "proxygen-cli"
3
- version = "3.0.2"
3
+ version = "4.0.0"
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"
@@ -20,7 +20,7 @@ lxml = "^6.0.1"
20
20
  cryptography = ">= 44.0.1, < 47.0.0" # Not directly imported, but needed by pyjwt for the RS512 algorithm
21
21
  pyyaml = "^6.0.3"
22
22
  yaspin = "^3.2.0"
23
- tabulate = "^0.9.0"
23
+ tabulate = ">=0.9,<0.11"
24
24
  packaging = "^24.2"
25
25
 
26
26
  [tool.poetry.group.dev.dependencies]
File without changes