From 404c6d8879065a9f12f4a7297892f74185c617e9 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 29 Apr 2024 12:07:09 +0000 Subject: [PATCH 01/18] [AEA-3864] updated auth to lvl 3 and misc cleanup --- packages/specification/Makefile | 15 +++++++ .../eps-prescription-status-update-api.yaml | 8 ++-- packages/specification/package.json | 2 - .../specification/src/replaceComponents.ts | 22 ----------- .../tests/testReplaceComponents.test.ts | 39 ------------------- 5 files changed, 19 insertions(+), 67 deletions(-) create mode 100644 packages/specification/Makefile delete mode 100644 packages/specification/src/replaceComponents.ts delete mode 100644 packages/specification/tests/testReplaceComponents.test.ts diff --git a/packages/specification/Makefile b/packages/specification/Makefile new file mode 100644 index 000000000..68e138093 --- /dev/null +++ b/packages/specification/Makefile @@ -0,0 +1,15 @@ +SHELL=/bin/bash -euo pipefail + +.PHONY: install build test publish release clean + +install: + npm ci + +clean: + rm -rf dist/ + +build: + mkdir -p dist + npm run lint + npm run resolve + ls -la dist diff --git a/packages/specification/eps-prescription-status-update-api.yaml b/packages/specification/eps-prescription-status-update-api.yaml index 08ef088d2..746816657 100755 --- a/packages/specification/eps-prescription-status-update-api.yaml +++ b/packages/specification/eps-prescription-status-update-api.yaml @@ -193,11 +193,11 @@ paths: example: $ref: examples/error-ods-code.json security: - - app-level0: [] + - app-level3: [] components: securitySchemes: - app-level0: - $ref: https://proxygen.ptl.api.platform.nhs.uk/components/securitySchemes/app-level0 + app-level3: + $ref: https://proxygen.prod.api.platform.nhs.uk/components/securitySchemes/app-level3 parameters: BearerAuthorisation: in: header @@ -281,7 +281,7 @@ x-nhsd-apim: access: - title: Application Restricted grants: - app-level0: [] + app-level3: [] target: type: hosted healthcheck: /_status diff --git a/packages/specification/package.json b/packages/specification/package.json index 54f5dc87e..f0c64d5fa 100644 --- a/packages/specification/package.json +++ b/packages/specification/package.json @@ -7,8 +7,6 @@ "unit": "POWERTOOLS_DEV=true NODE_OPTIONS=--experimental-vm-modules jest --no-cache --coverage", "lint": "swagger-cli validate eps-prescription-status-update-api.yaml", "resolve": "swagger-cli bundle eps-prescription-status-update-api.yaml -r -o dist/eps-prescription-status-update-api.resolved.json", - "replace-components": "node lib/src/replaceComponents.js", - "compile": "tsc", "clean": "rm -rf lib coverage", "test": "npm run clean && npm run resolve && npm run compile && npm run replace-components && npm run unit", "check-licenses": "license-checker --failOn GPL --failOn LGPL --start ../.." diff --git a/packages/specification/src/replaceComponents.ts b/packages/specification/src/replaceComponents.ts deleted file mode 100644 index 14e241345..000000000 --- a/packages/specification/src/replaceComponents.ts +++ /dev/null @@ -1,22 +0,0 @@ -import fs from "fs" - -export function replaceAppLevel0Object() { - const jsonFilePath = "dist/eps-prescription-status-update-api.resolved.json" - const jsonData = fs.readFileSync(jsonFilePath, "utf8") - const jsonObject = JSON.parse(jsonData) - - // Define the new object to replace "app-level0" - const newAppLevel0Object = { - "$ref": "https://proxygen.prod.api.platform.nhs.uk/components/securitySchemes/app-level0" - } - - // Replace the "app-level0" object - jsonObject.components.securitySchemes["app-level0"] = newAppLevel0Object - - // Write the modified JSON back to the file - fs.writeFileSync(jsonFilePath, JSON.stringify(jsonObject, null, 2)) - - console.log("Replacement completed.") -} - -replaceAppLevel0Object() diff --git a/packages/specification/tests/testReplaceComponents.test.ts b/packages/specification/tests/testReplaceComponents.test.ts deleted file mode 100644 index 7d93e5cb4..000000000 --- a/packages/specification/tests/testReplaceComponents.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import fs from "fs" -import {replaceAppLevel0Object} from "../src/replaceComponents" - -describe("replaceAppLevel0Object", () => { - const jsonFilePath: string = "dist/eps-prescription-status-update-api.resolved.json" - - beforeEach(() => { - // Create a sample JSON file before each test - const sampleData = { - components: { - securitySchemes: { - "app-level0": { - // Existing data to be replaced - description: "Existing app-level0 object" - } - } - } - } - fs.writeFileSync(jsonFilePath, JSON.stringify(sampleData, null, 2)) - }) - - afterEach(() => { - // Clean up the sample JSON file after each test - fs.unlinkSync(jsonFilePath) - }) - - it("should replace app-level0 object in the JSON file", () => { - // Call the function to replace the object - replaceAppLevel0Object() - - // Read the modified JSON file - const modifiedData = JSON.parse(fs.readFileSync(jsonFilePath, "utf8")) - - // Check if the app-level0 object is replaced - expect(modifiedData.components.securitySchemes["app-level0"]).toEqual({ - "$ref": "https://proxygen.prod.api.platform.nhs.uk/components/securitySchemes/app-level0" - }) - }) -}) From 9f9000f31338d5a18a47e9e5884ca729c438b333 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 29 Apr 2024 14:21:55 +0000 Subject: [PATCH 02/18] [AEA-3864] fixed package.json --- .github/workflows/sam_package_code.yml | 2 +- Makefile | 6 ++---- packages/specification/package.json | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/sam_package_code.yml b/.github/workflows/sam_package_code.yml index a605f3f31..e1c9d62d2 100644 --- a/.github/workflows/sam_package_code.yml +++ b/.github/workflows/sam_package_code.yml @@ -55,7 +55,7 @@ jobs: cp .tool-versions ~/ rm -rf .aws-sam export PATH=$PATH:$PWD/node_modules/.bin - make publish + make build-specification make sam-build cp Makefile .aws-sam/build/ cp samconfig_package_and_deploy.toml .aws-sam/build/ diff --git a/Makefile b/Makefile index 309488db4..5a1d789ab 100644 --- a/Makefile +++ b/Makefile @@ -136,10 +136,8 @@ deep-clean: clean find . -name 'node_modules' -type d -prune -exec rm -rf '{}' + poetry env remove --all -publish: - npm run resolve --workspace packages/specification 2> /dev/null - npm run compile --workspace packages/specification 2> /dev/null - npm run replace-components --workspace packages/specification 2> /dev/null +build-specification: + $(MAKE) --directory=packages/specification build check-licenses: check-licenses-node check-licenses-python diff --git a/packages/specification/package.json b/packages/specification/package.json index f0c64d5fa..911c0bfc7 100644 --- a/packages/specification/package.json +++ b/packages/specification/package.json @@ -8,7 +8,6 @@ "lint": "swagger-cli validate eps-prescription-status-update-api.yaml", "resolve": "swagger-cli bundle eps-prescription-status-update-api.yaml -r -o dist/eps-prescription-status-update-api.resolved.json", "clean": "rm -rf lib coverage", - "test": "npm run clean && npm run resolve && npm run compile && npm run replace-components && npm run unit", "check-licenses": "license-checker --failOn GPL --failOn LGPL --start ../.." }, "author": "NHS Digital", From 7fd97f9269a1ec3264deafae85fc982b32eb8855 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 29 Apr 2024 14:26:39 +0000 Subject: [PATCH 03/18] [AEA-3864] debugging pipeline --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 5a1d789ab..3557ea33f 100644 --- a/Makefile +++ b/Makefile @@ -120,7 +120,6 @@ test: compile npm run test --workspace packages/updatePrescriptionStatus npm run test --workspace packages/gsul npm run test --workspace packages/sandbox - npm run test --workspace packages/specification clean: rm -rf packages/updatePrescriptionStatus/coverage From 33540531fa8f4004b7ab15be780d471ca1fce890 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 29 Apr 2024 15:40:26 +0000 Subject: [PATCH 04/18] [AEA-3864] added securitySchema replacement to deploy_api --- .github/scripts/deploy_api.sh | 6 ++++++ .../specification/eps-prescription-status-update-api.yaml | 2 ++ 2 files changed, 8 insertions(+) diff --git a/.github/scripts/deploy_api.sh b/.github/scripts/deploy_api.sh index 989f1f624..ced2e01e0 100755 --- a/.github/scripts/deploy_api.sh +++ b/.github/scripts/deploy_api.sh @@ -30,6 +30,12 @@ else jq --arg env "$APIGEE_ENVIRONMENT" --arg inst "$instance" '.servers = [ { "url": "https://\($env).api.service.nhs.uk/\($inst)" } ]' "$SPEC_PATH" > temp.json && mv temp.json "$SPEC_PATH" fi +# Find and replace securitySchemes +if [[ $APIGEE_ENVIRONMENT == prod ]]; then + jq '.components.securitySchemes.["app-level3"] = {"$ref": "https://proxygen.prod.api.platform.nhs.uk/components/securitySchemes/app-level3"}' "$SPEC_PATH" > temp.json && mv temp.json "$SPEC_PATH" +else + jq '.components.securitySchemes.["app-level3"] = {"$ref": "https://proxygen.ptl.api.platform.nhs.uk/components/securitySchemes/app-level3"}' "$SPEC_PATH" > temp.json && mv temp.json "$SPEC_PATH" +fi # Retrieve the proxygen private key and client private key and cert from AWS Secrets Manager proxygen_private_key_arn=$(aws cloudformation list-exports --query "Exports[?Name=='account-resources:ProxgenPrivateKey'].Value" --output text) client_private_key_arn=$(aws cloudformation list-exports --query "Exports[?Name=='account-resources:PsuClientKeySecret'].Value" --output text) diff --git a/packages/specification/eps-prescription-status-update-api.yaml b/packages/specification/eps-prescription-status-update-api.yaml index 746816657..e46d7dbf7 100755 --- a/packages/specification/eps-prescription-status-update-api.yaml +++ b/packages/specification/eps-prescription-status-update-api.yaml @@ -275,6 +275,8 @@ components: $ref: "schemas/components/ResponseBundle.yaml" OperationOutcome: $ref: schemas/resources/OperationOutcome.yaml +security: + - app-level3: [] x-nhsd-apim: temporary: false monitoring: false From 4d4d35b50928a990364589b2444df72c8df4df5d Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 29 Apr 2024 15:53:46 +0000 Subject: [PATCH 05/18] [AEA-3864] debugging deployment --- .github/scripts/deploy_api.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/scripts/deploy_api.sh b/.github/scripts/deploy_api.sh index ced2e01e0..68f719559 100755 --- a/.github/scripts/deploy_api.sh +++ b/.github/scripts/deploy_api.sh @@ -32,9 +32,9 @@ fi # Find and replace securitySchemes if [[ $APIGEE_ENVIRONMENT == prod ]]; then - jq '.components.securitySchemes.["app-level3"] = {"$ref": "https://proxygen.prod.api.platform.nhs.uk/components/securitySchemes/app-level3"}' "$SPEC_PATH" > temp.json && mv temp.json "$SPEC_PATH" + jq '.components.securitySchemes."app-level3" = {"$ref": "https://proxygen.prod.api.platform.nhs.uk/components/securitySchemes/app-level3"}' "$SPEC_PATH" > temp.json && mv temp.json "$SPEC_PATH" else - jq '.components.securitySchemes.["app-level3"] = {"$ref": "https://proxygen.ptl.api.platform.nhs.uk/components/securitySchemes/app-level3"}' "$SPEC_PATH" > temp.json && mv temp.json "$SPEC_PATH" + jq '.components.securitySchemes."app-level3" = {"$ref": "https://proxygen.ptl.api.platform.nhs.uk/components/securitySchemes/app-level3"}' "$SPEC_PATH" > temp.json && mv temp.json "$SPEC_PATH" fi # Retrieve the proxygen private key and client private key and cert from AWS Secrets Manager proxygen_private_key_arn=$(aws cloudformation list-exports --query "Exports[?Name=='account-resources:ProxgenPrivateKey'].Value" --output text) From 642eb46f5c80001dda021b8b27f3c4116e70885d Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 30 Apr 2024 15:50:23 +0000 Subject: [PATCH 06/18] [AEA-3864] update deploy_api to tweak proxy title for PR's --- .github/scripts/deploy_api.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/scripts/deploy_api.sh b/.github/scripts/deploy_api.sh index 68f719559..9e77f235a 100755 --- a/.github/scripts/deploy_api.sh +++ b/.github/scripts/deploy_api.sh @@ -17,6 +17,12 @@ else fi echo "Proxy instance: $instance" +# Find and replace the title +title=$(jq '.info.title') +if [[ $STACK_NAME == psu-pr-* ]]; then + jq --arg title "[PR-$pr_id] $title" '.info.title = $title' "$SPEC_PATH" > temp.json && mv temp.json "$SPEC_PATH" +fi + # Find and replace the specification version number jq --arg version "$VERSION_NUMBER" '.info.version = $version' "$SPEC_PATH" > temp.json && mv temp.json "$SPEC_PATH" From d8004c8460777f1507b6e5f438d61c1d2d0cf7f7 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 30 Apr 2024 16:31:33 +0000 Subject: [PATCH 07/18] [AEA-3864] resolving conflict --- package-lock.json | 3 +++ poetry.lock | 5 ++++- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 53770ea7f..97d31c2da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3831,6 +3831,7 @@ }, "node_modules/ajv": { "version": "6.12.6", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -5913,6 +5914,7 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", + "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { @@ -7781,6 +7783,7 @@ }, "node_modules/json-schema-traverse": { "version": "0.4.1", + "dev": true, "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { diff --git a/poetry.lock b/poetry.lock index 821e007a3..77e663656 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1192,6 +1192,9 @@ files = [ {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, ] +[package.dependencies] +cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""} + [package.extras] crypto = ["cryptography (>=3.4.0)"] dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] @@ -1737,4 +1740,4 @@ termcolor = ">=2.3,<3.0" [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "39a576be17e0c4473e188549d3007ea7525e18787bbb185faaa9dd8f18ee6bc3" +content-hash = "a5429d4ea86a09c4e4205123f5a52e0e201bb39d977ec7f623b41b3bc2800a21" diff --git a/pyproject.toml b/pyproject.toml index da53f9c81..9d5c4ab63 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,8 +37,8 @@ argparse = "^1.4.0" pre-commit = "^3.5.0" pytest = "^8.2.0" cfn-lint = "^0.86.4" -pyjwt = "^2.8.0" -proxygen-cli = "^2.1.13" +pyjwt = {extras = ["crypto"], version = "^2.8.0"} +proxygen-cli = "^2.1.11" [tool.poetry.scripts] From abb87d924b20be0285590f6cf71dae8d249540f6 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 1 May 2024 08:34:56 +0000 Subject: [PATCH 08/18] [AEA-3864] tweaking script for replacing title --- .github/scripts/deploy_api.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/deploy_api.sh b/.github/scripts/deploy_api.sh index 9e77f235a..1b03dfce9 100755 --- a/.github/scripts/deploy_api.sh +++ b/.github/scripts/deploy_api.sh @@ -18,7 +18,7 @@ fi echo "Proxy instance: $instance" # Find and replace the title -title=$(jq '.info.title') +title=$(jq '.info.title' "$SPEC_PATH") if [[ $STACK_NAME == psu-pr-* ]]; then jq --arg title "[PR-$pr_id] $title" '.info.title = $title' "$SPEC_PATH" > temp.json && mv temp.json "$SPEC_PATH" fi From e09d88d6d24595f78633b2db18c138fa03e2c767 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 1 May 2024 09:05:40 +0000 Subject: [PATCH 09/18] [AEA-3864] tweaking title replacement --- .github/scripts/deploy_api.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/deploy_api.sh b/.github/scripts/deploy_api.sh index 1b03dfce9..fdb1e4a5c 100755 --- a/.github/scripts/deploy_api.sh +++ b/.github/scripts/deploy_api.sh @@ -18,7 +18,7 @@ fi echo "Proxy instance: $instance" # Find and replace the title -title=$(jq '.info.title' "$SPEC_PATH") +title=$(jq -r '.info.title' "$SPEC_PATH") if [[ $STACK_NAME == psu-pr-* ]]; then jq --arg title "[PR-$pr_id] $title" '.info.title = $title' "$SPEC_PATH" > temp.json && mv temp.json "$SPEC_PATH" fi From 01faf874ab05c7eb009f37e76cba0bea7282a00a Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 8 May 2024 10:39:23 +0000 Subject: [PATCH 10/18] [AEA-3864] initial auth script --- generate_jwt.py | 129 ++++++++++++++++++++++++++++++++++++++++++++++++ poetry.lock | 69 +++++++++++++++++++++++++- pyproject.toml | 2 + 3 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 generate_jwt.py diff --git a/generate_jwt.py b/generate_jwt.py new file mode 100644 index 000000000..59dccfa5d --- /dev/null +++ b/generate_jwt.py @@ -0,0 +1,129 @@ +import click +import json +import uuid +import jwt +import requests +from time import time +from rich.console import Console +from rich.theme import Theme +from rich.prompt import Confirm + + +cli_theme = Theme({ + "heading": "bold italic underline purple4", + "key": "bold italic purple4", + "value": "dim purple4", + "info": "deep_sky_blue4", + "error": "red", + "data": "orange3" +}) +console = Console(theme=cli_theme, highlight=False) + + +@click.group() +def cli(): + pass + + +@cli.command() +@click.option("--api_key", default=None, help="the api key, defaults to the value of in psu-creds.json") +@click.option("--creds_dir", default="/home/vscode/.ssh", + help="the directory containing any key pairs & psu-cred.json, defaults to '/home/vscode/.ssh'") +@click.option("--env", default="internal-dev", help="the target environment, defaults to 'internal-dev'") +@click.option("--expiry", default=300, help="The JWT expiry in seconds, defaults to 300(5mins)") +@click.option("--kid", default=None, help="the kid of the key pair, defaults to 'psu-'") +def encode_jwt(api_key, creds_dir, env, expiry, kid): + kid = kid if kid else f"psu-{env}" + + if not api_key: + console.print(f"Getting API key for [bold]{env}[/bold] from psu_creds.json...", style="info") + try: + with open(f"{creds_dir}/psu_creds.json", "r") as f: + psu_creds = json.load(f) + except FileNotFoundError: + console.print("[bold]Error:[/bold] PSU credentials file not found.", style="error") + console.print_exception() + exit() + + env_key = psu_creds.get(env) + if not env_key: + console.print(f"[bold]Error:[/bold] Key not found for env: {env}", style="error") + exit() + api_key = env_key + + console.print("--------------------------------------------", style="key") + console.print("Config:", style="heading") + console.print(f"[key]Env:[/key] [value]{env}[/value]") + console.print(f"[key]Credentials dir:[/key] [value]{creds_dir}[/value]") + console.print(f"[key]KID:[/key] [value]{kid}[/value]") + console.print(f"[key]API Key:[/key] [value]{api_key}[/value]") + console.print(f"[key]Expiry:[/key] [value]{expiry}[/value]") + console.print("--------------------------------------------", style="key") + + is_config_ok = Confirm.ask("Is this correct?") + if not is_config_ok: + exit() + console.print("--------------------------------------------", style="key") + + console.print(f"Getting private key from [bold]{creds_dir}/{kid}.pem[/bold]...", style="info") + try: + with open(f"{creds_dir}/{kid}.pem", "r") as f: + private_key = f.read() + except FileNotFoundError: + console.print("[bold]Error:[/bold] Private key not found.", style="error") + console.print_exception() + exit() + + claims = { + "sub": api_key, + "iss": api_key, + "jti": str(uuid.uuid4()), + "aud": f"https://{env}.api.service.nhs.uk/oauth2/token", + "exp": int(time()) + expiry, + } + + additional_headers = {"kid": kid} + + console.print("Encoding JWT...", style="info") + encoded_jwt = jwt.encode( + claims, private_key, algorithm="RS512", headers=additional_headers + ) + console.print(encoded_jwt, style="data") + console.print("Complete!", style="info") + return encoded_jwt + + +@cli.command() +@click.option("--encoded_jwt", help="the jwt") +@click.option("--env", default="internal-dev", help="the target environment, defaults to 'internal-dev'") +def exchange_tokens(encoded_jwt, env): + print(encoded_jwt) + print(env) + data = { + "grant_type": "client_credentials", + "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", + "client_assertion": encoded_jwt + } + headers = { + "Content-Type": "application/x-www-form-urlencoded" + } + + res = requests.post(f"https://{env}.api.service.nhs.uk/oauth2/token", data=data, headers=headers) + console.print(res.text, style="data") + + +@cli.command() +@click.option("--api_key", default=None, help="the api key, defaults to the value of in psu-creds.json") +@click.option("--creds_dir", default="/home/vscode/.ssh", + help="the directory containing any key pairs & psu-cred.json, defaults to '/home/vscode/.ssh'") +@click.option("--env", default="internal-dev", help="the target environment, defaults to 'internal-dev'") +@click.option("--expiry", default=300, help="The JWT expiry in seconds, defaults to 300(5mins)") +@click.option("--kid", default=None, help="the kid of the key pair, defaults to 'psu-'") +@click.pass_context +def auth(ctx, api_key, creds_dir, env, expiry, kid): + encoded_jwt = ctx.forward(encode_jwt) + ctx.invoke(exchange_tokens, encoded_jwt=encoded_jwt, env=env) + + +if __name__ == "__main__": + cli() diff --git a/poetry.lock b/poetry.lock index 77e663656..b6cb60e47 100644 --- a/poetry.lock +++ b/poetry.lock @@ -808,6 +808,30 @@ html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] source = ["Cython (==0.29.37)"] +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + [[package]] name = "markupsafe" version = "2.1.5" @@ -888,6 +912,17 @@ files = [ {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + [[package]] name = "mpmath" version = "1.3.0" @@ -1181,6 +1216,20 @@ files = [ {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, ] +[[package]] +name = "pygments" +version = "2.18.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + [[package]] name = "pyjwt" version = "2.8.0" @@ -1433,6 +1482,24 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "rich" +version = "13.7.1" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, + {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + [[package]] name = "rpds-py" version = "0.18.0" @@ -1740,4 +1807,4 @@ termcolor = ">=2.3,<3.0" [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "a5429d4ea86a09c4e4205123f5a52e0e201bb39d977ec7f623b41b3bc2800a21" +content-hash = "eee841ba2cc337984f810788f7790f26d42c7b0f5e367be69a03ff7bd1e6d46e" diff --git a/pyproject.toml b/pyproject.toml index 9d5c4ab63..05dff9a97 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,8 @@ black = "^24.4.2" flake8 = "^7.0.0" jinja2 = "^3.1.3" pip-licenses = "^4.4.0" +click = "^8.1.7" +rich = "^13.7.1" [build-system] requires = ["poetry>=0.12"] From a918eeb7061538142bde976f4b5e36a775a3affc Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 8 May 2024 16:11:05 +0000 Subject: [PATCH 11/18] [AEA-3864] added main commands to auth cli --- generate_jwt.py => psu_auth.py | 89 +++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 24 deletions(-) rename generate_jwt.py => psu_auth.py (56%) diff --git a/generate_jwt.py b/psu_auth.py similarity index 56% rename from generate_jwt.py rename to psu_auth.py index 59dccfa5d..27d283f15 100644 --- a/generate_jwt.py +++ b/psu_auth.py @@ -4,27 +4,44 @@ import jwt import requests from time import time +from datetime import datetime from rich.console import Console from rich.theme import Theme from rich.prompt import Confirm cli_theme = Theme({ - "heading": "bold italic underline purple4", - "key": "bold italic purple4", - "value": "dim purple4", + "heading": "bold italic underline", + "key": "bold italic", + "value": "dim", "info": "deep_sky_blue4", - "error": "red", + "error": "red1", + "success": "green4", + "config": "purple4", "data": "orange3" }) console = Console(theme=cli_theme, highlight=False) +def log_heading(heading, style): + console.print(f"[heading]{heading}[/heading]", style=style) + + +def log_key_value(key, value, style): + console.print(f"[key]{key}:[/key] [value]{value}[/value]", style=style) + + @click.group() def cli(): pass +@click.option("--creds_dir", default="/home/vscode/.ssh", + help="the directory containing any key pairs & psu-cred.json, defaults to '/home/vscode/.ssh'") +def create_creds_file(): + pass + + @cli.command() @click.option("--api_key", default=None, help="the api key, defaults to the value of in psu-creds.json") @click.option("--creds_dir", default="/home/vscode/.ssh", @@ -32,7 +49,7 @@ def cli(): @click.option("--env", default="internal-dev", help="the target environment, defaults to 'internal-dev'") @click.option("--expiry", default=300, help="The JWT expiry in seconds, defaults to 300(5mins)") @click.option("--kid", default=None, help="the kid of the key pair, defaults to 'psu-'") -def encode_jwt(api_key, creds_dir, env, expiry, kid): +def encode_jwt(api_key, creds_dir, env, expiry, kid, standalone=True): kid = kid if kid else f"psu-{env}" if not api_key: @@ -41,36 +58,36 @@ def encode_jwt(api_key, creds_dir, env, expiry, kid): with open(f"{creds_dir}/psu_creds.json", "r") as f: psu_creds = json.load(f) except FileNotFoundError: - console.print("[bold]Error:[/bold] PSU credentials file not found.", style="error") + log_key_value("Error", "PSU credentials file not found.", "error") console.print_exception() exit() env_key = psu_creds.get(env) if not env_key: - console.print(f"[bold]Error:[/bold] Key not found for env: {env}", style="error") + log_key_value("Error", f"Key not found for env: {env}", "error") exit() api_key = env_key - console.print("--------------------------------------------", style="key") - console.print("Config:", style="heading") - console.print(f"[key]Env:[/key] [value]{env}[/value]") - console.print(f"[key]Credentials dir:[/key] [value]{creds_dir}[/value]") - console.print(f"[key]KID:[/key] [value]{kid}[/value]") - console.print(f"[key]API Key:[/key] [value]{api_key}[/value]") - console.print(f"[key]Expiry:[/key] [value]{expiry}[/value]") - console.print("--------------------------------------------", style="key") + console.print("--------------------------------------------", style="config") + log_heading("Config:", "config") + log_key_value("Env", env, "config") + log_key_value("Credentials dir", creds_dir, "config") + log_key_value("KID", kid, "config") + log_key_value("API key", api_key, "config") + log_key_value("Expiry", expiry, "config") + console.print("--------------------------------------------", style="config") is_config_ok = Confirm.ask("Is this correct?") if not is_config_ok: exit() - console.print("--------------------------------------------", style="key") + console.print("--------------------------------------------", style="config") console.print(f"Getting private key from [bold]{creds_dir}/{kid}.pem[/bold]...", style="info") try: with open(f"{creds_dir}/{kid}.pem", "r") as f: private_key = f.read() except FileNotFoundError: - console.print("[bold]Error:[/bold] Private key not found.", style="error") + log_key_value("Error", "Private key not found.", "error") console.print_exception() exit() @@ -81,15 +98,18 @@ def encode_jwt(api_key, creds_dir, env, expiry, kid): "aud": f"https://{env}.api.service.nhs.uk/oauth2/token", "exp": int(time()) + expiry, } - additional_headers = {"kid": kid} console.print("Encoding JWT...", style="info") encoded_jwt = jwt.encode( claims, private_key, algorithm="RS512", headers=additional_headers ) - console.print(encoded_jwt, style="data") - console.print("Complete!", style="info") + + console.print("Encoding complete!", style="success") + if standalone: + console.print("--------------------------------------------", style="data") + console.print(encoded_jwt, style="data", soft_wrap=True) + console.print("--------------------------------------------", style="data") return encoded_jwt @@ -97,8 +117,7 @@ def encode_jwt(api_key, creds_dir, env, expiry, kid): @click.option("--encoded_jwt", help="the jwt") @click.option("--env", default="internal-dev", help="the target environment, defaults to 'internal-dev'") def exchange_tokens(encoded_jwt, env): - print(encoded_jwt) - print(env) + console.print(f"Exchanging tokens with [bold]https://{env}.api.service.nhs.uk/oauth2/token[/bold]...", style="info") data = { "grant_type": "client_credentials", "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", @@ -109,7 +128,27 @@ def exchange_tokens(encoded_jwt, env): } res = requests.post(f"https://{env}.api.service.nhs.uk/oauth2/token", data=data, headers=headers) - console.print(res.text, style="data") + status_code = res.status_code + body = json.loads(res.text) + + if status_code != 200: + log_key_value("Error", "Failed to exchange tokens."), "error" + console.print("--------------------------------------------", style="error") + log_key_value("Status Code", status_code, "error") + for key, value in body.items(): + log_key_value(key, value, "error") + console.print("--------------------------------------------", style="error") + exit() + + access_token = body.get("access_token") + expires_timestamp = int(body.get("issued_at"))/1000 + int(body.get("expires_in")) + expires_iso = datetime.fromtimestamp(expires_timestamp).astimezone().isoformat() + + console.print("Exchange successful!", style="success") + console.print("--------------------------------------------", style="data") + log_key_value("Access token", access_token, "data") + log_key_value("Expires", expires_iso, "data") + console.print("--------------------------------------------", style="data") @cli.command() @@ -121,8 +160,10 @@ def exchange_tokens(encoded_jwt, env): @click.option("--kid", default=None, help="the kid of the key pair, defaults to 'psu-'") @click.pass_context def auth(ctx, api_key, creds_dir, env, expiry, kid): - encoded_jwt = ctx.forward(encode_jwt) + console.print("Authenticating...", style="info") + encoded_jwt = ctx.forward(encode_jwt, standalone=False) ctx.invoke(exchange_tokens, encoded_jwt=encoded_jwt, env=env) + console.print("Authentication complete!", style="success") if __name__ == "__main__": From b7cdc0f930794fb3af2e0a6e310f59365d3ce351 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 9 May 2024 11:34:29 +0000 Subject: [PATCH 12/18] [AEA-3864] added cred functions to cli --- psu_auth.py => psu_auth_cli.py | 89 ++++++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 20 deletions(-) rename psu_auth.py => psu_auth_cli.py (58%) diff --git a/psu_auth.py b/psu_auth_cli.py similarity index 58% rename from psu_auth.py rename to psu_auth_cli.py index 27d283f15..a23e67dca 100644 --- a/psu_auth.py +++ b/psu_auth_cli.py @@ -7,7 +7,7 @@ from datetime import datetime from rich.console import Console from rich.theme import Theme -from rich.prompt import Confirm +from rich.prompt import Confirm, Prompt cli_theme = Theme({ @@ -36,19 +36,68 @@ def cli(): pass -@click.option("--creds_dir", default="/home/vscode/.ssh", - help="the directory containing any key pairs & psu-cred.json, defaults to '/home/vscode/.ssh'") -def create_creds_file(): - pass +@cli.command() +@click.option("-d", "--creds_dir", default="/home/vscode/.ssh", + help="The directory containing any key pairs & psu-cred.json, defaults to '/home/vscode/.ssh'") +def update_creds(creds_dir): + try: + with open(f"{creds_dir}/psu_creds.json", "r") as f: + psu_creds = json.load(f) + except FileNotFoundError: + console.print(f"PSU creds file does not exist, will create file at [bold]{creds_dir}/psu_creds.json[/bold]", + style="info") + psu_creds = {} + + add_keys = True + while add_keys: + console.print("Please enter the credential details:", style="info") + env = Prompt.ask("[bold italic purple4]Environment") + key = Prompt.ask("[bold italic purple4]API key") + + if env in psu_creds: + is_correct = Confirm.ask( + f"[deep_sky_blue4]Credentials for {env} already exist, do you want to overwrite them?") + else: + is_correct = Confirm.ask("[deep_sky_blue4]Is this correct?") + + if is_correct: + psu_creds[env] = key + + add_keys = Confirm.ask("[deep_sky_blue4]Do you want to continue adding credentials?") + console.print("--------------------------------------------", style="info") + + with open(f"{creds_dir}/psu_creds.json", "w+") as f: + json.dump(psu_creds, f) + console.print("Credentials updated!", style="success") + + +@cli.command() +@click.option("-d", "--creds_dir", default="/home/vscode/.ssh", + help="The directory containing any key pairs & psu-cred.json, defaults to '/home/vscode/.ssh'") +def list_creds(creds_dir): + console.print(f"Getting PSU credentials file at [bold]{creds_dir}/psu_creds.json[/bold]...", style="info") + try: + with open(f"{creds_dir}/psu_creds.json", "r") as f: + psu_creds = json.load(f) + except FileNotFoundError: + log_key_value("Error", "PSU credentials file not found.", "error") + console.print_exception() + exit() + console.print("--------------------------------------------", style="config") + log_heading("PSU Credentials:", "config") + for key, value in psu_creds.items(): + log_key_value(key, value, "config") + console.print("--------------------------------------------", style="config") + console.print("Complete!", style="success") @cli.command() -@click.option("--api_key", default=None, help="the api key, defaults to the value of in psu-creds.json") -@click.option("--creds_dir", default="/home/vscode/.ssh", - help="the directory containing any key pairs & psu-cred.json, defaults to '/home/vscode/.ssh'") -@click.option("--env", default="internal-dev", help="the target environment, defaults to 'internal-dev'") -@click.option("--expiry", default=300, help="The JWT expiry in seconds, defaults to 300(5mins)") -@click.option("--kid", default=None, help="the kid of the key pair, defaults to 'psu-'") +@click.option("-k", "--api_key", default=None, help="The api key, defaults to the value of in psu-creds.json") +@click.option("-d", "--creds_dir", default="/home/vscode/.ssh", + help="The directory containing any key pairs & psu-cred.json, defaults to '/home/vscode/.ssh'") +@click.option("-e", "--env", default="internal-dev", help="The target environment, defaults to 'internal-dev'") +@click.option("-x", "--expiry", default=300, help="The JWT expiry in seconds, defaults to 300(5mins)") +@click.option("-i", "--kid", default=None, help="The kid of the key pair, defaults to 'psu-'") def encode_jwt(api_key, creds_dir, env, expiry, kid, standalone=True): kid = kid if kid else f"psu-{env}" @@ -77,7 +126,7 @@ def encode_jwt(api_key, creds_dir, env, expiry, kid, standalone=True): log_key_value("Expiry", expiry, "config") console.print("--------------------------------------------", style="config") - is_config_ok = Confirm.ask("Is this correct?") + is_config_ok = Confirm.ask("[purple4]Is this correct?") if not is_config_ok: exit() console.print("--------------------------------------------", style="config") @@ -114,8 +163,8 @@ def encode_jwt(api_key, creds_dir, env, expiry, kid, standalone=True): @cli.command() -@click.option("--encoded_jwt", help="the jwt") -@click.option("--env", default="internal-dev", help="the target environment, defaults to 'internal-dev'") +@click.option("-t", "--encoded_jwt", help="the jwt") +@click.option("-e", "--env", default="internal-dev", help="The target environment, defaults to 'internal-dev'") def exchange_tokens(encoded_jwt, env): console.print(f"Exchanging tokens with [bold]https://{env}.api.service.nhs.uk/oauth2/token[/bold]...", style="info") data = { @@ -152,12 +201,12 @@ def exchange_tokens(encoded_jwt, env): @cli.command() -@click.option("--api_key", default=None, help="the api key, defaults to the value of in psu-creds.json") -@click.option("--creds_dir", default="/home/vscode/.ssh", - help="the directory containing any key pairs & psu-cred.json, defaults to '/home/vscode/.ssh'") -@click.option("--env", default="internal-dev", help="the target environment, defaults to 'internal-dev'") -@click.option("--expiry", default=300, help="The JWT expiry in seconds, defaults to 300(5mins)") -@click.option("--kid", default=None, help="the kid of the key pair, defaults to 'psu-'") +@click.option("-k", "--api_key", default=None, help="The api key, defaults to the value of in psu-creds.json") +@click.option("-d", "--creds_dir", default="/home/vscode/.ssh", + help="The directory containing any key pairs & psu-cred.json, defaults to '/home/vscode/.ssh'") +@click.option("-e", "--env", default="internal-dev", help="The target environment, defaults to 'internal-dev'") +@click.option("-x", "--expiry", default=300, help="The JWT expiry in seconds, defaults to 300(5mins)") +@click.option("-i", "--kid", default=None, help="The KID of the key pair, defaults to 'psu-'") @click.pass_context def auth(ctx, api_key, creds_dir, env, expiry, kid): console.print("Authenticating...", style="info") From 728823fbd40125f6d1fb5bd2f7a1d5884b241004 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 9 May 2024 11:37:08 +0000 Subject: [PATCH 13/18] [AEA-3864] update resource names to be consistent with pfp --- SAMtemplates/apis/main.yaml | 32 ++++++++++++++++---------------- SAMtemplates/functions/main.yaml | 16 ++++++++-------- SAMtemplates/main_template.yaml | 4 ++-- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/SAMtemplates/apis/main.yaml b/SAMtemplates/apis/main.yaml index 315da5867..bc5650341 100644 --- a/SAMtemplates/apis/main.yaml +++ b/SAMtemplates/apis/main.yaml @@ -1,4 +1,4 @@ -AWSTemplateFormatVersion: '2010-09-09' +AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Description: | PSU API's and related resources @@ -7,32 +7,32 @@ Parameters: StackName: Type: String Default: none - + EnableMutualTLS: Type: String - + TruststoreVersion: Type: String - + UpdatePrescriptionStatusStateMachineName: Type: String Default: none - + UpdatePrescriptionStatusStateMachineArn: Type: String Default: none - StatusLambdaFunctionName: + StatusFunctionName: Type: String Default: none - StatusLambdaFunctionArn: + StatusFunctionArn: Type: String Default: none LogRetentionInDays: Type: Number - + EnableSplunk: Type: String @@ -77,7 +77,7 @@ Resources: - - !Ref StackName - !ImportValue eps-route53-resources:EPS-domain RegionalCertificateArn: !Ref GenerateCertificate - EndpointConfiguration: + EndpointConfiguration: Types: - REGIONAL SecurityPolicy: TLS_1_2 @@ -90,7 +90,7 @@ Resources: - !Select - 5 - !Split - - ':' + - ":" - !ImportValue account-resources:TrustStoreBucket - psu-truststore.pem - !Ref AWS::NoValue @@ -204,7 +204,7 @@ Resources: $payload.Payload.body MethodResponses: - - StatusCode: '200' + - StatusCode: "200" StatusLambdaMethodResource: Type: AWS::ApiGateway::Resource @@ -212,7 +212,7 @@ Resources: RestApiId: !Ref RestApiGateway ParentId: !GetAtt RestApiGateway.RootResourceId PathPart: _status - + StatusLambdaMethod: Type: AWS::ApiGateway::Method Properties: @@ -224,7 +224,7 @@ Resources: Type: AWS_PROXY Credentials: !GetAtt RestApiGatewayResources.Outputs.ApiGwRoleArn IntegrationHttpMethod: POST - Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${StatusLambdaFunctionArn}/invocations + Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${StatusFunctionArn}/invocations # ********************************************************************* # if you add a new endpoint, then change the name of this resource @@ -250,7 +250,7 @@ Resources: AccessLogSetting: DestinationArn: !GetAtt RestApiGatewayResources.Outputs.ApiGwAccessLogsArn Format: '{ "requestTime": "$context.requestTime", "apiId": "$context.apiId", "accountId": "$context.accountId", "resourcePath": "$context.resourcePath", "stage": "$context.stage", "requestId": "$context.requestId", "extendedRequestId": "$context.extendedRequestId", "status": "$context.status", "httpMethod": "$context.httpMethod", "protocol": "$context.protocol", "path": "$context.path", "responseLatency": "$context.responseLatency", "responseLength": "$context.responseLength", "domainName": "$context.domainName", "identity": { "sourceIp": "$context.identity.sourceIp", "userAgent": "$context.identity.userAgent", "clientCert":{ "subjectDN": "$context.identity.clientCert.subjectDN", "issuerDN": "$context.identity.clientCert.issuerDN", "serialNumber": "$context.identity.clientCert.serialNumber", "validityNotBefore": "$context.identity.clientCert.validity.notBefore", "validityNotAfter": "$context.identity.clientCert.validity.notAfter" }}, "integration":{ "error": "$context.integration.error", "integrationStatus": "$context.integration.integrationStatus", "latency": "$context.integration.latency", "requestId": "$context.integration.requestId", "status": "$context.integration.status" }}' - + RestApiDomainMapping: Type: AWS::ApiGateway::BasePathMapping Properties: @@ -264,9 +264,9 @@ Resources: Location: api_resources.yaml Parameters: AdditionalPolicies: !Join - - ',' + - "," - - Fn::ImportValue: !Sub ${StackName}:state-machines:${UpdatePrescriptionStatusStateMachineName}:ExecuteStateMachinePolicy - - Fn::ImportValue: !Sub ${StackName}:functions:${StatusLambdaFunctionName}:ExecuteLambdaPolicyArn + - Fn::ImportValue: !Sub ${StackName}:functions:${StatusFunctionName}:ExecuteLambdaPolicyArn ApiName: !Sub ${StackName}-apigw LogRetentionInDays: !Ref LogRetentionInDays EnableSplunk: !Ref EnableSplunk diff --git a/SAMtemplates/functions/main.yaml b/SAMtemplates/functions/main.yaml index 0e65ef77c..cda4bbb80 100644 --- a/SAMtemplates/functions/main.yaml +++ b/SAMtemplates/functions/main.yaml @@ -119,13 +119,13 @@ Resources: SplunkSubscriptionFilterRole: !ImportValue lambda-resources:SplunkSubscriptionFilterRole SplunkDeliveryStreamArn: !ImportValue lambda-resources:SplunkDeliveryStream - StatusLambdaFunction: + StatusFunction: Type: AWS::Serverless::Function Properties: FunctionName: !Sub ${StackName}-statusLambda CodeUri: ../../packages Handler: statusLambda.handler - Role: !GetAtt StatusLambdaFunctionResources.Outputs.LambdaRoleArn + Role: !GetAtt StatusFunctionResources.Outputs.LambdaRoleArn Environment: Variables: VERSION_NUMBER: !Ref VersionNumber @@ -140,7 +140,7 @@ Resources: EntryPoints: - statusLambda/src/statusLambda.ts - StatusLambdaFunctionResources: + StatusFunctionResources: Type: AWS::Serverless::Application Properties: Location: lambda_resources.yaml @@ -177,10 +177,10 @@ Outputs: Export: Name: !Sub ${StackName}:functions:GetStatusUpdates:FunctionArn - StatusLambdaFunctionName: + StatusFunctionName: Description: The function name of the Status lambda - Value: !Ref StatusLambdaFunction - - StatusLambdaFunctionArn: + Value: !Ref StatusFunction + + StatusFunctionArn: Description: The function ARN of the Status lambda - Value: !GetAtt StatusLambdaFunction.Arn + Value: !GetAtt StatusFunction.Arn diff --git a/SAMtemplates/main_template.yaml b/SAMtemplates/main_template.yaml index 177798b25..9375b2d4a 100644 --- a/SAMtemplates/main_template.yaml +++ b/SAMtemplates/main_template.yaml @@ -79,8 +79,8 @@ Resources: TruststoreVersion: !Ref TruststoreVersion UpdatePrescriptionStatusStateMachineName: !GetAtt StateMachines.Outputs.UpdatePrescriptionStatusStateMachineName UpdatePrescriptionStatusStateMachineArn: !GetAtt StateMachines.Outputs.UpdatePrescriptionStatusStateMachineArn - StatusLambdaFunctionName: !GetAtt Functions.Outputs.StatusLambdaFunctionName - StatusLambdaFunctionArn: !GetAtt Functions.Outputs.StatusLambdaFunctionArn + StatusFunctionName: !GetAtt Functions.Outputs.StatusFunctionName + StatusFunctionArn: !GetAtt Functions.Outputs.StatusFunctionArn LogRetentionInDays: !Ref LogRetentionInDays EnableSplunk: !Ref EnableSplunk From 79d53ea98e1d6f72fa986c34233a1f500d669b2f Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 9 May 2024 12:52:53 +0000 Subject: [PATCH 14/18] [AEA-3864] fixing cf issiues --- SAMtemplates/functions/main.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/SAMtemplates/functions/main.yaml b/SAMtemplates/functions/main.yaml index cda4bbb80..c112d4ab1 100644 --- a/SAMtemplates/functions/main.yaml +++ b/SAMtemplates/functions/main.yaml @@ -119,13 +119,13 @@ Resources: SplunkSubscriptionFilterRole: !ImportValue lambda-resources:SplunkSubscriptionFilterRole SplunkDeliveryStreamArn: !ImportValue lambda-resources:SplunkDeliveryStream - StatusFunction: + Status: Type: AWS::Serverless::Function Properties: - FunctionName: !Sub ${StackName}-statusLambda + FunctionName: !Sub ${StackName}-status CodeUri: ../../packages Handler: statusLambda.handler - Role: !GetAtt StatusFunctionResources.Outputs.LambdaRoleArn + Role: !GetAtt StatusResources.Outputs.LambdaRoleArn Environment: Variables: VERSION_NUMBER: !Ref VersionNumber @@ -140,14 +140,14 @@ Resources: EntryPoints: - statusLambda/src/statusLambda.ts - StatusFunctionResources: + StatusResources: Type: AWS::Serverless::Application Properties: Location: lambda_resources.yaml Parameters: StackName: !Ref StackName - LambdaName: !Sub ${StackName}-statusLambda - LambdaArn: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${StackName}-statusLambda + LambdaName: !Sub ${StackName}-status + LambdaArn: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${StackName}-status IncludeAdditionalPolicies: true AdditionalPolicies: !Join - "," @@ -179,8 +179,8 @@ Outputs: StatusFunctionName: Description: The function name of the Status lambda - Value: !Ref StatusFunction + Value: !Ref Status StatusFunctionArn: Description: The function ARN of the Status lambda - Value: !GetAtt StatusFunction.Arn + Value: !GetAtt Status.Arn From 175d75a5e62948535cb1a030446fb1a700d5ea6f Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 9 May 2024 14:23:43 +0000 Subject: [PATCH 15/18] [AEA-3864] misc tweaks --- psu_auth_cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/psu_auth_cli.py b/psu_auth_cli.py index 8ea706ecf..24c48055a 100644 --- a/psu_auth_cli.py +++ b/psu_auth_cli.py @@ -163,7 +163,7 @@ def encode_jwt(api_key, creds_dir, env, expiry, kid, standalone=True): @cli.command() -@click.option("-t", "--encoded_jwt", help="the jwt") +@click.option("-t", "--encoded_jwt", help="The encoded JWT to exchange with the authorisation server", prompt=True) @click.option("-e", "--env", default="internal-dev", help="The target environment, defaults to 'internal-dev'") def exchange_tokens(encoded_jwt, env): console.print(f"Exchanging tokens with [bold]https://{env}.api.service.nhs.uk/oauth2/token[/bold]...", style="info") @@ -181,7 +181,7 @@ def exchange_tokens(encoded_jwt, env): body = json.loads(res.text) if status_code != 200: - log_key_value("Error", "Failed to exchange tokens."), "error" + log_key_value("Error", "Failed to exchange tokens.", "error") console.print("--------------------------------------------", style="error") log_key_value("Status Code", status_code, "error") for key, value in body.items(): From a3d6834c2218c795a8d8048cdc9e8fefd581ee07 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 9 May 2024 14:35:08 +0000 Subject: [PATCH 16/18] trigger build From 1324e63dc0b0bc6bb18cee0cd94adf11049d8aed Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 13 May 2024 10:23:42 +0000 Subject: [PATCH 17/18] [AEA-3864] moved cli into scripts folder --- psu_auth_cli.py => scripts/psu_auth_cli.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename psu_auth_cli.py => scripts/psu_auth_cli.py (100%) diff --git a/psu_auth_cli.py b/scripts/psu_auth_cli.py similarity index 100% rename from psu_auth_cli.py rename to scripts/psu_auth_cli.py From 5b4df993d382656bb65b8732ede97499c9871b35 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 13 May 2024 10:35:30 +0000 Subject: [PATCH 18/18] trigger build