diff --git a/azure/azure-release-pipeline.yml b/azure/azure-release-pipeline.yml index 92779aa..c312f72 100644 --- a/azure/azure-release-pipeline.yml +++ b/azure/azure-release-pipeline.yml @@ -51,10 +51,10 @@ extends: - environment: sandbox proxy_path: sandbox post_deploy: - - template: ./templates/run-integration-tests.yml + - template: ./templates/run-smoke-tests.yml - environment: int depends_on: - internal_qa - internal_qa_sandbox post_deploy: - - template: ./templates/run-integration-tests.yml + - template: ./templates/run-smoke-tests.yml diff --git a/azure/templates/run-smoke-tests.yml b/azure/templates/run-smoke-tests.yml new file mode 100644 index 0000000..c237fba --- /dev/null +++ b/azure/templates/run-smoke-tests.yml @@ -0,0 +1,24 @@ +steps: + - bash: | + make install-python + workingDirectory: $(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME) + displayName: Setup pytests + + - bash: | + export RELEASE_RELEASEID=$(Build.BuildId) + export SOURCE_COMMIT_ID=$(Build.SourceVersion) + export APIGEE_ENVIRONMENT="$(ENVIRONMENT)" + export SERVICE_BASE_PATH="$(SERVICE_BASE_PATH)" + export STATUS_ENDPOINT_API_KEY="$(status-endpoint-api-key)" + export APIGEE_API_TOKEN="$(secret.AccessToken)" + + poetry run pytest -v -m smoketest -o junit_logging=all --junitxml=smoke_tests_report.xml + workingDirectory: $(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/tests + displayName: run smoke tests + + - task: PublishTestResults@2 + displayName: 'Publish smoketest results' + condition: always() + inputs: + testResultsFiles: '$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/tests/smoke_tests_report.xml' + failTaskOnFailedTests: true diff --git a/proxies/live/apiproxy/policies/javascript.CacheRequestHost.xml b/proxies/live/apiproxy/policies/javascript.CacheRequestHost.xml new file mode 100644 index 0000000..0dc41a5 --- /dev/null +++ b/proxies/live/apiproxy/policies/javascript.CacheRequestHost.xml @@ -0,0 +1,6 @@ + + + javascript.CacheRequestHost + + jsc://CacheRequestHost.js + diff --git a/proxies/live/apiproxy/policies/javascript.RewriteHostName.xml b/proxies/live/apiproxy/policies/javascript.RewriteHostName.xml new file mode 100644 index 0000000..6db930d --- /dev/null +++ b/proxies/live/apiproxy/policies/javascript.RewriteHostName.xml @@ -0,0 +1,6 @@ + + + javascript.RewriteHostName + + jsc://RewriteHostName.js + diff --git a/proxies/live/apiproxy/proxies/default.xml b/proxies/live/apiproxy/proxies/default.xml index 1e1aa0e..d1ab2fa 100644 --- a/proxies/live/apiproxy/proxies/default.xml +++ b/proxies/live/apiproxy/proxies/default.xml @@ -41,7 +41,16 @@ - + + + + AssignMessage.SetApimGuids + + + javascript.CacheRequestHost + + + diff --git a/proxies/live/apiproxy/resources/jsc/CacheRequestHost.js b/proxies/live/apiproxy/resources/jsc/CacheRequestHost.js new file mode 100644 index 0000000..cc430d7 --- /dev/null +++ b/proxies/live/apiproxy/resources/jsc/CacheRequestHost.js @@ -0,0 +1,4 @@ +const env_regex = /^([a-zA-Z\-]+)(?=(\.api\.service\.nhs\.uk))/gm; +var hostname_env = request.headers.host; +hostname_env = hostname_env.match(env_regex, request.headers.host)[0]; +context.setVariable("request_hostname_env", hostname_env); diff --git a/proxies/live/apiproxy/resources/jsc/RewriteHostName.js b/proxies/live/apiproxy/resources/jsc/RewriteHostName.js new file mode 100644 index 0000000..edb0459 --- /dev/null +++ b/proxies/live/apiproxy/resources/jsc/RewriteHostName.js @@ -0,0 +1,19 @@ +var response = context.getVariable("response.content"); +var json = JSON.parse(response); + +if (json.place) { + // Loop over each item in the search result array, re-writing the hostname to that of the initial request + json.place.forEach(value => { + var request_hostname = context.getVariable("request_hostname_env"); + // Annoyingly, Apigee's version of JS doesn't support regex look-behinds, + // so we grab the env string including https:// prefix + var hostname_regex = /(^https:\/\/([a-zA-Z\-]+\.)+)nhs\.uk/gm; + var rewritten_url = value.url.replace(hostname_regex, "https://" + request_hostname + ".api.service.nhs.uk"); + value.url = rewritten_url; + value.url = value.url.replace("api-version=1", "api-version=2"); + value.url = value.url.replace("service-search", "service-search-api"); + }); + + // Update the response payload with the corrected urls + context.setVariable("message.content", JSON.stringify(json)); +} diff --git a/proxies/live/apiproxy/targets/target.xml b/proxies/live/apiproxy/targets/target.xml index a6b3463..7522541 100644 --- a/proxies/live/apiproxy/targets/target.xml +++ b/proxies/live/apiproxy/targets/target.xml @@ -15,6 +15,14 @@ + + + + + javascript.RewriteHostName + + + diff --git a/proxies/sandbox/apiproxy/policies/javascript.CacheRequestHost.xml b/proxies/sandbox/apiproxy/policies/javascript.CacheRequestHost.xml new file mode 100644 index 0000000..0dc41a5 --- /dev/null +++ b/proxies/sandbox/apiproxy/policies/javascript.CacheRequestHost.xml @@ -0,0 +1,6 @@ + + + javascript.CacheRequestHost + + jsc://CacheRequestHost.js + diff --git a/proxies/sandbox/apiproxy/policies/javascript.RewriteHostName.xml b/proxies/sandbox/apiproxy/policies/javascript.RewriteHostName.xml new file mode 100644 index 0000000..6db930d --- /dev/null +++ b/proxies/sandbox/apiproxy/policies/javascript.RewriteHostName.xml @@ -0,0 +1,6 @@ + + + javascript.RewriteHostName + + jsc://RewriteHostName.js + diff --git a/proxies/sandbox/apiproxy/proxies/default.xml b/proxies/sandbox/apiproxy/proxies/default.xml index 0924853..d9dad36 100644 --- a/proxies/sandbox/apiproxy/proxies/default.xml +++ b/proxies/sandbox/apiproxy/proxies/default.xml @@ -39,7 +39,16 @@ - + + + + AssignMessage.SetApimGuids + + + javascript.CacheRequestHost + + + diff --git a/proxies/sandbox/apiproxy/resources/jsc/CacheRequestHost.js b/proxies/sandbox/apiproxy/resources/jsc/CacheRequestHost.js new file mode 100644 index 0000000..cc430d7 --- /dev/null +++ b/proxies/sandbox/apiproxy/resources/jsc/CacheRequestHost.js @@ -0,0 +1,4 @@ +const env_regex = /^([a-zA-Z\-]+)(?=(\.api\.service\.nhs\.uk))/gm; +var hostname_env = request.headers.host; +hostname_env = hostname_env.match(env_regex, request.headers.host)[0]; +context.setVariable("request_hostname_env", hostname_env); diff --git a/proxies/sandbox/apiproxy/resources/jsc/RewriteHostName.js b/proxies/sandbox/apiproxy/resources/jsc/RewriteHostName.js new file mode 100644 index 0000000..edb0459 --- /dev/null +++ b/proxies/sandbox/apiproxy/resources/jsc/RewriteHostName.js @@ -0,0 +1,19 @@ +var response = context.getVariable("response.content"); +var json = JSON.parse(response); + +if (json.place) { + // Loop over each item in the search result array, re-writing the hostname to that of the initial request + json.place.forEach(value => { + var request_hostname = context.getVariable("request_hostname_env"); + // Annoyingly, Apigee's version of JS doesn't support regex look-behinds, + // so we grab the env string including https:// prefix + var hostname_regex = /(^https:\/\/([a-zA-Z\-]+\.)+)nhs\.uk/gm; + var rewritten_url = value.url.replace(hostname_regex, "https://" + request_hostname + ".api.service.nhs.uk"); + value.url = rewritten_url; + value.url = value.url.replace("api-version=1", "api-version=2"); + value.url = value.url.replace("service-search", "service-search-api"); + }); + + // Update the response payload with the corrected urls + context.setVariable("message.content", JSON.stringify(json)); +} diff --git a/proxies/sandbox/apiproxy/targets/sandbox.xml b/proxies/sandbox/apiproxy/targets/sandbox.xml index 22be523..74caad5 100644 --- a/proxies/sandbox/apiproxy/targets/sandbox.xml +++ b/proxies/sandbox/apiproxy/targets/sandbox.xml @@ -14,6 +14,14 @@ + + + + + javascript.RewriteHostName + + + AssignMessage.AddCors diff --git a/specification/examples/search-place_v2.json b/specification/examples/search-place_v2.json index 3d61153..aade346 100644 --- a/specification/examples/search-place_v2.json +++ b/specification/examples/search-place_v2.json @@ -4,13 +4,13 @@ "Latitude": 53.478941671902611, "Longitude": -2.245277998298477, "text": "Manchester, North West", - "url": "https://api.nhs.uk/service-search/search-postcode-or-place?api-version=1&search=manchester&latitude=53.4789416719026&longitude=-2.24527799829848" + "url": "https://int.api.service.nhs.uk/service-search/search-postcode-or-place?api-version=1&search=manchester&latitude=53.4789416719026&longitude=-2.24527799829848" }, { "Latitude": 53.514265448236706, "Longitude": -2.4199003923191209, "text": "New Manchester, North West", - "url": "https://api.nhs.uk/service-search/search-postcode-or-place?api-version=1&search=manchester&latitude=53.5142654482367&longitude=-2.41990039231912" + "url": "https://int.api.service.nhs.uk/service-search/search-postcode-or-place?api-version=1&search=manchester&latitude=53.5142654482367&longitude=-2.41990039231912" } ] -} \ No newline at end of file +} diff --git a/specification/service-search-api.yaml b/specification/service-search-api.yaml index b60665c..8d0e5dd 100644 --- a/specification/service-search-api.yaml +++ b/specification/service-search-api.yaml @@ -49,7 +49,7 @@ info: * unattended (end user not present) To use this access mode, use the following security pattern: - * [application-restricted RESTful API - signed JWT authentication](https://digital.nhs.uk/developer/guides-and-documentation/security-and-authorisation/application-restricted-restful-apis-signed-jwt-authentication) + * [application-restricted RESTful API - API key authentication](https://digital.nhs.uk/developer/guides-and-documentation/security-and-authorisation/application-restricted-restful-apis-api-key-authentication) ## Environments and testing diff --git a/tests/test_search_postcode.py b/tests/test_search_postcode.py index a252c36..52c4886 100644 --- a/tests/test_search_postcode.py +++ b/tests/test_search_postcode.py @@ -151,7 +151,6 @@ def test_invalid_api_version(self, get_api_key): assert_that(response.status_code).is_equal_to(expected_status_code) assert_that(response.json()).is_equal_to(expected_body) - @pytest.mark.skip @pytest.mark.integration def test_response_payload_urls_are_corrected(self, get_api_key): """ @@ -172,11 +171,11 @@ def test_response_payload_urls_are_corrected(self, get_api_key): json={}, ) - results = response.json()["place"] + results = response.json()['place'] for item in results: - url_response = requests.get( - url=item["url"], - params={"apikey": api_key}, + url_response = requests.post( + url=item['url'], headers=make_headers(api_key), + json={}, ) assert_that(url_response.status_code).is_equal_to(expected_status_code)